]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge branch 'for-linus-4.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 12 Jan 2016 21:27:18 +0000 (13:27 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 12 Jan 2016 21:27:18 +0000 (13:27 -0800)
Pull UML updates from Richard Weinberger:
 "This contains beside of random fixes/cleanups two bigger changes:

   - seccomp support by Mickaël Salaün

   - IRQ rework by Anton Ivanov"

* 'for-linus-4.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml:
  um: Use race-free temporary file creation
  um: Do not set unsecure permission for temporary file
  um: Fix build error and kconfig for i386
  um: Add seccomp support
  um: Add full asm/syscall.h support
  selftests/seccomp: Remove the need for HAVE_ARCH_TRACEHOOK
  um: Fix ptrace GETREGS/SETREGS bugs
  um: link with -lpthread
  um: Update UBD to use pread/pwrite family of functions
  um: Do not change hard IRQ flags in soft IRQ processing
  um: Prevent IRQ handler reentrancy
  uml: flush stdout before forking
  uml: fix hostfs mknod()

1900 files changed:
CREDITS
Documentation/DocBook/device-drivers.tmpl
Documentation/DocBook/media/Makefile
Documentation/DocBook/media/dvb/dvbproperty.xml
Documentation/DocBook/media/dvb/examples.xml
Documentation/DocBook/media/dvb/intro.xml
Documentation/DocBook/media/v4l/capture.c.xml
Documentation/DocBook/media/v4l/compat.xml
Documentation/DocBook/media/v4l/io.xml
Documentation/DocBook/media/v4l/v4l2.xml
Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml
Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml
Documentation/DocBook/media/v4l/vidioc-enumstd.xml
Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
Documentation/DocBook/media_api.tmpl
Documentation/RCU/Design/Requirements/2013-08-is-it-dead.png [new file with mode: 0644]
Documentation/RCU/Design/Requirements/GPpartitionReaders1.svg [new file with mode: 0644]
Documentation/RCU/Design/Requirements/RCUApplicability.svg [new file with mode: 0644]
Documentation/RCU/Design/Requirements/ReadersPartitionGP1.svg [new file with mode: 0644]
Documentation/RCU/Design/Requirements/Requirements.html [new file with mode: 0644]
Documentation/RCU/Design/Requirements/Requirements.htmlx [new file with mode: 0644]
Documentation/RCU/Design/htmlqqz.sh [new file with mode: 0755]
Documentation/arm64/silicon-errata.txt [new file with mode: 0644]
Documentation/device-mapper/verity.txt
Documentation/devicetree/bindings/arm/l2c2x0.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/l2cc.txt [deleted file]
Documentation/devicetree/bindings/arm/pmu.txt
Documentation/devicetree/bindings/ata/brcm,sata-brcmstb.txt
Documentation/devicetree/bindings/ata/sata_rcar.txt
Documentation/devicetree/bindings/interrupt-controller/allwinner,sun67i-sc-nmi.txt [deleted file]
Documentation/devicetree/bindings/interrupt-controller/allwinner,sunxi-nmi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/technologic,ts4800.txt [new file with mode: 0644]
Documentation/devicetree/bindings/media/stih407-c8sectpfe.txt
Documentation/devicetree/bindings/mmc/renesas,mmcif.txt
Documentation/devicetree/bindings/net/cpsw.txt
Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/brcm,cygnus-gpio.txt [deleted file]
Documentation/devicetree/bindings/pinctrl/brcm,iproc-gpio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/brcm,nsp-gpio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/lantiq,pinctrl-xway.txt
Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt
Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt
Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt
Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
Documentation/dvb/README.dvb-usb
Documentation/dvb/faq.txt
Documentation/dvb/get_dvb_firmware
Documentation/dvb/readme.txt
Documentation/edac.txt
Documentation/features/time/irq-time-acct/arch-support.txt
Documentation/filesystems/Locking
Documentation/filesystems/porting
Documentation/filesystems/vfs.txt
Documentation/hwmon/htu21 [deleted file]
Documentation/hwmon/ltc3815 [new file with mode: 0644]
Documentation/kernel-parameters.txt
Documentation/leds/leds-class.txt
Documentation/memory-barriers.txt
Documentation/sysctl/kernel.txt
Documentation/trace/events-msr.txt [new file with mode: 0644]
Documentation/trace/postprocess/decode_msr.py [new file with mode: 0644]
Documentation/video4linux/API.html
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/fimc.txt
Documentation/video4linux/omap4_camera.txt
Documentation/video4linux/si4713.txt
Documentation/video4linux/v4l2-pci-skeleton.c
Documentation/virtual/kvm/api.txt
Documentation/virtual/kvm/devices/vm.txt
Documentation/virtual/kvm/mmu.txt
MAINTAINERS
Makefile
arch/arm/Kconfig
arch/arm/boot/compressed/Makefile
arch/arm/boot/compressed/efi-header.S [new file with mode: 0644]
arch/arm/boot/compressed/head.S
arch/arm/boot/compressed/vmlinux.lds.S
arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
arch/arm/boot/dts/stihxxx-b2120.dtsi
arch/arm/boot/dts/versatile-ab.dts
arch/arm/boot/dts/versatile-pb.dts
arch/arm/boot/dts/wm8650.dtsi
arch/arm/configs/multi_v7_defconfig
arch/arm/configs/sunxi_defconfig
arch/arm/include/asm/Kbuild
arch/arm/include/asm/bug.h
arch/arm/include/asm/cpuidle.h
arch/arm/include/asm/efi.h [new file with mode: 0644]
arch/arm/include/asm/fixmap.h
arch/arm/include/asm/hardirq.h
arch/arm/include/asm/kvm_arm.h
arch/arm/include/asm/kvm_host.h
arch/arm/include/asm/kvm_mmu.h
arch/arm/include/asm/mach/map.h
arch/arm/include/asm/mmu_context.h
arch/arm/include/asm/paravirt.h [new file with mode: 0644]
arch/arm/include/asm/psci.h
arch/arm/include/asm/setup.h
arch/arm/include/asm/xen/hypercall.h
arch/arm/include/asm/xen/interface.h
arch/arm/kernel/Makefile
arch/arm/kernel/armksyms.c
arch/arm/kernel/atags.h
arch/arm/kernel/cpuidle.c
arch/arm/kernel/efi.c [new file with mode: 0644]
arch/arm/kernel/entry-v7m.S
arch/arm/kernel/paravirt.c [new file with mode: 0644]
arch/arm/kernel/perf_event_v7.c
arch/arm/kernel/pj4-cp0.c
arch/arm/kernel/psci-call.S [deleted file]
arch/arm/kernel/setup.c
arch/arm/kernel/smccc-call.S [new file with mode: 0644]
arch/arm/kernel/smp.c
arch/arm/kernel/sys_oabi-compat.c
arch/arm/kernel/vdso.c
arch/arm/kvm/arm.c
arch/arm/kvm/emulate.c
arch/arm/kvm/guest.c
arch/arm/kvm/handle_exit.c
arch/arm/kvm/mmio.c
arch/arm/kvm/mmu.c
arch/arm/lib/lib1funcs.S
arch/arm/mach-davinci/board-da850-evm.c
arch/arm/mach-davinci/board-dm355-evm.c
arch/arm/mach-davinci/board-dm365-evm.c
arch/arm/mach-davinci/board-dm644x-evm.c
arch/arm/mach-davinci/board-dm646x-evm.c
arch/arm/mach-exynos/Kconfig
arch/arm/mach-imx/devices/devices-common.h
arch/arm/mach-omap1/include/mach/camera.h
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/gpmc-onenand.c
arch/arm/mach-pxa/devices.c
arch/arm/mach-pxa/em-x270.c
arch/arm/mach-pxa/ezx.c
arch/arm/mach-pxa/mioa701.c
arch/arm/mach-pxa/palmtreo.c
arch/arm/mach-pxa/palmz72.c
arch/arm/mach-pxa/pcm990-baseboard.c
arch/arm/mach-sti/Kconfig
arch/arm/mach-ux500/Kconfig
arch/arm/mm/cache-l2x0.c
arch/arm/mm/cache-uniphier.c
arch/arm/mm/init.c
arch/arm/mm/ioremap.c
arch/arm/mm/mmu.c
arch/arm/mm/proc-v7.S
arch/arm/mm/proc-v7m.S
arch/arm/net/bpf_jit_32.c
arch/arm/plat-samsung/devs.c
arch/arm/xen/enlighten.c
arch/arm/xen/hypercall.S
arch/arm64/Kconfig
arch/arm64/include/asm/alternative.h
arch/arm64/include/asm/assembler.h
arch/arm64/include/asm/cacheflush.h
arch/arm64/include/asm/cmpxchg.h
arch/arm64/include/asm/efi.h
arch/arm64/include/asm/ftrace.h
arch/arm64/include/asm/hugetlb.h
arch/arm64/include/asm/irq.h
arch/arm64/include/asm/kvm_arm.h
arch/arm64/include/asm/kvm_asm.h
arch/arm64/include/asm/kvm_emulate.h
arch/arm64/include/asm/kvm_host.h
arch/arm64/include/asm/kvm_mmio.h
arch/arm64/include/asm/kvm_mmu.h
arch/arm64/include/asm/paravirt.h [new file with mode: 0644]
arch/arm64/include/asm/pgtable-hwdef.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/shmparam.h
arch/arm64/include/asm/spinlock.h
arch/arm64/include/asm/stacktrace.h
arch/arm64/include/asm/sysreg.h
arch/arm64/include/asm/thread_info.h
arch/arm64/kernel/Makefile
arch/arm64/kernel/alternative.c
arch/arm64/kernel/arm64ksyms.c
arch/arm64/kernel/armv8_deprecated.c
arch/arm64/kernel/asm-offsets.c
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/efi.c
arch/arm64/kernel/entry.S
arch/arm64/kernel/fpsimd.c
arch/arm64/kernel/ftrace.c
arch/arm64/kernel/head.S
arch/arm64/kernel/irq.c
arch/arm64/kernel/module.c
arch/arm64/kernel/paravirt.c [new file with mode: 0644]
arch/arm64/kernel/perf_callchain.c
arch/arm64/kernel/perf_event.c
arch/arm64/kernel/process.c
arch/arm64/kernel/psci-call.S [deleted file]
arch/arm64/kernel/ptrace.c
arch/arm64/kernel/return_address.c
arch/arm64/kernel/sleep.S
arch/arm64/kernel/smccc-call.S [new file with mode: 0644]
arch/arm64/kernel/stacktrace.c
arch/arm64/kernel/time.c
arch/arm64/kernel/traps.c
arch/arm64/kernel/vmlinux.lds.S
arch/arm64/kvm/Makefile
arch/arm64/kvm/guest.c
arch/arm64/kvm/handle_exit.c
arch/arm64/kvm/hyp-init.S
arch/arm64/kvm/hyp.S
arch/arm64/kvm/hyp/Makefile [new file with mode: 0644]
arch/arm64/kvm/hyp/debug-sr.c [new file with mode: 0644]
arch/arm64/kvm/hyp/entry.S [new file with mode: 0644]
arch/arm64/kvm/hyp/fpsimd.S [new file with mode: 0644]
arch/arm64/kvm/hyp/hyp-entry.S [new file with mode: 0644]
arch/arm64/kvm/hyp/hyp.h [new file with mode: 0644]
arch/arm64/kvm/hyp/switch.c [new file with mode: 0644]
arch/arm64/kvm/hyp/sysreg-sr.c [new file with mode: 0644]
arch/arm64/kvm/hyp/timer-sr.c [new file with mode: 0644]
arch/arm64/kvm/hyp/tlb.c [new file with mode: 0644]
arch/arm64/kvm/hyp/vgic-v2-sr.c [new file with mode: 0644]
arch/arm64/kvm/hyp/vgic-v3-sr.c [new file with mode: 0644]
arch/arm64/kvm/sys_regs.c
arch/arm64/kvm/vgic-v2-switch.S [deleted file]
arch/arm64/kvm/vgic-v3-switch.S [deleted file]
arch/arm64/mm/cache.S
arch/arm64/mm/copypage.c
arch/arm64/mm/dma-mapping.c
arch/arm64/mm/flush.c
arch/arm64/mm/hugetlbpage.c
arch/arm64/mm/init.c
arch/arm64/mm/mmu.c
arch/arm64/mm/pgd.c
arch/arm64/mm/proc-macros.S
arch/arm64/mm/proc.S
arch/arm64/xen/hypercall.S
arch/blackfin/include/asm/cmpxchg.h
arch/blackfin/mach-bf561/boards/ezkit.c
arch/blackfin/mach-bf609/boards/ezkit.c
arch/c6x/include/asm/Kbuild
arch/c6x/include/asm/clkdev.h [deleted file]
arch/c6x/include/asm/cmpxchg.h
arch/frv/include/asm/cmpxchg.h
arch/h8300/Kconfig
arch/h8300/include/asm/io.h
arch/h8300/kernel/setup.c
arch/ia64/include/asm/barrier.h
arch/ia64/include/asm/percpu.h
arch/m32r/include/asm/Kbuild
arch/m32r/include/asm/io.h
arch/m68k/atari/config.c
arch/m68k/coldfire/gpio.c
arch/m68k/configs/amiga_defconfig
arch/m68k/configs/apollo_defconfig
arch/m68k/configs/atari_defconfig
arch/m68k/configs/bvme6000_defconfig
arch/m68k/configs/hp300_defconfig
arch/m68k/configs/mac_defconfig
arch/m68k/configs/multi_defconfig
arch/m68k/configs/mvme147_defconfig
arch/m68k/configs/mvme16x_defconfig
arch/m68k/configs/q40_defconfig
arch/m68k/configs/sun3_defconfig
arch/m68k/configs/sun3x_defconfig
arch/m68k/include/asm/mac_psc.h
arch/m68k/include/asm/page.h
arch/m68k/mac/macints.c
arch/m68k/mac/psc.c
arch/m68k/sun3/config.c
arch/mips/boot/dts/brcm/bcm6328.dtsi
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/net/bpf_jit.c
arch/mips/vdso/Makefile
arch/powerpc/include/asm/barrier.h
arch/powerpc/include/asm/kvm_host.h
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_pr.c
arch/powerpc/net/bpf_jit_comp.c
arch/powerpc/sysdev/fsl_pci.c
arch/powerpc/sysdev/fsl_pci.h
arch/s390/include/asm/barrier.h
arch/s390/include/asm/elf.h
arch/s390/include/asm/kvm_host.h
arch/s390/include/asm/sclp.h
arch/s390/include/uapi/asm/kvm.h
arch/s390/kernel/processor.c
arch/s390/kernel/setup.c
arch/s390/kvm/diag.c
arch/s390/kvm/gaccess.c
arch/s390/kvm/intercept.c
arch/s390/kvm/interrupt.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h
arch/s390/kvm/trace-s390.h
arch/s390/mm/pgtable.c
arch/sh/boards/mach-ap325rxa/setup.c
arch/sh/boards/mach-ecovec24/setup.c
arch/sh/boards/mach-kfr2r09/setup.c
arch/sh/boards/mach-migor/setup.c
arch/sh/boards/mach-se/7724/setup.c
arch/sparc/include/uapi/asm/unistd.h
arch/sparc/kernel/systbls_32.S
arch/sparc/kernel/systbls_64.S
arch/sparc/net/bpf_jit_comp.c
arch/tile/Kconfig
arch/tile/include/asm/cmpxchg.h
arch/tile/include/asm/page.h
arch/x86/Kconfig
arch/x86/Kconfig.debug
arch/x86/crypto/chacha20_glue.c
arch/x86/crypto/crc32c-intel_glue.c
arch/x86/entry/calling.h
arch/x86/entry/common.c
arch/x86/entry/entry_32.S
arch/x86/entry/entry_64.S
arch/x86/entry/entry_64_compat.S
arch/x86/entry/vdso/vclock_gettime.c
arch/x86/entry/vdso/vdso-layout.lds.S
arch/x86/entry/vdso/vdso2c.c
arch/x86/entry/vdso/vdso32/system_call.S
arch/x86/entry/vdso/vma.c
arch/x86/include/asm/apic.h
arch/x86/include/asm/atomic.h
arch/x86/include/asm/atomic64_32.h
arch/x86/include/asm/calgary.h
arch/x86/include/asm/cmpxchg_32.h
arch/x86/include/asm/cmpxchg_64.h
arch/x86/include/asm/cpu.h
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/fixmap.h
arch/x86/include/asm/fpu/internal.h
arch/x86/include/asm/intel_pt.h [new file with mode: 0644]
arch/x86/include/asm/ipi.h
arch/x86/include/asm/jump_label.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/microcode.h
arch/x86/include/asm/msi.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/msr-trace.h [new file with mode: 0644]
arch/x86/include/asm/msr.h
arch/x86/include/asm/page_types.h
arch/x86/include/asm/paravirt.h
arch/x86/include/asm/paravirt_types.h
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/pvclock.h
arch/x86/include/asm/qspinlock_paravirt.h
arch/x86/include/asm/reboot.h
arch/x86/include/asm/smp.h
arch/x86/include/asm/suspend_32.h
arch/x86/include/asm/suspend_64.h
arch/x86/include/asm/uaccess.h
arch/x86/include/asm/vdso.h
arch/x86/include/asm/x86_init.h
arch/x86/include/asm/xen/hypercall.h
arch/x86/include/asm/xor_32.h
arch/x86/include/uapi/asm/hyperv.h
arch/x86/include/uapi/asm/mce.h
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/apic_flat_64.c
arch/x86/kernel/apic/apic_noop.c
arch/x86/kernel/apic/apic_numachip.c
arch/x86/kernel/apic/bigsmp_32.c
arch/x86/kernel/apic/ipi.c
arch/x86/kernel/apic/msi.c
arch/x86/kernel/apic/probe_32.c
arch/x86/kernel/apic/vector.c
arch/x86/kernel/apic/x2apic_cluster.c
arch/x86/kernel/apic/x2apic_phys.c
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/asm-offsets.c
arch/x86/kernel/asm-offsets_64.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/centaur.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/microcode/core.c
arch/x86/kernel/cpu/microcode/intel.c
arch/x86/kernel/cpu/mtrr/cleanup.c
arch/x86/kernel/cpu/mtrr/generic.c
arch/x86/kernel/cpu/mtrr/main.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event.h
arch/x86/kernel/cpu/perf_event_amd.c
arch/x86/kernel/cpu/perf_event_amd_uncore.c
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_ds.c
arch/x86/kernel/cpu/perf_event_intel_lbr.c
arch/x86/kernel/cpu/perf_event_intel_pt.c
arch/x86/kernel/cpu/perf_event_intel_rapl.c
arch/x86/kernel/cpu/perf_event_intel_uncore.c
arch/x86/kernel/cpu/perf_event_intel_uncore.h
arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c
arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c
arch/x86/kernel/cpu/rdrand.c
arch/x86/kernel/cpu/scattered.c
arch/x86/kernel/cpu/transmeta.c
arch/x86/kernel/crash.c
arch/x86/kernel/fpu/init.c
arch/x86/kernel/fpu/xstate.c
arch/x86/kernel/hw_breakpoint.c
arch/x86/kernel/kvmclock.c
arch/x86/kernel/nmi.c
arch/x86/kernel/paravirt.c
arch/x86/kernel/paravirt_patch_32.c
arch/x86/kernel/paravirt_patch_64.c
arch/x86/kernel/pci-calgary_64.c
arch/x86/kernel/pci-swiotlb.c
arch/x86/kernel/process_64.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/pvclock.c
arch/x86/kernel/reboot.c
arch/x86/kernel/rtc.c
arch/x86/kernel/setup.c
arch/x86/kernel/smp.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/tsc.c
arch/x86/kernel/vm86_32.c
arch/x86/kernel/x86_init.c
arch/x86/kvm/cpuid.h
arch/x86/kvm/hyperv.c
arch/x86/kvm/hyperv.h
arch/x86/kvm/i8254.c
arch/x86/kvm/ioapic.c
arch/x86/kvm/ioapic.h
arch/x86/kvm/irq.c
arch/x86/kvm/irq_comm.c
arch/x86/kvm/lapic.c
arch/x86/kvm/lapic.h
arch/x86/kvm/mmu.c
arch/x86/kvm/mmu_audit.c
arch/x86/kvm/paging_tmpl.h
arch/x86/kvm/svm.c
arch/x86/kvm/trace.h
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/lguest/boot.c
arch/x86/lib/Makefile
arch/x86/lib/cpu.c [new file with mode: 0644]
arch/x86/lib/msr.c
arch/x86/mm/Makefile
arch/x86/mm/debug_pagetables.c [new file with mode: 0644]
arch/x86/mm/dump_pagetables.c
arch/x86/mm/ioremap.c
arch/x86/mm/pageattr.c
arch/x86/mm/pat.c
arch/x86/mm/pat_rbtree.c
arch/x86/mm/pgtable.c
arch/x86/mm/setup_nx.c
arch/x86/mm/srat.c
arch/x86/platform/uv/uv_nmi.c
arch/x86/power/cpu.c
arch/x86/xen/apic.c
arch/x86/xen/enlighten.c
arch/x86/xen/mmu.c
arch/x86/xen/suspend.c
arch/x86/xen/time.c
arch/x86/xen/xen-asm_32.S
arch/x86/xen/xen-asm_64.S
arch/x86/xen/xen-ops.h
block/blk-core.c
crypto/algif_skcipher.c
crypto/async_tx/async_memcpy.c
crypto/async_tx/async_pq.c
crypto/async_tx/async_raid6_recov.c
crypto/async_tx/async_xor.c
drivers/acpi/device_sysfs.c
drivers/ata/Kconfig
drivers/ata/ahci.c
drivers/ata/ahci.h
drivers/ata/ahci_brcmstb.c
drivers/ata/ahci_qoriq.c
drivers/ata/libahci.c
drivers/ata/libata-core.c
drivers/ata/sata_rcar.c
drivers/ata/sata_sx4.c
drivers/base/component.c
drivers/base/platform-msi.c
drivers/base/platform.c
drivers/base/regmap/regcache-flat.c
drivers/base/regmap/regcache-lzo.c
drivers/base/regmap/regcache-rbtree.c
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap-debugfs.c
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap-mmio.c
drivers/base/regmap/regmap.c
drivers/block/null_blk.c
drivers/char/hw_random/via-rng.c
drivers/clocksource/Kconfig
drivers/clocksource/Makefile
drivers/clocksource/acpi_pm.c
drivers/clocksource/arm_global_timer.c
drivers/clocksource/dw_apb_timer.c
drivers/clocksource/dw_apb_timer_of.c
drivers/clocksource/h8300_timer16.c
drivers/clocksource/h8300_timer8.c
drivers/clocksource/h8300_tpu.c
drivers/clocksource/mtk_timer.c
drivers/clocksource/rockchip_timer.c
drivers/clocksource/tango_xtal.c
drivers/clocksource/tegra20_timer.c
drivers/clocksource/time-lpc32xx.c
drivers/clocksource/time-pistachio.c
drivers/clocksource/timer-sun5i.c
drivers/clocksource/vt8500_timer.c
drivers/connector/connector.c
drivers/crypto/padlock-aes.c
drivers/crypto/padlock-sha.c
drivers/dma/mic_x100_dma.c
drivers/dma/xgene-dma.c
drivers/edac/Makefile
drivers/edac/edac_device.c
drivers/edac/edac_device_sysfs.c
drivers/edac/edac_mc.c
drivers/edac/edac_mc_sysfs.c
drivers/edac/edac_module.c
drivers/edac/edac_module.h
drivers/edac/edac_pci.c
drivers/edac/edac_pci_sysfs.c
drivers/edac/edac_stub.c
drivers/edac/i5100_edac.c
drivers/edac/mpc85xx_edac.c
drivers/edac/mv64x60_edac.c
drivers/edac/sb_edac.c
drivers/edac/wq.c [new file with mode: 0644]
drivers/firmware/Kconfig
drivers/firmware/dmi_scan.c
drivers/firmware/efi/Makefile
drivers/firmware/efi/arm-init.c [new file with mode: 0644]
drivers/firmware/efi/arm-runtime.c [new file with mode: 0644]
drivers/firmware/efi/efi.c
drivers/firmware/efi/libstub/Makefile
drivers/firmware/efi/libstub/arm-stub.c
drivers/firmware/efi/libstub/arm32-stub.c [new file with mode: 0644]
drivers/firmware/psci.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c
drivers/gpu/ipu-v3/ipu-cpmem.c
drivers/hv/hyperv_vmbus.h
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/fam15h_power.c
drivers/hwmon/htu21.c [deleted file]
drivers/hwmon/ibmaem.c
drivers/hwmon/nct6683.c
drivers/hwmon/nct6775.c
drivers/hwmon/pmbus/Kconfig
drivers/hwmon/pmbus/Makefile
drivers/hwmon/pmbus/ltc3815.c [new file with mode: 0644]
drivers/infiniband/core/cma.c
drivers/infiniband/hw/mlx4/srq.c
drivers/infiniband/hw/ocrdma/ocrdma.h
drivers/infiniband/hw/ocrdma/ocrdma_hw.c
drivers/infiniband/hw/ocrdma/ocrdma_hw.h
drivers/infiniband/hw/ocrdma/ocrdma_main.c
drivers/infiniband/hw/ocrdma/ocrdma_sli.h
drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
drivers/input/touchscreen/sur40.c
drivers/iommu/dma-iommu.c
drivers/iommu/intel_irq_remapping.c
drivers/iommu/ipmmu-vmsa.c
drivers/irqchip/Kconfig
drivers/irqchip/Makefile
drivers/irqchip/irq-bcm2836.c
drivers/irqchip/irq-gic-realview.c [new file with mode: 0644]
drivers/irqchip/irq-gic-v2m.c
drivers/irqchip/irq-gic.c
drivers/irqchip/irq-mbigen.c [new file with mode: 0644]
drivers/irqchip/irq-omap-intc.c
drivers/irqchip/irq-renesas-h8300h.c
drivers/irqchip/irq-renesas-intc-irqpin.c
drivers/irqchip/irq-sunxi-nmi.c
drivers/irqchip/irq-ts4800.c [new file with mode: 0644]
drivers/irqchip/irq-zevio.c
drivers/leds/Kconfig
drivers/leds/led-class-flash.c
drivers/leds/led-class.c
drivers/leds/led-core.c
drivers/leds/led-triggers.c
drivers/leds/leds-88pm860x.c
drivers/leds/leds-aat1290.c
drivers/leds/leds-adp5520.c
drivers/leds/leds-bcm6328.c
drivers/leds/leds-bcm6358.c
drivers/leds/leds-bd2802.c
drivers/leds/leds-blinkm.c
drivers/leds/leds-da903x.c
drivers/leds/leds-da9052.c
drivers/leds/leds-dac124s085.c
drivers/leds/leds-gpio.c
drivers/leds/leds-ipaq-micro.c
drivers/leds/leds-ktd2692.c
drivers/leds/leds-lm3533.c
drivers/leds/leds-lm355x.c
drivers/leds/leds-lm3642.c
drivers/leds/leds-lp3944.c
drivers/leds/leds-lp5521.c
drivers/leds/leds-lp5523.c
drivers/leds/leds-lp5562.c
drivers/leds/leds-lp55xx-common.c
drivers/leds/leds-lp55xx-common.h
drivers/leds/leds-lp8501.c
drivers/leds/leds-lp8788.c
drivers/leds/leds-lp8860.c
drivers/leds/leds-lt3593.c
drivers/leds/leds-max77693.c
drivers/leds/leds-max8997.c
drivers/leds/leds-mc13783.c
drivers/leds/leds-ns2.c
drivers/leds/leds-pca9532.c
drivers/leds/leds-pca955x.c
drivers/leds/leds-pca963x.c
drivers/leds/leds-powernv.c
drivers/leds/leds-pwm.c
drivers/leds/leds-regulator.c
drivers/leds/leds-sunfire.c
drivers/leds/leds-syscon.c
drivers/leds/leds-tlc591xx.c
drivers/leds/leds-wm831x-status.c
drivers/leds/leds-wm8350.c
drivers/leds/leds.h
drivers/leds/trigger/ledtrig-backlight.c
drivers/leds/trigger/ledtrig-cpu.c
drivers/leds/trigger/ledtrig-default-on.c
drivers/leds/trigger/ledtrig-gpio.c
drivers/leds/trigger/ledtrig-heartbeat.c
drivers/leds/trigger/ledtrig-ide-disk.c
drivers/leds/trigger/ledtrig-oneshot.c
drivers/leds/trigger/ledtrig-transient.c
drivers/lightnvm/gennvm.c
drivers/md/Kconfig
drivers/md/Makefile
drivers/md/dm-bufio.c
drivers/md/dm-cache-target.c
drivers/md/dm-exception-store.h
drivers/md/dm-snap-persistent.c
drivers/md/dm-snap-transient.c
drivers/md/dm-snap.c
drivers/md/dm-thin-metadata.c
drivers/md/dm-thin.c
drivers/md/dm-verity-fec.c [new file with mode: 0644]
drivers/md/dm-verity-fec.h [new file with mode: 0644]
drivers/md/dm-verity-target.c [new file with mode: 0644]
drivers/md/dm-verity.c [deleted file]
drivers/md/dm-verity.h [new file with mode: 0644]
drivers/md/persistent-data/Kconfig
drivers/md/persistent-data/dm-block-manager.c
drivers/md/persistent-data/dm-btree.c
drivers/md/persistent-data/dm-space-map-metadata.c
drivers/media/Kconfig
drivers/media/common/cx2341x.c
drivers/media/common/saa7146/saa7146_core.c
drivers/media/common/saa7146/saa7146_fops.c
drivers/media/common/saa7146/saa7146_hlp.c
drivers/media/common/saa7146/saa7146_i2c.c
drivers/media/common/saa7146/saa7146_vbi.c
drivers/media/common/saa7146/saa7146_video.c
drivers/media/common/siano/smsir.h
drivers/media/dvb-core/demux.h
drivers/media/dvb-core/dvb-usb-ids.h
drivers/media/dvb-core/dvb_frontend.c
drivers/media/dvb-core/dvb_frontend.h
drivers/media/dvb-frontends/Kconfig
drivers/media/dvb-frontends/au8522_common.c
drivers/media/dvb-frontends/au8522_decoder.c
drivers/media/dvb-frontends/au8522_dig.c
drivers/media/dvb-frontends/au8522_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/isl6405.c
drivers/media/dvb-frontends/isl6405.h
drivers/media/dvb-frontends/isl6421.c
drivers/media/dvb-frontends/isl6421.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/rtl2832.c
drivers/media/dvb-frontends/rtl2832_sdr.c
drivers/media/dvb-frontends/si2165.c
drivers/media/dvb-frontends/stb6100.c
drivers/media/dvb-frontends/stb6100.h
drivers/media/dvb-frontends/stb6100_cfg.h
drivers/media/dvb-frontends/stb6100_proc.h
drivers/media/dvb-frontends/tda665x.c
drivers/media/dvb-frontends/tda8261.c
drivers/media/dvb-frontends/tda8261_cfg.h
drivers/media/dvb-frontends/tdhd1.h
drivers/media/i2c/Kconfig
drivers/media/i2c/Makefile
drivers/media/i2c/ad9389b.c
drivers/media/i2c/adp1653.c
drivers/media/i2c/adv7180.c
drivers/media/i2c/adv7183.c
drivers/media/i2c/adv7343.c
drivers/media/i2c/adv7393.c
drivers/media/i2c/adv7511.c
drivers/media/i2c/adv7604.c
drivers/media/i2c/adv7842.c
drivers/media/i2c/ak881x.c
drivers/media/i2c/as3645a.c
drivers/media/i2c/bt819.c
drivers/media/i2c/cs3308.c [new file with mode: 0644]
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/ir-kbd-i2c.c
drivers/media/i2c/lm3560.c
drivers/media/i2c/lm3646.c
drivers/media/i2c/m52790.c
drivers/media/i2c/m5mols/m5mols_capture.c
drivers/media/i2c/m5mols/m5mols_core.c
drivers/media/i2c/msp3400-driver.c
drivers/media/i2c/msp3400-driver.h
drivers/media/i2c/msp3400-kthreads.c
drivers/media/i2c/mt9m032.c
drivers/media/i2c/mt9p031.c
drivers/media/i2c/mt9t001.c
drivers/media/i2c/mt9v011.c
drivers/media/i2c/mt9v032.c
drivers/media/i2c/noon010pc30.c
drivers/media/i2c/ov2659.c
drivers/media/i2c/ov7670.c
drivers/media/i2c/ov9650.c
drivers/media/i2c/s5c73m3/s5c73m3-core.c
drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
drivers/media/i2c/s5c73m3/s5c73m3-spi.c
drivers/media/i2c/s5c73m3/s5c73m3.h
drivers/media/i2c/s5k4ecgx.c
drivers/media/i2c/s5k6aa.c
drivers/media/i2c/saa6588.c
drivers/media/i2c/saa7115.c
drivers/media/i2c/saa7127.c
drivers/media/i2c/smiapp/smiapp.h
drivers/media/i2c/soc_camera/mt9m001.c
drivers/media/i2c/soc_camera/mt9t112.c
drivers/media/i2c/soc_camera/mt9v022.c
drivers/media/i2c/soc_camera/ov772x.c
drivers/media/i2c/soc_camera/rj54n1cb0c.c
drivers/media/i2c/soc_camera/tw9910.c
drivers/media/i2c/sr030pc30.c
drivers/media/i2c/tc358743.c
drivers/media/i2c/ths7303.c
drivers/media/i2c/tvaudio.c
drivers/media/i2c/tvp514x.c
drivers/media/i2c/tvp5150.c
drivers/media/i2c/tvp7002.c
drivers/media/i2c/uda1342.c
drivers/media/i2c/upd64031a.c
drivers/media/i2c/upd64083.c
drivers/media/i2c/wm8775.c
drivers/media/pci/bt8xx/bttv-cards.c
drivers/media/pci/bt8xx/bttv-driver.c
drivers/media/pci/bt8xx/bttvp.h
drivers/media/pci/cobalt/cobalt-driver.c
drivers/media/pci/cobalt/cobalt-irq.c
drivers/media/pci/cobalt/cobalt-v4l2.c
drivers/media/pci/cx18/cx18-cards.c
drivers/media/pci/cx18/cx18-controls.c
drivers/media/pci/cx18/cx18-controls.h
drivers/media/pci/cx18/cx18-driver.h
drivers/media/pci/cx18/cx18-ioctl.c
drivers/media/pci/cx18/cx23418.h
drivers/media/pci/cx23885/Kconfig
drivers/media/pci/cx23885/cx23885-417.c
drivers/media/pci/cx23885/cx23885-cards.c
drivers/media/pci/cx23885/cx23885-core.c
drivers/media/pci/cx23885/cx23885-dvb.c
drivers/media/pci/cx23885/cx23885-i2c.c
drivers/media/pci/cx23885/cx23885-input.c
drivers/media/pci/cx23885/cx23885-vbi.c
drivers/media/pci/cx23885/cx23885-video.c
drivers/media/pci/cx23885/cx23885.h
drivers/media/pci/cx25821/cx25821-video.c
drivers/media/pci/cx88/cx88-alsa.c
drivers/media/pci/cx88/cx88-blackbird.c
drivers/media/pci/cx88/cx88-core.c
drivers/media/pci/cx88/cx88-dvb.c
drivers/media/pci/cx88/cx88-vbi.c
drivers/media/pci/cx88/cx88-video.c
drivers/media/pci/cx88/cx88.h
drivers/media/pci/ddbridge/ddbridge-core.c
drivers/media/pci/dm1105/dm1105.c
drivers/media/pci/dt3155/dt3155.c
drivers/media/pci/ivtv/ivtv-cards.c
drivers/media/pci/ivtv/ivtv-controls.c
drivers/media/pci/ivtv/ivtv-controls.h
drivers/media/pci/ivtv/ivtv-driver.c
drivers/media/pci/ivtv/ivtv-driver.h
drivers/media/pci/ivtv/ivtv-fileops.c
drivers/media/pci/ivtv/ivtv-firmware.c
drivers/media/pci/ivtv/ivtv-i2c.c
drivers/media/pci/ivtv/ivtv-ioctl.c
drivers/media/pci/ivtv/ivtv-routing.c
drivers/media/pci/netup_unidvb/netup_unidvb_core.c
drivers/media/pci/saa7134/saa7134-core.c
drivers/media/pci/saa7134/saa7134-ts.c
drivers/media/pci/saa7134/saa7134-vbi.c
drivers/media/pci/saa7134/saa7134-video.c
drivers/media/pci/saa7134/saa7134.h
drivers/media/pci/saa7146/hexium_gemini.c
drivers/media/pci/saa7146/hexium_orion.c
drivers/media/pci/saa7146/mxb.c
drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
drivers/media/pci/solo6x10/solo6x10-v4l2.c
drivers/media/pci/sta2x11/sta2x11_vip.c
drivers/media/pci/ttpci/av7110.c
drivers/media/pci/ttpci/av7110.h
drivers/media/pci/ttpci/av7110_av.c
drivers/media/pci/ttpci/av7110_av.h
drivers/media/pci/ttpci/av7110_ca.c
drivers/media/pci/ttpci/av7110_hw.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/budget.h
drivers/media/pci/tw68/tw68-video.c
drivers/media/pci/zoran/zoran_card.c
drivers/media/platform/Kconfig
drivers/media/platform/am437x/am437x-vpfe.c
drivers/media/platform/blackfin/bfin_capture.c
drivers/media/platform/coda/coda-bit.c
drivers/media/platform/coda/coda-common.c
drivers/media/platform/coda/coda-jpeg.c
drivers/media/platform/coda/coda.h
drivers/media/platform/davinci/Kconfig
drivers/media/platform/davinci/vpbe_display.c
drivers/media/platform/davinci/vpif_capture.c
drivers/media/platform/davinci/vpif_display.c
drivers/media/platform/exynos-gsc/gsc-m2m.c
drivers/media/platform/exynos4-is/common.c
drivers/media/platform/exynos4-is/fimc-capture.c
drivers/media/platform/exynos4-is/fimc-core.h
drivers/media/platform/exynos4-is/fimc-isp-video.c
drivers/media/platform/exynos4-is/fimc-isp.h
drivers/media/platform/exynos4-is/fimc-lite-reg.c
drivers/media/platform/exynos4-is/fimc-lite.c
drivers/media/platform/exynos4-is/fimc-lite.h
drivers/media/platform/exynos4-is/fimc-m2m.c
drivers/media/platform/exynos4-is/fimc-reg.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/m2m-deinterlace.c
drivers/media/platform/marvell-ccic/mcam-core.c
drivers/media/platform/marvell-ccic/mmp-driver.c
drivers/media/platform/mx2_emmaprp.c
drivers/media/platform/omap/omap_vout_vrfb.c
drivers/media/platform/omap3isp/ispvideo.c
drivers/media/platform/rcar_jpu.c
drivers/media/platform/s3c-camif/camif-capture.c
drivers/media/platform/s3c-camif/camif-core.h
drivers/media/platform/s3c-camif/camif-regs.h
drivers/media/platform/s5p-g2d/g2d.c
drivers/media/platform/s5p-jpeg/jpeg-core.c
drivers/media/platform/s5p-mfc/s5p_mfc.c
drivers/media/platform/s5p-mfc/s5p_mfc_common.h
drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
drivers/media/platform/s5p-mfc/s5p_mfc_dec.h
drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
drivers/media/platform/s5p-mfc/s5p_mfc_enc.h
drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
drivers/media/platform/s5p-tv/hdmi_drv.c
drivers/media/platform/s5p-tv/mixer_video.c
drivers/media/platform/s5p-tv/sii9234_drv.c
drivers/media/platform/sh_veu.c
drivers/media/platform/sh_vou.c
drivers/media/platform/soc_camera/atmel-isi.c
drivers/media/platform/soc_camera/atmel-isi.h
drivers/media/platform/soc_camera/mx2_camera.c
drivers/media/platform/soc_camera/mx3_camera.c
drivers/media/platform/soc_camera/omap1_camera.c
drivers/media/platform/soc_camera/pxa_camera.c
drivers/media/platform/soc_camera/rcar_vin.c
drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
drivers/media/platform/soc_camera/sh_mobile_csi2.c
drivers/media/platform/soc_camera/soc_camera.c
drivers/media/platform/soc_camera/soc_camera_platform.c
drivers/media/platform/soc_camera/soc_mediabus.c
drivers/media/platform/sti/bdisp/bdisp-v4l2.c
drivers/media/platform/sti/c8sectpfe/c8sectpfe-common.c
drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c
drivers/media/platform/ti-vpe/vpe.c
drivers/media/platform/timblogiw.c
drivers/media/platform/via-camera.c
drivers/media/platform/vim2m.c
drivers/media/platform/vivid/vivid-core.h
drivers/media/platform/vivid/vivid-ctrls.c
drivers/media/platform/vivid/vivid-kthread-cap.c
drivers/media/platform/vivid/vivid-kthread-out.c
drivers/media/platform/vivid/vivid-sdr-cap.c
drivers/media/platform/vivid/vivid-vbi-cap.c
drivers/media/platform/vivid/vivid-vbi-out.c
drivers/media/platform/vivid/vivid-vid-cap.c
drivers/media/platform/vivid/vivid-vid-out.c
drivers/media/platform/vsp1/vsp1_video.c
drivers/media/platform/xilinx/xilinx-dma.c
drivers/media/platform/xilinx/xilinx-tpg.c
drivers/media/platform/xilinx/xilinx-vipp.c
drivers/media/radio/radio-maxiradio.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-shark.c
drivers/media/radio/radio-shark2.c
drivers/media/radio/radio-si476x.c
drivers/media/radio/radio-tea5777.h
drivers/media/radio/radio-timb.c
drivers/media/radio/si4713/radio-usb-si4713.c
drivers/media/radio/si4713/si4713.h
drivers/media/radio/tea575x.c
drivers/media/rc/Kconfig
drivers/media/rc/gpio-ir-recv.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-xmp-decoder.c
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-main.c
drivers/media/rc/st_rc.c
drivers/media/rc/streamzap.c
drivers/media/rc/sunxi-cir.c
drivers/media/tuners/max2165.c
drivers/media/tuners/mt2063.c
drivers/media/tuners/si2157.c
drivers/media/usb/airspy/airspy.c
drivers/media/usb/as102/as102_fw.c
drivers/media/usb/au0828/au0828-vbi.c
drivers/media/usb/au0828/au0828-video.c
drivers/media/usb/cpia2/cpia2_usb.c
drivers/media/usb/cx231xx/cx231xx-417.c
drivers/media/usb/cx231xx/cx231xx-cards.c
drivers/media/usb/cx231xx/cx231xx-core.c
drivers/media/usb/cx231xx/cx231xx-dvb.c
drivers/media/usb/cx231xx/cx231xx-vbi.c
drivers/media/usb/cx231xx/cx231xx-video.c
drivers/media/usb/cx231xx/cx231xx.h
drivers/media/usb/dvb-usb-v2/Kconfig
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.c
drivers/media/usb/dvb-usb-v2/rtl28xxu.c
drivers/media/usb/dvb-usb/Kconfig
drivers/media/usb/em28xx/em28xx-camera.c
drivers/media/usb/em28xx/em28xx-cards.c
drivers/media/usb/em28xx/em28xx-dvb.c
drivers/media/usb/em28xx/em28xx-vbi.c
drivers/media/usb/em28xx/em28xx-video.c
drivers/media/usb/em28xx/em28xx.h
drivers/media/usb/go7007/go7007-driver.c
drivers/media/usb/go7007/go7007-usb.c
drivers/media/usb/go7007/go7007-v4l2.c
drivers/media/usb/gspca/ov534.c
drivers/media/usb/gspca/topro.c
drivers/media/usb/hackrf/hackrf.c
drivers/media/usb/hdpvr/hdpvr-video.c
drivers/media/usb/hdpvr/hdpvr.h
drivers/media/usb/msi2500/msi2500.c
drivers/media/usb/pvrusb2/pvrusb2-audio.c
drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c
drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c
drivers/media/usb/pwc/pwc-if.c
drivers/media/usb/s2255/s2255drv.c
drivers/media/usb/stk1160/stk1160-core.c
drivers/media/usb/stk1160/stk1160-v4l.c
drivers/media/usb/stk1160/stk1160-video.c
drivers/media/usb/tm6000/tm6000-cards.c
drivers/media/usb/ttusb-dec/ttusb_dec.c
drivers/media/usb/usbtv/usbtv-video.c
drivers/media/usb/usbvision/usbvision-core.c
drivers/media/usb/usbvision/usbvision-video.c
drivers/media/usb/uvc/uvc_ctrl.c
drivers/media/usb/uvc/uvc_driver.c
drivers/media/usb/uvc/uvc_queue.c
drivers/media/usb/uvc/uvc_v4l2.c
drivers/media/usb/uvc/uvc_video.c
drivers/media/v4l2-core/v4l2-clk.c
drivers/media/v4l2-core/v4l2-compat-ioctl32.c
drivers/media/v4l2-core/v4l2-ctrls.c
drivers/media/v4l2-core/v4l2-device.c
drivers/media/v4l2-core/v4l2-dv-timings.c
drivers/media/v4l2-core/v4l2-flash-led-class.c
drivers/media/v4l2-core/v4l2-ioctl.c
drivers/media/v4l2-core/videobuf2-core.c
drivers/media/v4l2-core/videobuf2-internal.h [deleted file]
drivers/media/v4l2-core/videobuf2-v4l2.c
drivers/mfd/timberdale.c
drivers/mmc/card/block.c
drivers/mmc/core/bus.c
drivers/mmc/core/core.c
drivers/mmc/core/core.h
drivers/mmc/core/host.c
drivers/mmc/core/mmc.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/pwrseq.h
drivers/mmc/core/pwrseq_emmc.c
drivers/mmc/core/pwrseq_simple.c
drivers/mmc/core/sd.c
drivers/mmc/core/sdio.c
drivers/mmc/core/sdio_bus.c
drivers/mmc/host/Kconfig
drivers/mmc/host/atmel-mci-regs.h [deleted file]
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/cb710-mmc.h
drivers/mmc/host/dw_mmc-pltfm.c
drivers/mmc/host/dw_mmc-rockchip.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/mtk-sd.c
drivers/mmc/host/mvsdio.c
drivers/mmc/host/of_mmc_spi.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-of-at91.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-pci-core.c
drivers/mmc/host/sdhci-pltfm.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sh_mmcif.c
drivers/mmc/host/usdhi6rol0.c
drivers/mtd/mtdcore.c
drivers/mtd/spi-nor/spi-nor.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
drivers/net/ethernet/emulex/benet/be.h
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/emulex/benet/be_roce.c
drivers/net/ethernet/emulex/benet/be_roce.h
drivers/net/ethernet/mellanox/mlx4/en_clock.c
drivers/net/ethernet/mellanox/mlx4/en_main.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/natsemi/natsemi.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/renesas/sh_eth.h
drivers/net/ethernet/ti/cpsw.c
drivers/net/geneve.c
drivers/net/hamradio/6pack.c
drivers/net/hamradio/mkiss.c
drivers/net/usb/cdc_mbim.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/r8152.c
drivers/net/veth.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vmxnet3/vmxnet3_int.h
drivers/net/vrf.c
drivers/net/wireless/iwlwifi/iwl-7000.c
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/pci/host/Kconfig
drivers/pci/host/pcie-hisi.c
drivers/pci/msi.c
drivers/pci/pci-acpi.c
drivers/pci/probe.c
drivers/perf/arm_pmu.c
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/bcm/Kconfig
drivers/pinctrl/bcm/Makefile
drivers/pinctrl/bcm/pinctrl-bcm2835.c
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c [deleted file]
drivers/pinctrl/bcm/pinctrl-iproc-gpio.c [new file with mode: 0644]
drivers/pinctrl/bcm/pinctrl-nsp-gpio.c [new file with mode: 0644]
drivers/pinctrl/berlin/Makefile
drivers/pinctrl/mediatek/pinctrl-mt8127.c
drivers/pinctrl/mediatek/pinctrl-mt8135.c
drivers/pinctrl/mediatek/pinctrl-mt8173.c
drivers/pinctrl/mediatek/pinctrl-mtk-common.c
drivers/pinctrl/mvebu/Makefile
drivers/pinctrl/mvebu/pinctrl-mvebu.c
drivers/pinctrl/pinconf-generic.c
drivers/pinctrl/pinctrl-adi2.c
drivers/pinctrl/pinctrl-at91-pio4.c
drivers/pinctrl/pinctrl-at91.c
drivers/pinctrl/pinctrl-lantiq.h
drivers/pinctrl/pinctrl-rockchip.c
drivers/pinctrl/pinctrl-single.c
drivers/pinctrl/pinctrl-tegra-xusb.c
drivers/pinctrl/pinctrl-tegra.c
drivers/pinctrl/pinctrl-xway.c
drivers/pinctrl/pxa/Kconfig [new file with mode: 0644]
drivers/pinctrl/pxa/Makefile [new file with mode: 0644]
drivers/pinctrl/pxa/pinctrl-pxa27x.c [new file with mode: 0644]
drivers/pinctrl/pxa/pinctrl-pxa2xx.c [new file with mode: 0644]
drivers/pinctrl/pxa/pinctrl-pxa2xx.h [new file with mode: 0644]
drivers/pinctrl/qcom/Kconfig
drivers/pinctrl/qcom/Makefile
drivers/pinctrl/qcom/pinctrl-msm8996.c [new file with mode: 0644]
drivers/pinctrl/qcom/pinctrl-qdf2xxx.c
drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c
drivers/pinctrl/samsung/pinctrl-exynos.c
drivers/pinctrl/samsung/pinctrl-samsung.c
drivers/pinctrl/samsung/pinctrl-samsung.h
drivers/pinctrl/sh-pfc/pfc-emev2.c
drivers/pinctrl/sh-pfc/pfc-r8a7740.c
drivers/pinctrl/sh-pfc/pfc-r8a7778.c
drivers/pinctrl/sh-pfc/pfc-r8a7779.c
drivers/pinctrl/sh-pfc/pfc-r8a7790.c
drivers/pinctrl/sh-pfc/pfc-r8a7791.c
drivers/pinctrl/sh-pfc/pfc-r8a7794.c
drivers/pinctrl/sh-pfc/pfc-r8a7795.c
drivers/pinctrl/sh-pfc/pfc-sh73a0.c
drivers/pinctrl/sh-pfc/pfc-sh7734.c
drivers/pinctrl/sh-pfc/pinctrl.c
drivers/pinctrl/sh-pfc/sh_pfc.h
drivers/pinctrl/sirf/pinctrl-atlas7.c
drivers/pinctrl/sirf/pinctrl-sirf.c
drivers/pinctrl/spear/Makefile
drivers/pinctrl/sunxi/Kconfig
drivers/pinctrl/sunxi/Makefile
drivers/pinctrl/sunxi/pinctrl-sun8i-h3.c [new file with mode: 0644]
drivers/pinctrl/sunxi/pinctrl-sun9i-a80-r.c [new file with mode: 0644]
drivers/pinctrl/uniphier/Kconfig
drivers/s390/char/sclp_early.c
drivers/scsi/sd.c
drivers/soc/qcom/spm.c
drivers/staging/lustre/lustre/llite/symlink.c
drivers/staging/lustre/lustre/llite/xattr.c
drivers/staging/media/bcm2048/radio-bcm2048.c
drivers/staging/media/davinci_vpfe/Kconfig
drivers/staging/media/davinci_vpfe/dm365_ipipe.c
drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c
drivers/staging/media/davinci_vpfe/dm365_resizer.c
drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
drivers/staging/media/davinci_vpfe/vpfe_video.c
drivers/staging/media/lirc/lirc_imon.c
drivers/staging/media/lirc/lirc_parallel.c
drivers/staging/media/lirc/lirc_sasem.c
drivers/staging/media/lirc/lirc_serial.c
drivers/staging/media/omap4iss/Kconfig
drivers/staging/media/omap4iss/iss.c
drivers/staging/media/omap4iss/iss.h
drivers/staging/media/omap4iss/iss_csi2.c
drivers/staging/media/omap4iss/iss_csiphy.h
drivers/staging/media/omap4iss/iss_resizer.c
drivers/staging/media/omap4iss/iss_video.c
drivers/tty/sysrq.c
drivers/usb/gadget/function/uvc_queue.c
drivers/xen/Makefile
drivers/xen/acpi.c
drivers/xen/efi.c
drivers/xen/gntdev.c
drivers/xen/grant-table.c
drivers/xen/pcpu.c
drivers/xen/time.c [new file with mode: 0644]
drivers/xen/xen-acpi-cpuhotplug.c
drivers/xen/xen-acpi-pad.c
drivers/xen/xen-acpi-processor.c
drivers/xen/xenfs/xensyms.c
firmware/WHENCE
fs/9p/acl.c
fs/9p/vfs_inode.c
fs/9p/vfs_inode_dotl.c
fs/9p/xattr.c
fs/affs/inode.c
fs/affs/namei.c
fs/affs/symlink.c
fs/afs/inode.c
fs/autofs4/symlink.c
fs/befs/linuxvfs.c
fs/btrfs/acl.c
fs/btrfs/disk-io.c
fs/btrfs/inode.c
fs/btrfs/xattr.c
fs/btrfs/xattr.h
fs/ceph/acl.c
fs/ceph/inode.c
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/link.c
fs/cifs/xattr.c
fs/coda/cnode.c
fs/coda/symlink.c
fs/compat_ioctl.c
fs/configfs/symlink.c
fs/cramfs/inode.c
fs/dcache.c
fs/ecryptfs/inode.c
fs/efs/inode.c
fs/efs/symlink.c
fs/exofs/inode.c
fs/exofs/namei.c
fs/ext2/inode.c
fs/ext2/namei.c
fs/ext2/symlink.c
fs/ext2/xattr.c
fs/ext2/xattr_security.c
fs/ext2/xattr_trusted.c
fs/ext2/xattr_user.c
fs/ext4/inode.c
fs/ext4/namei.c
fs/ext4/symlink.c
fs/ext4/xattr.c
fs/ext4/xattr_security.c
fs/ext4/xattr_trusted.c
fs/ext4/xattr_user.c
fs/f2fs/inode.c
fs/f2fs/namei.c
fs/f2fs/xattr.c
fs/f2fs/xattr.h
fs/freevxfs/vxfs_inode.c
fs/fuse/dir.c
fs/gfs2/acl.c
fs/gfs2/acl.h
fs/gfs2/inode.c
fs/gfs2/xattr.c
fs/gfs2/xattr.h
fs/hfsplus/inode.c
fs/hfsplus/posix_acl.c
fs/hfsplus/xattr.c
fs/hostfs/hostfs_kern.c
fs/hpfs/inode.c
fs/hpfs/namei.c
fs/hugetlbfs/inode.c
fs/inode.c
fs/internal.h
fs/ioctl.c
fs/isofs/inode.c
fs/isofs/rock.c
fs/jffs2/security.c
fs/jffs2/symlink.c
fs/jffs2/xattr.c
fs/jffs2/xattr_trusted.c
fs/jffs2/xattr_user.c
fs/jfs/acl.c
fs/jfs/inode.c
fs/jfs/namei.c
fs/jfs/symlink.c
fs/kernfs/inode.c
fs/kernfs/symlink.c
fs/libfs.c
fs/logfs/dir.c
fs/logfs/inode.c
fs/logfs/logfs.h
fs/minix/inode.c
fs/namei.c
fs/ncpfs/inode.c
fs/nfs/inode.c
fs/nfs/nfs3acl.c
fs/nfs/nfs4proc.c
fs/nfs/symlink.c
fs/nilfs2/inode.c
fs/nilfs2/namei.c
fs/ocfs2/dlm/dlmmaster.c
fs/ocfs2/inode.c
fs/ocfs2/locks.c
fs/ocfs2/namei.c
fs/ocfs2/resize.c
fs/ocfs2/symlink.c
fs/ocfs2/xattr.c
fs/overlayfs/inode.c
fs/posix_acl.c
fs/proc/base.c
fs/proc/inode.c
fs/proc/namespaces.c
fs/proc/self.c
fs/proc/thread_self.c
fs/qnx4/inode.c
fs/qnx6/inode.c
fs/ramfs/inode.c
fs/reiserfs/inode.c
fs/reiserfs/namei.c
fs/reiserfs/xattr.c
fs/reiserfs/xattr_acl.c
fs/reiserfs/xattr_security.c
fs/reiserfs/xattr_trusted.c
fs/reiserfs/xattr_user.c
fs/romfs/super.c
fs/squashfs/inode.c
fs/squashfs/symlink.c
fs/squashfs/xattr.c
fs/sysv/inode.c
fs/ubifs/file.c
fs/udf/inode.c
fs/udf/namei.c
fs/udf/symlink.c
fs/udf/udfdecl.h
fs/ufs/Makefile
fs/ufs/inode.c
fs/ufs/namei.c
fs/ufs/symlink.c [deleted file]
fs/ufs/ufs.h
fs/xattr.c
fs/xfs/xfs_acl.c
fs/xfs/xfs_acl.h
fs/xfs/xfs_iops.c
fs/xfs/xfs_xattr.c
include/asm-generic/barrier.h
include/asm-generic/pgtable.h
include/asm-generic/qspinlock.h
include/clocksource/arm_arch_timer.h
include/kvm/arm_vgic.h
include/linux/arm-smccc.h [new file with mode: 0644]
include/linux/blkdev.h
include/linux/bootmem.h
include/linux/clocksource.h
include/linux/compiler.h
include/linux/component.h
include/linux/context_tracking.h
include/linux/context_tracking_state.h
include/linux/delayed_call.h [new file with mode: 0644]
include/linux/edac.h
include/linux/filter.h
include/linux/fs.h
include/linux/fsl/edac.h [new file with mode: 0644]
include/linux/ftrace.h
include/linux/hugetlb.h
include/linux/init_task.h
include/linux/interrupt.h
include/linux/irqchip/arm-gic.h
include/linux/irqdesc.h
include/linux/irqdomain.h
include/linux/kernel.h
include/linux/kexec.h
include/linux/kvm_host.h
include/linux/kvm_para.h
include/linux/leds.h
include/linux/libata.h
include/linux/list.h
include/linux/list_bl.h
include/linux/list_nulls.h
include/linux/memblock.h
include/linux/mfd/wm8350/pmic.h
include/linux/mmc/dw_mmc.h
include/linux/mmc/host.h
include/linux/msi.h
include/linux/mtd/spi-nor.h
include/linux/nfs_fs.h
include/linux/pci.h
include/linux/percpu-refcount.h
include/linux/percpu.h
include/linux/perf/arm_pmu.h
include/linux/platform_data/camera-mx2.h [deleted file]
include/linux/platform_data/camera-mx3.h [deleted file]
include/linux/platform_data/camera-pxa.h [deleted file]
include/linux/platform_data/camera-rcar.h [deleted file]
include/linux/platform_data/coda.h [deleted file]
include/linux/platform_data/irq-renesas-intc-irqpin.h [deleted file]
include/linux/platform_data/media/camera-mx2.h [new file with mode: 0644]
include/linux/platform_data/media/camera-mx3.h [new file with mode: 0644]
include/linux/platform_data/media/camera-pxa.h [new file with mode: 0644]
include/linux/platform_data/media/coda.h [new file with mode: 0644]
include/linux/platform_data/media/gpio-ir-recv.h [new file with mode: 0644]
include/linux/platform_data/media/ir-rx51.h [new file with mode: 0644]
include/linux/platform_data/media/mmp-camera.h [new file with mode: 0644]
include/linux/platform_data/media/omap1_camera.h [new file with mode: 0644]
include/linux/platform_data/media/omap4iss.h [new file with mode: 0644]
include/linux/platform_data/media/s5p_hdmi.h [new file with mode: 0644]
include/linux/platform_data/media/si4713.h [new file with mode: 0644]
include/linux/platform_data/media/sii9234.h [new file with mode: 0644]
include/linux/platform_data/media/soc_camera_platform.h [new file with mode: 0644]
include/linux/platform_data/media/timb_radio.h [new file with mode: 0644]
include/linux/platform_data/media/timb_video.h [new file with mode: 0644]
include/linux/platform_data/mmc-mvsdio.h [deleted file]
include/linux/platform_device.h
include/linux/posix_acl_xattr.h
include/linux/rculist.h
include/linux/rcupdate.h
include/linux/rcutiny.h
include/linux/rcutree.h
include/linux/regmap.h
include/linux/sched.h
include/linux/sched_clock.h
include/linux/stop_machine.h
include/linux/time.h
include/linux/tracepoint-defs.h [new file with mode: 0644]
include/linux/tracepoint.h
include/linux/usb/cdc_ncm.h
include/linux/videodev2.h
include/linux/vmstat.h
include/linux/vtime.h
include/linux/wait.h
include/linux/workqueue.h
include/linux/xattr.h
include/media/ad9389b.h [deleted file]
include/media/adp1653.h [deleted file]
include/media/adv7183.h [deleted file]
include/media/adv7343.h [deleted file]
include/media/adv7393.h [deleted file]
include/media/adv7511.h [deleted file]
include/media/adv7604.h [deleted file]
include/media/adv7842.h [deleted file]
include/media/ak881x.h [deleted file]
include/media/as3645a.h [deleted file]
include/media/bt819.h [deleted file]
include/media/cs5345.h [deleted file]
include/media/cs53l32a.h [deleted file]
include/media/cx2341x.h [deleted file]
include/media/cx25840.h [deleted file]
include/media/drv-intf/cx2341x.h [new file with mode: 0644]
include/media/drv-intf/cx25840.h [new file with mode: 0644]
include/media/drv-intf/exynos-fimc.h [new file with mode: 0644]
include/media/drv-intf/msp3400.h [new file with mode: 0644]
include/media/drv-intf/s3c_camif.h [new file with mode: 0644]
include/media/drv-intf/saa7146.h [new file with mode: 0644]
include/media/drv-intf/saa7146_vv.h [new file with mode: 0644]
include/media/drv-intf/sh_mobile_ceu.h [new file with mode: 0644]
include/media/drv-intf/sh_mobile_csi2.h [new file with mode: 0644]
include/media/drv-intf/sh_vou.h [new file with mode: 0644]
include/media/drv-intf/si476x.h [new file with mode: 0644]
include/media/drv-intf/soc_mediabus.h [new file with mode: 0644]
include/media/drv-intf/tea575x.h [new file with mode: 0644]
include/media/exynos-fimc.h [deleted file]
include/media/gpio-ir-recv.h [deleted file]
include/media/i2c/ad9389b.h [new file with mode: 0644]
include/media/i2c/adp1653.h [new file with mode: 0644]
include/media/i2c/adv7183.h [new file with mode: 0644]
include/media/i2c/adv7343.h [new file with mode: 0644]
include/media/i2c/adv7393.h [new file with mode: 0644]
include/media/i2c/adv7511.h [new file with mode: 0644]
include/media/i2c/adv7604.h [new file with mode: 0644]
include/media/i2c/adv7842.h [new file with mode: 0644]
include/media/i2c/ak881x.h [new file with mode: 0644]
include/media/i2c/as3645a.h [new file with mode: 0644]
include/media/i2c/bt819.h [new file with mode: 0644]
include/media/i2c/cs5345.h [new file with mode: 0644]
include/media/i2c/cs53l32a.h [new file with mode: 0644]
include/media/i2c/ir-kbd-i2c.h [new file with mode: 0644]
include/media/i2c/lm3560.h [new file with mode: 0644]
include/media/i2c/lm3646.h [new file with mode: 0644]
include/media/i2c/m52790.h [new file with mode: 0644]
include/media/i2c/m5mols.h [new file with mode: 0644]
include/media/i2c/mt9m032.h [new file with mode: 0644]
include/media/i2c/mt9p031.h [new file with mode: 0644]
include/media/i2c/mt9t001.h [new file with mode: 0644]
include/media/i2c/mt9t112.h [new file with mode: 0644]
include/media/i2c/mt9v011.h [new file with mode: 0644]
include/media/i2c/mt9v022.h [new file with mode: 0644]
include/media/i2c/mt9v032.h [new file with mode: 0644]
include/media/i2c/noon010pc30.h [new file with mode: 0644]
include/media/i2c/ov2659.h [new file with mode: 0644]
include/media/i2c/ov7670.h [new file with mode: 0644]
include/media/i2c/ov772x.h [new file with mode: 0644]
include/media/i2c/ov9650.h [new file with mode: 0644]
include/media/i2c/rj54n1cb0c.h [new file with mode: 0644]
include/media/i2c/s5c73m3.h [new file with mode: 0644]
include/media/i2c/s5k4ecgx.h [new file with mode: 0644]
include/media/i2c/s5k6aa.h [new file with mode: 0644]
include/media/i2c/saa6588.h [new file with mode: 0644]
include/media/i2c/saa7115.h [new file with mode: 0644]
include/media/i2c/saa7127.h [new file with mode: 0644]
include/media/i2c/smiapp.h [new file with mode: 0644]
include/media/i2c/sr030pc30.h [new file with mode: 0644]
include/media/i2c/tc358743.h [new file with mode: 0644]
include/media/i2c/ths7303.h [new file with mode: 0644]
include/media/i2c/tvaudio.h [new file with mode: 0644]
include/media/i2c/tvp514x.h [new file with mode: 0644]
include/media/i2c/tvp5150.h [new file with mode: 0644]
include/media/i2c/tvp7002.h [new file with mode: 0644]
include/media/i2c/tw9910.h [new file with mode: 0644]
include/media/i2c/uda1342.h [new file with mode: 0644]
include/media/i2c/upd64031a.h [new file with mode: 0644]
include/media/i2c/upd64083.h [new file with mode: 0644]
include/media/i2c/wm8775.h [new file with mode: 0644]
include/media/ir-kbd-i2c.h [deleted file]
include/media/ir-rx51.h [deleted file]
include/media/lirc.h
include/media/lm3560.h [deleted file]
include/media/lm3646.h [deleted file]
include/media/m52790.h [deleted file]
include/media/m5mols.h [deleted file]
include/media/mmp-camera.h [deleted file]
include/media/msp3400.h [deleted file]
include/media/mt9m032.h [deleted file]
include/media/mt9p031.h [deleted file]
include/media/mt9t001.h [deleted file]
include/media/mt9t112.h [deleted file]
include/media/mt9v011.h [deleted file]
include/media/mt9v022.h [deleted file]
include/media/mt9v032.h [deleted file]
include/media/noon010pc30.h [deleted file]
include/media/omap1_camera.h [deleted file]
include/media/omap4iss.h [deleted file]
include/media/ov2659.h [deleted file]
include/media/ov7670.h [deleted file]
include/media/ov772x.h [deleted file]
include/media/ov9650.h [deleted file]
include/media/rc-core.h
include/media/rc-map.h
include/media/rj54n1cb0c.h [deleted file]
include/media/s3c_camif.h [deleted file]
include/media/s5c73m3.h [deleted file]
include/media/s5k4ecgx.h [deleted file]
include/media/s5k6aa.h [deleted file]
include/media/s5p_hdmi.h [deleted file]
include/media/saa6588.h [deleted file]
include/media/saa7115.h [deleted file]
include/media/saa7127.h [deleted file]
include/media/saa7146.h [deleted file]
include/media/saa7146_vv.h [deleted file]
include/media/sh_mobile_ceu.h [deleted file]
include/media/sh_mobile_csi2.h [deleted file]
include/media/sh_vou.h [deleted file]
include/media/si4713.h [deleted file]
include/media/si476x.h [deleted file]
include/media/sii9234.h [deleted file]
include/media/smiapp.h [deleted file]
include/media/soc_camera_platform.h [deleted file]
include/media/soc_mediabus.h [deleted file]
include/media/sr030pc30.h [deleted file]
include/media/tc358743.h [deleted file]
include/media/tea575x.h [deleted file]
include/media/ths7303.h [deleted file]
include/media/timb_radio.h [deleted file]
include/media/timb_video.h [deleted file]
include/media/tvaudio.h [deleted file]
include/media/tvp514x.h [deleted file]
include/media/tvp5150.h [deleted file]
include/media/tvp7002.h [deleted file]
include/media/tw9910.h [deleted file]
include/media/uda1342.h [deleted file]
include/media/upd64031a.h [deleted file]
include/media/upd64083.h [deleted file]
include/media/v4l2-clk.h
include/media/v4l2-dv-timings.h
include/media/videobuf2-core.h
include/media/videobuf2-v4l2.h
include/media/wm8775.h [deleted file]
include/net/l3mdev.h
include/net/route.h
include/sound/soc.h
include/trace/events/v4l2.h
include/trace/events/vb2.h
include/uapi/drm/drm_fourcc.h
include/uapi/linux/dvb/video.h
include/uapi/linux/kvm.h
include/uapi/linux/lirc.h [new file with mode: 0644]
include/uapi/linux/perf_event.h
include/uapi/linux/usb/video.h
include/uapi/linux/v4l2-controls.h
include/uapi/linux/videodev2.h
include/uapi/xen/gntdev.h
include/xen/interface/platform.h
include/xen/interface/xen.h
include/xen/xen-ops.h
init/main.c
kernel/context_tracking.c
kernel/events/core.c
kernel/fork.c
kernel/futex.c
kernel/irq/chip.c
kernel/irq/irqdesc.c
kernel/irq/irqdomain.c
kernel/irq/manage.c
kernel/irq/msi.c
kernel/kexec_core.c
kernel/ksysfs.c
kernel/locking/qspinlock.c
kernel/locking/qspinlock_paravirt.h
kernel/locking/qspinlock_stat.h [new file with mode: 0644]
kernel/module.c
kernel/panic.c
kernel/rcu/rcutorture.c
kernel/rcu/srcu.c
kernel/rcu/tree.c
kernel/rcu/tree.h
kernel/rcu/tree_plugin.h
kernel/rcu/tree_trace.c
kernel/rcu/update.c
kernel/sched/auto_group.c
kernel/sched/clock.c
kernel/sched/core.c
kernel/sched/cputime.c
kernel/sched/deadline.c
kernel/sched/fair.c
kernel/sched/idle_task.c
kernel/sched/sched.h
kernel/stop_machine.c
kernel/time/alarmtimer.c
kernel/time/clocksource.c
kernel/time/ntp.c
kernel/time/ntp_internal.h
kernel/time/posix-clock.c
kernel/time/tick-sched.c
kernel/time/timekeeping.c
kernel/time/timekeeping_internal.h
kernel/trace/trace_printk.c
kernel/watchdog.c
kernel/workqueue.c
lib/Kconfig.debug
lib/atomic64_test.c
lib/list_debug.c
lib/rhashtable.c
mm/bootmem.c
mm/memblock.c
mm/memcontrol.c
mm/memory_hotplug.c
mm/mremap.c
mm/nobootmem.c
mm/shmem.c
mm/vmstat.c
net/bridge/br_stp_if.c
net/core/dst.c
net/ipv4/ipip.c
net/ipv4/raw.c
net/ipv4/tcp_input.c
net/ipv4/udp.c
net/ipv4/xfrm4_policy.c
net/ipv6/addrconf.c
net/ipv6/addrlabel.c
net/ipv6/ndisc.c
net/ipv6/xfrm6_policy.c
net/netfilter/nf_tables_netdev.c
net/netfilter/nft_ct.c
net/openvswitch/conntrack.c
net/openvswitch/flow_netlink.c
net/sched/sch_generic.c
net/sctp/sm_statefuns.c
net/sctp/socket.c
net/socket.c
net/unix/af_unix.c
net/xfrm/xfrm_policy.c
scripts/ld-version.sh
scripts/recordmcount.c
security/keys/keyctl.c
security/smack/smack_lsm.c
sound/pci/es1968.c
sound/pci/fm801.c
sound/pci/hda/patch_realtek.c
sound/soc/codecs/arizona.c
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5645.h
sound/soc/intel/skylake/skl-topology.c
sound/soc/intel/skylake/skl.c
sound/soc/intel/skylake/skl.h
tools/Makefile
tools/build/Makefile
tools/build/Makefile.feature
tools/build/Makefile.include
tools/build/feature/Makefile
tools/include/linux/bitmap.h [new file with mode: 0644]
tools/include/linux/string.h [new file with mode: 0644]
tools/lib/bitmap.c [new file with mode: 0644]
tools/lib/bpf/Makefile
tools/lib/bpf/bpf.c
tools/lib/bpf/bpf.h
tools/lib/bpf/libbpf.c
tools/lib/bpf/libbpf.h
tools/lib/find_bit.c [new file with mode: 0644]
tools/lib/string.c [new file with mode: 0644]
tools/lib/subcmd/Build [new file with mode: 0644]
tools/lib/subcmd/Makefile [new file with mode: 0644]
tools/lib/subcmd/exec-cmd.c [new file with mode: 0644]
tools/lib/subcmd/exec-cmd.h [new file with mode: 0644]
tools/lib/subcmd/help.c [new file with mode: 0644]
tools/lib/subcmd/help.h [new file with mode: 0644]
tools/lib/subcmd/pager.c [new file with mode: 0644]
tools/lib/subcmd/pager.h [new file with mode: 0644]
tools/lib/subcmd/parse-options.c [new file with mode: 0644]
tools/lib/subcmd/parse-options.h [new file with mode: 0644]
tools/lib/subcmd/run-command.c [new file with mode: 0644]
tools/lib/subcmd/run-command.h [new file with mode: 0644]
tools/lib/subcmd/sigchain.c [new file with mode: 0644]
tools/lib/subcmd/sigchain.h [new file with mode: 0644]
tools/lib/subcmd/subcmd-config.c [new file with mode: 0644]
tools/lib/subcmd/subcmd-config.h [new file with mode: 0644]
tools/lib/subcmd/subcmd-util.h [new file with mode: 0644]
tools/lib/traceevent/event-parse.c
tools/lib/traceevent/event-parse.h
tools/lib/util/find_next_bit.c [deleted file]
tools/perf/Build
tools/perf/Documentation/perf-config.txt [new file with mode: 0644]
tools/perf/Documentation/perf-evlist.txt
tools/perf/Documentation/perf-record.txt
tools/perf/Documentation/perf-report.txt
tools/perf/Documentation/perf-stat.txt
tools/perf/Documentation/perf-top.txt
tools/perf/Documentation/tips.txt [new file with mode: 0644]
tools/perf/MANIFEST
tools/perf/Makefile.perf
tools/perf/arch/x86/include/arch-tests.h
tools/perf/arch/x86/tests/insn-x86.c
tools/perf/arch/x86/tests/intel-cqm.c
tools/perf/arch/x86/tests/perf-time-to-tsc.c
tools/perf/arch/x86/tests/rdpmc.c
tools/perf/arch/x86/util/Build
tools/perf/arch/x86/util/intel-bts.c
tools/perf/arch/x86/util/intel-pt.c
tools/perf/bench/futex-hash.c
tools/perf/bench/futex-lock-pi.c
tools/perf/bench/futex-requeue.c
tools/perf/bench/futex-wake-parallel.c
tools/perf/bench/futex-wake.c
tools/perf/bench/mem-functions.c
tools/perf/bench/numa.c
tools/perf/bench/sched-messaging.c
tools/perf/bench/sched-pipe.c
tools/perf/builtin-annotate.c
tools/perf/builtin-bench.c
tools/perf/builtin-buildid-cache.c
tools/perf/builtin-buildid-list.c
tools/perf/builtin-config.c [new file with mode: 0644]
tools/perf/builtin-data.c
tools/perf/builtin-diff.c
tools/perf/builtin-evlist.c
tools/perf/builtin-help.c
tools/perf/builtin-inject.c
tools/perf/builtin-kmem.c
tools/perf/builtin-kvm.c
tools/perf/builtin-list.c
tools/perf/builtin-lock.c
tools/perf/builtin-mem.c
tools/perf/builtin-probe.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-script.c
tools/perf/builtin-stat.c
tools/perf/builtin-timechart.c
tools/perf/builtin-top.c
tools/perf/builtin-trace.c
tools/perf/builtin-version.c [new file with mode: 0644]
tools/perf/builtin.h
tools/perf/command-list.txt
tools/perf/config/Makefile
tools/perf/config/utilities.mak
tools/perf/perf.c
tools/perf/scripts/python/stat-cpi.py [new file with mode: 0644]
tools/perf/tests/.gitignore
tools/perf/tests/Build
tools/perf/tests/attr.c
tools/perf/tests/bp_signal.c
tools/perf/tests/bp_signal_overflow.c
tools/perf/tests/bpf-script-test-prologue.c [new file with mode: 0644]
tools/perf/tests/bpf.c
tools/perf/tests/builtin-test.c
tools/perf/tests/code-reading.c
tools/perf/tests/cpumap.c [new file with mode: 0644]
tools/perf/tests/dso-data.c
tools/perf/tests/dwarf-unwind.c
tools/perf/tests/event_update.c [new file with mode: 0644]
tools/perf/tests/evsel-roundtrip-name.c
tools/perf/tests/evsel-tp-sched.c
tools/perf/tests/fdarray.c
tools/perf/tests/hists_common.c
tools/perf/tests/hists_cumulate.c
tools/perf/tests/hists_filter.c
tools/perf/tests/hists_link.c
tools/perf/tests/hists_output.c
tools/perf/tests/keep-tracking.c
tools/perf/tests/kmod-path.c
tools/perf/tests/llvm.c
tools/perf/tests/llvm.h
tools/perf/tests/make
tools/perf/tests/mmap-basic.c
tools/perf/tests/mmap-thread-lookup.c
tools/perf/tests/openat-syscall-all-cpus.c
tools/perf/tests/openat-syscall-tp-fields.c
tools/perf/tests/openat-syscall.c
tools/perf/tests/parse-events.c
tools/perf/tests/parse-no-sample-id-all.c
tools/perf/tests/perf-record.c
tools/perf/tests/pmu.c
tools/perf/tests/python-use.c
tools/perf/tests/sample-parsing.c
tools/perf/tests/stat.c [new file with mode: 0644]
tools/perf/tests/sw-clock.c
tools/perf/tests/switch-tracking.c
tools/perf/tests/task-exit.c
tools/perf/tests/tests.h
tools/perf/tests/thread-map.c
tools/perf/tests/thread-mg-share.c
tools/perf/tests/topology.c
tools/perf/tests/vmlinux-kallsyms.c
tools/perf/ui/browser.c
tools/perf/ui/browsers/hists.c
tools/perf/ui/gtk/hists.c
tools/perf/ui/hist.c
tools/perf/ui/stdio/hist.c
tools/perf/util/Build
tools/perf/util/annotate.c
tools/perf/util/auxtrace.c
tools/perf/util/bitmap.c [deleted file]
tools/perf/util/bpf-loader.c
tools/perf/util/bpf-loader.h
tools/perf/util/bpf-prologue.c [new file with mode: 0644]
tools/perf/util/bpf-prologue.h [new file with mode: 0644]
tools/perf/util/build-id.c
tools/perf/util/cache.h
tools/perf/util/callchain.c
tools/perf/util/callchain.h
tools/perf/util/cgroup.c
tools/perf/util/color.c
tools/perf/util/config.c
tools/perf/util/cpumap.c
tools/perf/util/cpumap.h
tools/perf/util/data-convert-bt.c
tools/perf/util/dso.c
tools/perf/util/env.c
tools/perf/util/environment.c [deleted file]
tools/perf/util/event.c
tools/perf/util/event.h
tools/perf/util/evlist.c
tools/perf/util/evlist.h
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/exec_cmd.c [deleted file]
tools/perf/util/exec_cmd.h [deleted file]
tools/perf/util/generate-cmdlist.sh
tools/perf/util/header.c
tools/perf/util/header.h
tools/perf/util/help-unknown-cmd.c [new file with mode: 0644]
tools/perf/util/help-unknown-cmd.h [new file with mode: 0644]
tools/perf/util/help.c [deleted file]
tools/perf/util/help.h [deleted file]
tools/perf/util/hist.c
tools/perf/util/hist.h
tools/perf/util/include/linux/bitmap.h [deleted file]
tools/perf/util/include/linux/string.h [deleted file]
tools/perf/util/intel-pt.c
tools/perf/util/machine.c
tools/perf/util/map.c
tools/perf/util/pager.c [deleted file]
tools/perf/util/parse-branch-options.c
tools/perf/util/parse-events.c
tools/perf/util/parse-options.c [deleted file]
tools/perf/util/parse-options.h [deleted file]
tools/perf/util/parse-regs-options.c
tools/perf/util/path.c
tools/perf/util/pmu.c
tools/perf/util/probe-event.c
tools/perf/util/probe-finder.c
tools/perf/util/python-ext-sources
tools/perf/util/run-command.c [deleted file]
tools/perf/util/run-command.h [deleted file]
tools/perf/util/scripting-engines/trace-event-python.c
tools/perf/util/session.c
tools/perf/util/session.h
tools/perf/util/sigchain.c [deleted file]
tools/perf/util/sigchain.h [deleted file]
tools/perf/util/sort.c
tools/perf/util/sort.h
tools/perf/util/stat.c
tools/perf/util/stat.h
tools/perf/util/string.c
tools/perf/util/symbol-elf.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/term.c [new file with mode: 0644]
tools/perf/util/term.h [new file with mode: 0644]
tools/perf/util/thread.c
tools/perf/util/thread_map.c
tools/perf/util/thread_map.h
tools/perf/util/tool.h
tools/perf/util/trace-event.h
tools/perf/util/unwind-libdw.c
tools/perf/util/unwind-libdw.h
tools/perf/util/unwind-libunwind.c
tools/perf/util/util.c
tools/perf/util/util.h
tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
tools/testing/selftests/rcutorture/bin/kvm.sh
tools/testing/selftests/rcutorture/bin/parse-console.sh
tools/testing/selftests/rcutorture/doc/TINY_RCU.txt
tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt
tools/testing/selftests/timers/clocksource-switch.c
virt/kvm/arm/vgic-v3.c
virt/kvm/arm/vgic.c
virt/kvm/async_pf.c
virt/kvm/irqchip.c
virt/kvm/kvm_main.c

diff --git a/CREDITS b/CREDITS
index 8207cc62ee9d6079bb55032090ef518ef08f6b04..af67a84517d700526327c7a60543500029abb1ca 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1507,6 +1507,14 @@ S: 312/107 Canberra Avenue
 S: Griffith, ACT 2603 
 S: Australia
 
+N: Andreas Herrmann
+E: herrmann.der.user@gmail.com
+E: herrmann.der.user@googlemail.com
+D: Key developer of x86/AMD64
+D: Author of AMD family 15h processor power monitoring driver
+D: Maintainer of AMD Athlon 64 and Opteron processor frequency driver
+S: Germany
+
 N: Sebastian Hetze
 E: she@lunetix.de
 D: German Linux Documentation,
index 42a2d8593e39cd15acbab6ace23ed08e5c33a313..7b3fcc5effcde760026110c6d1f5786d34316b15 100644 (file)
@@ -238,78 +238,26 @@ X!Isound/sound_firmware.c
 !Iinclude/media/videobuf2-memops.h
      </sect1>
      <sect1><title>Digital TV (DVB) devices</title>
-!Idrivers/media/dvb-core/dvb_ca_en50221.h
-!Idrivers/media/dvb-core/dvb_frontend.h
+       <sect1><title>Digital TV Common functions</title>
 !Idrivers/media/dvb-core/dvb_math.h
 !Idrivers/media/dvb-core/dvb_ringbuffer.h
 !Idrivers/media/dvb-core/dvbdev.h
-       <sect1><title>Digital TV Demux API</title>
-           <para>The kernel demux API defines a driver-internal interface for
-           registering low-level, hardware specific driver to a hardware
-           independent demux layer. It is only of interest for Digital TV
-           device driver writers. The header file for this API is named
-           <constant>demux.h</constant> and located in
-           <constant>drivers/media/dvb-core</constant>.</para>
-
-       <para>The demux API should be implemented for each demux in the
-       system. It is used to select the TS source of a demux and to manage
-       the demux resources. When the demux client allocates a resource via
-       the demux API, it receives a pointer to the API of that
-       resource.</para>
-       <para>Each demux receives its TS input from a DVB front-end or from
-       memory, as set via this demux API. In a system with more than one
-       front-end, the API can be used to select one of the DVB front-ends
-       as a TS source for a demux, unless this is fixed in the HW platform.
-       The demux API only controls front-ends regarding to their connections
-       with demuxes; the APIs used to set the other front-end parameters,
-       such as tuning, are not defined in this document.</para>
-       <para>The functions that implement the abstract interface demux should
-       be defined static or module private and registered to the Demux
-       core for external access. It is not necessary to implement every
-       function in the struct <constant>dmx_demux</constant>. For example,
-       a demux interface might support Section filtering, but not PES
-       filtering. The API client is expected to check the value of any
-       function pointer before calling the function: the value of NULL means
-       that the &#8220;function is not available&#8221;.</para>
-       <para>Whenever the functions of the demux API modify shared data,
-       the possibilities of lost update and race condition problems should
-       be addressed, e.g. by protecting parts of code with mutexes.</para>
-       <para>Note that functions called from a bottom half context must not
-       sleep. Even a simple memory allocation without using GFP_ATOMIC can
-       result in a kernel thread being put to sleep if swapping is needed.
-       For example, the Linux kernel calls the functions of a network device
-       interface from a bottom half context. Thus, if a demux API function
-       is called from network device code, the function must not sleep.
-       </para>
-    </sect1>
-
-    <section id="demux_callback_api">
-       <title>Demux Callback API</title>
-       <para>This kernel-space API comprises the callback functions that
-       deliver filtered data to the demux client. Unlike the other DVB
-       kABIs, these functions are provided by the client and called from
-       the demux code.</para>
-       <para>The function pointers of this abstract interface are not
-       packed into a structure as in the other demux APIs, because the
-       callback functions are registered and used independent of each
-       other. As an example, it is possible for the API client to provide
-       several callback functions for receiving TS packets and no
-       callbacks for PES packets or sections.</para>
-       <para>The functions that implement the callback API need not be
-       re-entrant: when a demux driver calls one of these functions,
-       the driver is not allowed to call the function again before
-       the original call returns. If a callback is triggered by a
-       hardware interrupt, it is recommended to use the Linux
-       &#8220;bottom half&#8221; mechanism or start a tasklet instead of
-       making the callback function call directly from a hardware
-       interrupt.</para>
-       <para>This mechanism is implemented by
-       <link linkend='API-dmx-ts-cb'>dmx_ts_cb()</link> and
-       <link linkend='API-dmx-section-cb'>dmx_section_cb()</link>.</para>
-    </section>
-
+       </sect1>
+       <sect1><title>Digital TV Frontend kABI</title>
+!Pdrivers/media/dvb-core/dvb_frontend.h Digital TV Frontend
+!Idrivers/media/dvb-core/dvb_frontend.h
+       </sect1>
+       <sect1><title>Digital TV Demux kABI</title>
+!Pdrivers/media/dvb-core/demux.h Digital TV Demux
+       <sect1><title>Demux Callback API</title>
+!Pdrivers/media/dvb-core/demux.h Demux Callback
+       </sect1>
 !Idrivers/media/dvb-core/demux.h
-    </sect1>
+       </sect1>
+       <sect1><title>Digital TV Conditional Access kABI</title>
+!Idrivers/media/dvb-core/dvb_ca_en50221.h
+       </sect1>
+     </sect1>
     <sect1><title>Remote Controller devices</title>
 !Iinclude/media/rc-core.h
 !Iinclude/media/lirc_dev.h
index 08527e7ea4d0ff009e55ddfb11f5efc716210e5d..2840ff483d5a204db2e5e1c183ca143295f7ab20 100644 (file)
@@ -199,8 +199,10 @@ DVB_DOCUMENTED = \
 #
 
 install_media_images = \
-       $(Q)-mkdir $(MEDIA_OBJ_DIR)/media_api; \
-       cp $(OBJIMGFILES) $(MEDIA_SRC_DIR)/*.svg $(MEDIA_SRC_DIR)/v4l/*.svg $(MEDIA_OBJ_DIR)/media_api
+       $(Q)if [ "x$(findstring media_api.xml,$(DOCBOOKS))" != "x" ]; then \
+               mkdir -p $(MEDIA_OBJ_DIR)/media_api; \
+               cp $(OBJIMGFILES) $(MEDIA_SRC_DIR)/*.svg $(MEDIA_SRC_DIR)/v4l/*.svg $(MEDIA_OBJ_DIR)/media_api; \
+       fi
 
 $(MEDIA_OBJ_DIR)/%: $(MEDIA_SRC_DIR)/%.b64
        $(Q)base64 -d $< >$@
index 08227d4e915044985b2a6fd7b7966f95dac6e7a0..e579ae5088aefa21023f77a58c5ea16ab2198f52 100644 (file)
@@ -76,7 +76,7 @@ int main(void)
 
 <para>NOTE: While it is possible to directly call the Kernel code like the
     above example, it is strongly recommended to use
-    <ulink url="http://linuxtv.org/docs/libdvbv5/index.html">libdvbv5</ulink>,
+    <ulink url="https://linuxtv.org/docs/libdvbv5/index.html">libdvbv5</ulink>,
     as it provides abstraction to work with the supported digital TV standards
     and provides methods for usual operations like program scanning and to
     read/write channel descriptor files.</para>
index c9f68c7183cca21ddd4ef7c9a6549fe56cfa953d..837fb3b64b72959a9fbb59331d51bade071e4d61 100644 (file)
@@ -3,7 +3,7 @@
 </para>
 <para>NOTE: This section is out of date, and the code below won't even
     compile. Please refer to the
-    <ulink url="http://linuxtv.org/docs/libdvbv5/index.html">libdvbv5</ulink>
+    <ulink url="https://linuxtv.org/docs/libdvbv5/index.html">libdvbv5</ulink>
     for updated/recommended examples.
 </para>
 
index 51db1564809976dc14e3b66f3c18b13024bb4c54..b5b701f5d8c297416ab734f182496b0fdaf06464 100644 (file)
@@ -32,7 +32,7 @@ and filtering several section and PES data streams at the same time.
 new standard Linux DVB API. As a commitment to the development of
 terminals based on open standards, Nokia and Convergence made it
 available to all Linux developers and published it on
-<ulink url="http://www.linuxtv.org/" /> in September 2000.
+<ulink url="https://linuxtv.org" /> in September 2000.
 Convergence is the maintainer of the Linux DVB API. Together with the
 LinuxTV community (i.e. you, the reader of this document), the Linux DVB
 API will be constantly reviewed and improved. With the Linux driver for
index 1c5c49a2de59322174c9d89af61feb34585e8fe6..22126a991b3498c82c9b5ab43d3c37b0873cdb2d 100644 (file)
@@ -5,7 +5,7 @@
  *  This program can be used and distributed without restrictions.
  *
  *      This program is provided with the V4L2 API
- * see http://linuxtv.org/docs.php for more information
+ * see https://linuxtv.org/docs.php for more information
  */
 
 #include &lt;stdio.h&gt;
index 5701a08ed792dae2cf3fdbd5a8a8bda4fe29cc2d..5399e8904715da19fe3eec6ae40e97588dae9e8e 100644 (file)
@@ -2666,7 +2666,7 @@ is useful to display images captured with V4L2 devices.</para>
         <para>V4L2 does not support digital terrestrial, cable or
 satellite broadcast. A separate project aiming at digital receivers
 exists. You can find its homepage at <ulink
-url="http://linuxtv.org">http://linuxtv.org</ulink>. The Linux DVB API
+url="https://linuxtv.org">https://linuxtv.org</ulink>. The Linux DVB API
 has no connection to the V4L2 API except that drivers for hybrid
 hardware may support both.</para>
       </section>
index da654031ef3fd82d5ec73c56ad65af38e131e0f3..144158b3a5acad6e64f4e7be75bd82c54df1532a 100644 (file)
@@ -699,7 +699,7 @@ linkend="v4l2-buf-type" /></entry>
 buffer. It depends on the negotiated data format and may change with
 each buffer for compressed variable size data like JPEG images.
 Drivers must set this field when <structfield>type</structfield>
-refers to an input stream, applications when it refers to an output stream.
+refers to a capture stream, applications when it refers to an output stream.
 If the application sets this to 0 for an output stream, then
 <structfield>bytesused</structfield> will be set to the size of the
 buffer (see the <structfield>length</structfield> field of this struct) by
@@ -720,14 +720,14 @@ linkend="buffer-flags" />.</entry>
            <entry>Indicates the field order of the image in the
 buffer, see <xref linkend="v4l2-field" />. This field is not used when
 the buffer contains VBI data. Drivers must set it when
-<structfield>type</structfield> refers to an input stream,
+<structfield>type</structfield> refers to a capture stream,
 applications when it refers to an output stream.</entry>
          </row>
          <row>
            <entry>struct timeval</entry>
            <entry><structfield>timestamp</structfield></entry>
            <entry></entry>
-           <entry><para>For input streams this is time when the first data
+           <entry><para>For capture streams this is time when the first data
            byte was captured, as returned by the
            <function>clock_gettime()</function> function for the relevant
            clock id; see <constant>V4L2_BUF_FLAG_TIMESTAMP_*</constant> in
@@ -866,7 +866,7 @@ must set this to 0.</entry>
            <entry></entry>
            <entry>The number of bytes occupied by data in the plane
              (its payload). Drivers must set this field when <structfield>type</structfield>
-             refers to an input stream, applications when it refers to an output stream.
+             refers to a capture stream, applications when it refers to an output stream.
              If the application sets this to 0 for an output stream, then
              <structfield>bytesused</structfield> will be set to the size of the
              plane (see the <structfield>length</structfield> field of this struct)
@@ -919,7 +919,7 @@ must set this to 0.</entry>
            <entry></entry>
            <entry>Offset in bytes to video data in the plane.
              Drivers must set this field when <structfield>type</structfield>
-             refers to an input stream, applications when it refers to an output stream.
+             refers to a capture stream, applications when it refers to an output stream.
              Note that data_offset is included in <structfield>bytesused</structfield>.
              So the size of the image in the plane is
              <structfield>bytesused</structfield>-<structfield>data_offset</structfield> at
index 7e61643358de034df628a0106e84e1e222315566..42e626d6c936234ad469b5b51dfef401b232d3d3 100644 (file)
@@ -151,6 +151,16 @@ Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab,
 structs, ioctls) must be noted in more detail in the history chapter
 (compat.xml), along with the possible impact on existing drivers and
 applications. -->
+      <revision>
+       <revnumber>4.5</revnumber>
+       <date>2015-10-29</date>
+       <authorinitials>rr</authorinitials>
+       <revremark>Extend vidioc-g-ext-ctrls;. Replace ctrl_class with a new
+union with ctrl_class and which. Which is used to select the current value of
+the control or the default value.
+       </revremark>
+      </revision>
+
       <revision>
        <revnumber>4.4</revnumber>
        <date>2015-05-26</date>
index 8ffe74f84af1f40209cf028e0a217e0b81dc3bb5..d81fa0d4016b15208135babd76175da8982342db 100644 (file)
@@ -58,7 +58,7 @@
     <para>This ioctl is used to create buffers for <link linkend="mmap">memory
 mapped</link> or <link linkend="userp">user pointer</link> or <link
 linkend="dmabuf">DMA buffer</link> I/O. It can be used as an alternative or in
-addition to the <constant>VIDIOC_REQBUFS</constant> ioctl, when a tighter
+addition to the &VIDIOC-REQBUFS; ioctl, when a tighter
 control over buffers is required. This ioctl can be called multiple times to
 create buffers of different sizes.</para>
 
@@ -71,30 +71,28 @@ zeroed.</para>
 
     <para>The <structfield>format</structfield> field specifies the image format
 that the buffers must be able to handle. The application has to fill in this
-&v4l2-format;. Usually this will be done using the
-<constant>VIDIOC_TRY_FMT</constant> or <constant>VIDIOC_G_FMT</constant> ioctl()
-to ensure that the requested format is supported by the driver. Unsupported
-formats will result in an error.</para>
+&v4l2-format;. Usually this will be done using the &VIDIOC-TRY-FMT; or &VIDIOC-G-FMT; ioctls
+to ensure that the requested format is supported by the driver.
+Based on the format's <structfield>type</structfield> field the requested buffer
+size (for single-planar) or plane sizes (for multi-planar formats) will be
+used for the allocated buffers. The driver may return an error if the size(s)
+are not supported by the hardware (usually because they are too small).</para>
 
     <para>The buffers created by this ioctl will have as minimum size the size
-defined by the <structfield>format.pix.sizeimage</structfield> field. If the
+defined by the <structfield>format.pix.sizeimage</structfield> field (or the
+corresponding fields for other format types). Usually if the
 <structfield>format.pix.sizeimage</structfield> field is less than the minimum
-required for the given format, then <structfield>sizeimage</structfield> will be
-increased by the driver to that minimum to allocate the buffers. If it is
-larger, then the value will be used as-is. The same applies to the
-<structfield>sizeimage</structfield> field of the
-<structname>v4l2_plane_pix_format</structname> structure in the case of
-multiplanar formats.</para>
+required for the given format, then an error will be returned since drivers will
+typically not allow this. If it is larger, then the value will be used as-is.
+In other words, the driver may reject the requested size, but if it is accepted
+the driver will use it unchanged.</para>
 
     <para>When the ioctl is called with a pointer to this structure the driver
 will attempt to allocate up to the requested number of buffers and store the
 actual number allocated and the starting index in the
 <structfield>count</structfield> and the <structfield>index</structfield> fields
 respectively. On return <structfield>count</structfield> can be smaller than
-the number requested. The driver may also increase buffer sizes if required,
-however, it will not update <structfield>sizeimage</structfield> field values.
-The user has to use <constant>VIDIOC_QUERYBUF</constant> to retrieve that
-information.</para>
+the number requested.</para>
 
     <table pgwide="1" frame="none" id="v4l2-create-buffers">
       <title>struct <structname>v4l2_create_buffers</structname></title>
index 4c4603c135fe2b6843e82b542fd4e94a11cfbdfb..f14a3bb1afaa6fdd2b9eff83546edfdc7325a723 100644 (file)
@@ -99,7 +99,7 @@ if the driver supports writing registers to the device.</para>
     <para>We recommended the <application>v4l2-dbg</application>
 utility over calling this ioctl directly. It is available from the
 LinuxTV v4l-dvb repository; see <ulink
-url="http://linuxtv.org/repo/">http://linuxtv.org/repo/</ulink> for
+url="https://linuxtv.org/repo/">https://linuxtv.org/repo/</ulink> for
 access instructions.</para>
 
     <!-- Note for convenience vidioc-dbg-g-register.sgml
index 3d038e75d12bd1fb0bba6084371b2aaa3aa72524..5877f68a5820f1bbf4d899600bc5777abcf684bb 100644 (file)
@@ -117,7 +117,7 @@ However when a driver supports these ioctls it must also support
     <para>We recommended the <application>v4l2-dbg</application>
 utility over calling these ioctls directly. It is available from the
 LinuxTV v4l-dvb repository; see <ulink
-url="http://linuxtv.org/repo/">http://linuxtv.org/repo/</ulink> for
+url="https://linuxtv.org/repo/">https://linuxtv.org/repo/</ulink> for
 access instructions.</para>
 
     <!-- Note for convenience vidioc-dbg-g-chip-info.sgml
index 8065099401d16fb34a12ce6156592f2a601f3ce0..f18454e91752e885614b9d26f9daa7abe05bca1d 100644 (file)
@@ -198,7 +198,7 @@ video4linux-list@redhat.com on 17 Oct 2002
 <constant>V4L2_STD_ATSC_16_VSB</constant> are U.S. terrestrial digital
 TV standards. Presently the V4L2 API does not support digital TV. See
 also the Linux DVB API at <ulink
-url="http://linuxtv.org">http://linuxtv.org</ulink>.</para>
+url="https://linuxtv.org">https://linuxtv.org</ulink>.</para>
 <para><programlisting>
 #define V4L2_STD_PAL_BG         (V4L2_STD_PAL_B         |\
                                 V4L2_STD_PAL_B1        |\
index 842536aae8b4978153baf5058219a9007c5be0a7..eb82f7e7d06b26b2906048e60edabbd8a7afdd69 100644 (file)
@@ -61,7 +61,7 @@ must belong to the same control class.</para>
 
     <para>Applications must always fill in the
 <structfield>count</structfield>,
-<structfield>ctrl_class</structfield>,
+<structfield>which</structfield>,
 <structfield>controls</structfield> and
 <structfield>reserved</structfield> fields of &v4l2-ext-controls;, and
 initialize the &v4l2-ext-control; array pointed to by the
@@ -109,7 +109,7 @@ the driver whether wrong values are automatically adjusted to a valid
 value or if an error is returned.</para>
 
     <para>When the <structfield>id</structfield> or
-<structfield>ctrl_class</structfield> is invalid drivers return an
+<structfield>which</structfield> is invalid drivers return an
 &EINVAL;. When the value is out of bounds drivers can choose to take
 the closest valid value or return an &ERANGE;, whatever seems more
 appropriate. In the first case the new value is set in
@@ -223,7 +223,12 @@ Valid if <constant>V4L2_CTRL_FLAG_HAS_PAYLOAD</constant> is set for this control
       <tgroup cols="3">
        &cs-str;
        <tbody valign="top">
+        <row>
+           <entry>union</entry>
+           <entry>(anonymous)</entry>
+         </row>
          <row>
+           <entry></entry>
            <entry>__u32</entry>
            <entry><structfield>ctrl_class</structfield></entry>
            <entry>The control class to which all controls belong, see
@@ -233,6 +238,23 @@ belong to any control class. Whether drivers support this can be tested by setti
 <structfield>ctrl_class</structfield> to 0 and calling <constant>VIDIOC_TRY_EXT_CTRLS</constant>
 with a <structfield>count</structfield> of 0. If that succeeds, then the driver
 supports this feature.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>which</structfield></entry>
+           <entry><para>Which value of the control to get/set/try. <constant>V4L2_CTRL_WHICH_CUR_VAL</constant>
+will return the current value of the control and <constant>V4L2_CTRL_WHICH_DEF_VAL</constant> will
+return the default value of the control. Please note that you can only get the default value of the
+control, you cannot set or try it.</para>
+<para>For backwards compatibility you can also use a control class here (see
+<xref linkend="ctrl-class" />). In that case all controls have to belong to that
+control class. This usage is deprecated, instead just use <constant>V4L2_CTRL_WHICH_CUR_VAL</constant>.
+There are some very old drivers that do not yet support <constant>V4L2_CTRL_WHICH_CUR_VAL</constant>
+and that require a control class here. You can test for such drivers by setting ctrl_class to
+<constant>V4L2_CTRL_WHICH_CUR_VAL</constant> and calling VIDIOC_TRY_EXT_CTRLS with a count of 0.
+If that fails, then the driver does not support <constant>V4L2_CTRL_WHICH_CUR_VAL</constant>.</para>
+</entry>
          </row>
          <row>
            <entry>__u32</entry>
@@ -390,7 +412,7 @@ These controls are described in <xref linkend="rf-tuner-controls" />.</entry>
        <listitem>
          <para>The &v4l2-ext-control; <structfield>id</structfield>
 is invalid, the &v4l2-ext-controls;
-<structfield>ctrl_class</structfield> is invalid, or the &v4l2-ext-control;
+<structfield>which</structfield> is invalid, or the &v4l2-ext-control;
 <structfield>value</structfield> was inappropriate (e.g. the given menu
 index is not supported by the driver). This error code is
 also returned by the <constant>VIDIOC_S_EXT_CTRLS</constant> and
index 92037033f5eb3d14500129c9892514ce9c270469..7b77e0f7b87d25a024fce19ccace4f347833ee6d 100644 (file)
 <!ENTITY cs-def                 "<colspec colname='c1' colwidth='3*' /><colspec colname='c2' colwidth='1*' /><colspec colname='c3' colwidth='4*' /><spanspec spanname='hspan' namest='c1' nameend='c3' />">
 
 <!-- Video for Linux mailing list address. -->
-<!ENTITY v4l-ml                 "<ulink url='http://www.linuxtv.org/lists.php'>http://www.linuxtv.org/lists.php</ulink>">
+<!ENTITY v4l-ml                 "<ulink url='https://linuxtv.org/lists.php'>https://linuxtv.org/lists.php</ulink>">
 
 <!-- LinuxTV v4l-dvb repository. -->
-<!ENTITY v4l-dvb               "<ulink url='http://linuxtv.org/repo/'>http://linuxtv.org/repo/</ulink>">
+<!ENTITY v4l-dvb               "<ulink url='https://linuxtv.org/repo/'>https://linuxtv.org/repo/</ulink>">
 <!ENTITY dash-ent-8             "<entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry>">
 <!ENTITY dash-ent-10            "<entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry>">
 <!ENTITY dash-ent-12            "<entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry>">
@@ -91,7 +91,7 @@
              components, like mixers, PCM capture, PCM playback, etc, which
              are controlled via ALSA API.</para>
        <para>For additional information and for the latest development code,
-               see: <ulink url="http://linuxtv.org">http://linuxtv.org</ulink>.</para>
+               see: <ulink url="https://linuxtv.org">https://linuxtv.org</ulink>.</para>
        <para>For discussing improvements, reporting troubles, sending new drivers, etc, please mail to: <ulink url="http://vger.kernel.org/vger-lists.html#linux-media">Linux Media Mailing List (LMML).</ulink>.</para>
 </preface>
 
diff --git a/Documentation/RCU/Design/Requirements/2013-08-is-it-dead.png b/Documentation/RCU/Design/Requirements/2013-08-is-it-dead.png
new file mode 100644 (file)
index 0000000..7496a55
Binary files /dev/null and b/Documentation/RCU/Design/Requirements/2013-08-is-it-dead.png differ
diff --git a/Documentation/RCU/Design/Requirements/GPpartitionReaders1.svg b/Documentation/RCU/Design/Requirements/GPpartitionReaders1.svg
new file mode 100644 (file)
index 0000000..4b4014f
--- /dev/null
@@ -0,0 +1,374 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="447.99197"
+   height="428.19299"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="GPpartitionReaders1.svg">
+  <defs
+     id="defs4">
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend"
+       style="overflow:visible">
+      <path
+         id="path3792"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lstart"
+       style="overflow:visible">
+      <path
+         id="path3789"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.6184291"
+     inkscape:cx="223.99599"
+     inkscape:cy="214.0965"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="979"
+     inkscape:window-height="836"
+     inkscape:window-x="571"
+     inkscape:window-y="335"
+     inkscape:window-maximized="0"
+     fit-margin-top="5"
+     fit-margin-left="5"
+     fit-margin-right="5"
+     fit-margin-bottom="5" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-28.441125,-185.60612)">
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot2985"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"><flowRegion
+         id="flowRegion2987"><rect
+           id="rect2989"
+           width="82.85714"
+           height="11.428572"
+           x="240"
+           y="492.36218" /></flowRegion><flowPara
+         id="flowPara2991"></flowPara></flowRoot>    <g
+       id="g4433"
+       transform="translate(2,0)">
+      <text
+         sodipodi:linespacing="125%"
+         id="text2993"
+         y="-261.66608"
+         x="412.12299"
+         style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+         xml:space="preserve"
+         transform="matrix(0,1,-1,0,0,0)"><tspan
+           y="-261.66608"
+           x="412.12299"
+           id="tspan2995"
+           sodipodi:role="line">synchronize_rcu()</tspan></text>
+      <g
+         id="g4417"
+         transform="matrix(0,1,-1,0,730.90257,222.4928)">
+        <path
+           style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Lstart);marker-end:url(#Arrow2Lend)"
+           d="m 97.580736,477.4048 183.140664,0"
+           id="path2997"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+        <path
+           style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 96.752718,465.38398 0,22.62742"
+           id="path4397"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+        <path
+           style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 281.54942,465.38397 0,22.62742"
+           id="path4397-5"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+      </g>
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="112.04738"
+       y="268.18076"
+       id="text4429"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4431"
+         x="112.04738"
+         y="268.18076">WRITE_ONCE(a, 1);</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="112.04738"
+       y="439.13766"
+       id="text4441"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4443"
+         x="112.04738"
+         y="439.13766">WRITE_ONCE(b, 1);</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="255.60869"
+       y="309.29346"
+       id="text4445"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4447"
+         x="255.60869"
+         y="309.29346">r1 = READ_ONCE(a);</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="255.14423"
+       y="520.61786"
+       id="text4449"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4451"
+         x="255.14423"
+         y="520.61786">WRITE_ONCE(c, 1);</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="396.10254"
+       y="384.71124"
+       id="text4453"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4455"
+         x="396.10254"
+         y="384.71124">r2 = READ_ONCE(b);</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="396.10254"
+       y="582.13617"
+       id="text4457"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4459"
+         x="396.10254"
+         y="582.13617">r3 = READ_ONCE(c);</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="112.08231"
+       y="213.91006"
+       id="text4461"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4463"
+         x="112.08231"
+         y="213.91006">thread0()</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="252.34512"
+       y="213.91006"
+       id="text4461-6"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4463-0"
+         x="252.34512"
+         y="213.91006">thread1()</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="396.42557"
+       y="213.91006"
+       id="text4461-2"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4463-2"
+         x="396.42557"
+         y="213.91006">thread2()</tspan></text>
+    <rect
+       style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       id="rect4495"
+       width="436.28488"
+       height="416.4859"
+       x="34.648232"
+       y="191.10612" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       d="m 183.14066,191.10612 0,417.193 -0.70711,0"
+       id="path4497"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       d="m 325.13867,191.10612 0,417.193 -0.70711,0"
+       id="path4497-5"
+       inkscape:connector-curvature="0" />
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="111.75929"
+       y="251.53981"
+       id="text4429-8"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4431-9"
+         x="111.75929"
+         y="251.53981">rcu_read_lock();</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="396.10254"
+       y="367.91556"
+       id="text4429-8-9"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4431-9-4"
+         x="396.10254"
+         y="367.91556">rcu_read_lock();</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="396.10254"
+       y="597.40289"
+       id="text4429-8-9-3"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4431-9-4-4"
+         x="396.10254"
+         y="597.40289">rcu_read_unlock();</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="111.75929"
+       y="453.15311"
+       id="text4429-8-9-3-1"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4431-9-4-4-6"
+         x="111.75929"
+         y="453.15311">rcu_read_unlock();</tspan></text>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 33.941125,227.87568 436.284885,0 0,0.7071"
+       id="path4608"
+       inkscape:connector-curvature="0" />
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="394.94427"
+       y="345.66351"
+       id="text4648"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4650"
+         x="394.94427"
+         y="345.66351">QS</tspan></text>
+    <path
+       sodipodi:type="arc"
+       style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       id="path4652"
+       sodipodi:cx="358.85669"
+       sodipodi:cy="142.87541"
+       sodipodi:rx="10.960155"
+       sodipodi:ry="10.253048"
+       d="m 358.86939,132.62237 a 10.960155,10.253048 0 1 1 -0.0228,0"
+       transform="translate(36.441125,199.60612)"
+       sodipodi:start="4.7135481"
+       sodipodi:end="10.994651"
+       sodipodi:open="true" />
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="112.11968"
+       y="475.77856"
+       id="text4648-4"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4650-4"
+         x="112.11968"
+         y="475.77856">QS</tspan></text>
+    <path
+       sodipodi:type="arc"
+       style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       id="path4652-7"
+       sodipodi:cx="358.85669"
+       sodipodi:cy="142.87541"
+       sodipodi:rx="10.960155"
+       sodipodi:ry="10.253048"
+       d="m 358.86939,132.62237 a 10.960155,10.253048 0 1 1 -0.0228,0"
+       transform="translate(-246.38346,329.72117)"
+       sodipodi:start="4.7135481"
+       sodipodi:end="10.994651"
+       sodipodi:open="true" />
+    <path
+       sodipodi:type="arc"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       id="path4652-7-7"
+       sodipodi:cx="358.85669"
+       sodipodi:cy="142.87541"
+       sodipodi:rx="10.960155"
+       sodipodi:ry="10.253048"
+       d="m 358.86939,132.62237 a 10.960155,10.253048 0 1 1 -0.0228,0"
+       transform="translate(-103.65246,202.90878)"
+       sodipodi:start="4.7135481"
+       sodipodi:end="10.994651"
+       sodipodi:open="true" />
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="254.85066"
+       y="348.96619"
+       id="text4648-4-3"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4650-4-5"
+         x="254.85066"
+         y="348.96619">QS</tspan></text>
+  </g>
+</svg>
diff --git a/Documentation/RCU/Design/Requirements/RCUApplicability.svg b/Documentation/RCU/Design/Requirements/RCUApplicability.svg
new file mode 100644 (file)
index 0000000..ebcbeee
--- /dev/null
@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Creator: fig2dev Version 3.2 Patchlevel 5d -->
+
+<!-- CreationDate: Tue Mar  4 18:34:25 2014 -->
+
+<!-- Magnification: 3.000 -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="1089.1382"
+   height="668.21368"
+   viewBox="-2121 -36 14554.634 8876.4061"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="RCUApplicability.svg">
+  <metadata
+     id="metadata40">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs38" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="849"
+     inkscape:window-height="639"
+     id="namedview36"
+     showgrid="false"
+     inkscape:zoom="0.51326165"
+     inkscape:cx="544.56912"
+     inkscape:cy="334.10686"
+     inkscape:window-x="149"
+     inkscape:window-y="448"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="g4"
+     fit-margin-top="5"
+     fit-margin-left="5"
+     fit-margin-right="5"
+     fit-margin-bottom="5" />
+  <g
+     style="fill:none;stroke-width:0.025in"
+     id="g4"
+     transform="translate(-2043.6828,14.791398)">
+    <!-- Line: box -->
+    <rect
+       x="0"
+       y="0"
+       width="14400"
+       height="8775"
+       rx="0"
+       style="fill:#ffa1a1;stroke:#000000;stroke-width:21;stroke-linecap:butt;stroke-linejoin:miter"
+       id="rect6" />
+    <!-- Line: box -->
+    <rect
+       x="1350"
+       y="0"
+       width="11700"
+       height="6075"
+       rx="0"
+       style="fill:#ffff00;stroke:#000000;stroke-width:21;stroke-linecap:butt;stroke-linejoin:miter"
+       id="rect8" />
+    <!-- Line: box -->
+    <rect
+       x="2700"
+       y="0"
+       width="9000"
+       height="4275"
+       rx="0"
+       style="fill:#00ff00;stroke:#000000;stroke-width:21;stroke-linecap:butt;stroke-linejoin:miter"
+       id="rect10" />
+    <!-- Line: box -->
+    <rect
+       x="4050"
+       y="0"
+       width="6300"
+       height="2475"
+       rx="0"
+       style="fill:#87cfff;stroke:#000000;stroke-width:21;stroke-linecap:butt;stroke-linejoin:miter"
+       id="rect12" />
+    <!-- Text -->
+    <text
+       xml:space="preserve"
+       x="7200"
+       y="900"
+       font-style="normal"
+       font-weight="normal"
+       font-size="324"
+       id="text14"
+       sodipodi:linespacing="125%"
+       style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"><tspan
+         style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+         id="tspan3017">Read-Mostly, Stale &amp;</tspan></text>
+    <!-- Text -->
+    <text
+       xml:space="preserve"
+       x="7200"
+       y="1350"
+       font-style="normal"
+       font-weight="normal"
+       font-size="324"
+       id="text16"
+       sodipodi:linespacing="125%"
+       style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"><tspan
+         style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+         id="tspan3019">Inconsistent Data OK</tspan></text>
+    <!-- Text -->
+    <text
+       xml:space="preserve"
+       x="7200"
+       y="1800"
+       font-style="normal"
+       font-weight="normal"
+       font-size="324"
+       id="text18"
+       sodipodi:linespacing="125%"
+       style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"><tspan
+         style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+         id="tspan3021">(RCU Works Great!!!)</tspan></text>
+    <!-- Text -->
+    <text
+       xml:space="preserve"
+       x="7200"
+       y="3825"
+       font-style="normal"
+       font-weight="normal"
+       font-size="324"
+       id="text20"
+       sodipodi:linespacing="125%"
+       style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"><tspan
+         style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+         id="tspan3023">(RCU Works Well)</tspan></text>
+    <!-- Text -->
+    <text
+       xml:space="preserve"
+       x="7200"
+       y="3375"
+       font-style="normal"
+       font-weight="normal"
+       font-size="324"
+       id="text22"
+       sodipodi:linespacing="125%"
+       style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"><tspan
+         style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+         id="tspan3025">Read-Mostly, Need Consistent Data</tspan></text>
+    <!-- Text -->
+    <text
+       xml:space="preserve"
+       x="7200"
+       y="5175"
+       font-style="normal"
+       font-weight="normal"
+       font-size="324"
+       id="text24"
+       sodipodi:linespacing="125%"
+       style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"><tspan
+         style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+         id="tspan3027">Read-Write, Need Consistent Data</tspan></text>
+    <!-- Text -->
+    <text
+       xml:space="preserve"
+       x="7200"
+       y="6975"
+       font-style="normal"
+       font-weight="normal"
+       font-size="324"
+       id="text26"
+       style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+       sodipodi:linespacing="125%">Update-Mostly, Need Consistent Data</text>
+    <!-- Text -->
+    <text
+       xml:space="preserve"
+       x="7200"
+       y="5625"
+       font-style="normal"
+       font-weight="normal"
+       font-size="324"
+       id="text28"
+       sodipodi:linespacing="125%"
+       style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"><tspan
+         style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+         id="tspan3029">(RCU Might Be OK...)</tspan></text>
+    <!-- Text -->
+    <text
+       xml:space="preserve"
+       x="7200"
+       y="7875"
+       font-style="normal"
+       font-weight="normal"
+       font-size="324"
+       id="text30"
+       style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+       sodipodi:linespacing="125%">(1) Provide Existence Guarantees For Update-Friendly Mechanisms</text>
+    <!-- Text -->
+    <text
+       xml:space="preserve"
+       x="7200"
+       y="8325"
+       font-style="normal"
+       font-weight="normal"
+       font-size="324"
+       id="text32"
+       style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+       sodipodi:linespacing="125%">(2) Provide Wait-Free Read-Side Primitives for Real-Time Use)</text>
+    <!-- Text -->
+    <text
+       xml:space="preserve"
+       x="7200"
+       y="7425"
+       font-style="normal"
+       font-weight="normal"
+       font-size="324"
+       id="text34"
+       style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+       sodipodi:linespacing="125%">(RCU is Very Unlikely to be the Right Tool For The Job, But it Can:</text>
+  </g>
+</svg>
diff --git a/Documentation/RCU/Design/Requirements/ReadersPartitionGP1.svg b/Documentation/RCU/Design/Requirements/ReadersPartitionGP1.svg
new file mode 100644 (file)
index 0000000..48cd162
--- /dev/null
@@ -0,0 +1,639 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="735.25"
+   height="516.21875"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="ReadersPartitionGP1.svg">
+  <defs
+     id="defs4">
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend"
+       style="overflow:visible">
+      <path
+         id="path3792"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lstart"
+       style="overflow:visible">
+      <path
+         id="path3789"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lstart-4"
+       style="overflow:visible">
+      <path
+         id="path3789-9"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-4"
+       style="overflow:visible">
+      <path
+         id="path3792-4"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.3670394"
+     inkscape:cx="367.26465"
+     inkscape:cy="258.46182"
+     inkscape:document-units="px"
+     inkscape:current-layer="g4433-6"
+     showgrid="false"
+     inkscape:window-width="1351"
+     inkscape:window-height="836"
+     inkscape:window-x="438"
+     inkscape:window-y="335"
+     inkscape:window-maximized="0"
+     fit-margin-top="5"
+     fit-margin-left="5"
+     fit-margin-right="5"
+     fit-margin-bottom="5" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-29.15625,-185.59375)">
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot2985"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"><flowRegion
+         id="flowRegion2987"><rect
+           id="rect2989"
+           width="82.85714"
+           height="11.428572"
+           x="240"
+           y="492.36218" /></flowRegion><flowPara
+         id="flowPara2991" /></flowRoot>    <g
+       id="g4433"
+       transform="translate(2,-12)">
+      <text
+         sodipodi:linespacing="125%"
+         id="text2993"
+         y="-261.66608"
+         x="436.12299"
+         style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+         xml:space="preserve"
+         transform="matrix(0,1,-1,0,0,0)"><tspan
+           y="-261.66608"
+           x="436.12299"
+           id="tspan2995"
+           sodipodi:role="line">synchronize_rcu()</tspan></text>
+      <g
+         id="g4417"
+         transform="matrix(0,1,-1,0,730.90257,222.4928)">
+        <path
+           style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Lstart);marker-end:url(#Arrow2Lend)"
+           d="M 97.580736,477.4048 327.57913,476.09759"
+           id="path2997"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+        <path
+           style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 96.752718,465.38398 0,22.62742"
+           id="path4397"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+        <path
+           style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 328.40703,465.38397 0,22.62742"
+           id="path4397-5"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+      </g>
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="112.04738"
+       y="268.18076"
+       id="text4429"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4431"
+         x="112.04738"
+         y="268.18076">WRITE_ONCE(a, 1);</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="112.04738"
+       y="487.13766"
+       id="text4441"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4443"
+         x="112.04738"
+         y="487.13766">WRITE_ONCE(b, 1);</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="255.60869"
+       y="297.29346"
+       id="text4445"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4447"
+         x="255.60869"
+         y="297.29346">r1 = READ_ONCE(a);</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="255.14423"
+       y="554.61786"
+       id="text4449"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4451"
+         x="255.14423"
+         y="554.61786">WRITE_ONCE(c, 1);</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="396.10254"
+       y="370.71124"
+       id="text4453"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4455"
+         x="396.10254"
+         y="370.71124">WRITE_ONCE(d, 1);</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="396.10254"
+       y="572.13617"
+       id="text4457"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4459"
+         x="396.10254"
+         y="572.13617">r2 = READ_ONCE(c);</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="112.08231"
+       y="213.91006"
+       id="text4461"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4463"
+         x="112.08231"
+         y="213.91006">thread0()</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="252.34512"
+       y="213.91006"
+       id="text4461-6"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4463-0"
+         x="252.34512"
+         y="213.91006">thread1()</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="396.42557"
+       y="213.91006"
+       id="text4461-2"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4463-2"
+         x="396.42557"
+         y="213.91006">thread2()</tspan></text>
+    <rect
+       style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       id="rect4495"
+       width="724.25244"
+       height="505.21201"
+       x="34.648232"
+       y="191.10612" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       d="m 183.14066,191.10612 0,504.24243"
+       id="path4497"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       d="m 325.13867,191.10612 0,504.24243"
+       id="path4497-5"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="111.75929"
+       y="251.53981"
+       id="text4429-8"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4431-9"
+         x="111.75929"
+         y="251.53981">rcu_read_lock();</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="396.10254"
+       y="353.91556"
+       id="text4429-8-9"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4431-9-4"
+         x="396.10254"
+         y="353.91556">rcu_read_lock();</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="396.10254"
+       y="587.40289"
+       id="text4429-8-9-3"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4431-9-4-4"
+         x="396.10254"
+         y="587.40289">rcu_read_unlock();</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="111.75929"
+       y="501.15311"
+       id="text4429-8-9-3-1"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4431-9-4-4-6"
+         x="111.75929"
+         y="501.15311">rcu_read_unlock();</tspan></text>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 33.941125,227.87568 724.941765,0"
+       id="path4608"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="394.94427"
+       y="331.66351"
+       id="text4648"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4650"
+         x="394.94427"
+         y="331.66351">QS</tspan></text>
+    <path
+       sodipodi:type="arc"
+       style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       id="path4652"
+       sodipodi:cx="358.85669"
+       sodipodi:cy="142.87541"
+       sodipodi:rx="10.960155"
+       sodipodi:ry="10.253048"
+       d="m 358.86939,132.62237 a 10.960155,10.253048 0 1 1 -0.0228,0"
+       transform="translate(36.441125,185.60612)"
+       sodipodi:start="4.7135481"
+       sodipodi:end="10.994651"
+       sodipodi:open="true" />
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="112.11968"
+       y="523.77856"
+       id="text4648-4"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4650-4"
+         x="112.11968"
+         y="523.77856">QS</tspan></text>
+    <path
+       sodipodi:type="arc"
+       style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       id="path4652-7"
+       sodipodi:cx="358.85669"
+       sodipodi:cy="142.87541"
+       sodipodi:rx="10.960155"
+       sodipodi:ry="10.253048"
+       d="m 358.86939,132.62237 a 10.960155,10.253048 0 1 1 -0.0228,0"
+       transform="translate(-246.38346,377.72117)"
+       sodipodi:start="4.7135481"
+       sodipodi:end="10.994651"
+       sodipodi:open="true" />
+    <path
+       sodipodi:type="arc"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       id="path4652-7-7"
+       sodipodi:cx="358.85669"
+       sodipodi:cy="142.87541"
+       sodipodi:rx="10.960155"
+       sodipodi:ry="10.253048"
+       d="m 358.86939,132.62237 a 10.960155,10.253048 0 1 1 -0.0228,0"
+       transform="translate(-103.65246,190.90878)"
+       sodipodi:start="4.7135481"
+       sodipodi:end="10.994651"
+       sodipodi:open="true" />
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="254.85066"
+       y="336.96619"
+       id="text4648-4-3"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4650-4-5"
+         x="254.85066"
+         y="336.96619">QS</tspan></text>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       d="m 470.93311,190.39903 0,504.24243"
+       id="path4497-5-6"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       d="m 616.22755,190.38323 0,504.24243"
+       id="path4497-5-2"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <g
+       id="g4433-6"
+       transform="translate(288.0964,78.32827)">
+      <text
+         sodipodi:linespacing="125%"
+         id="text2993-7"
+         y="-261.66608"
+         x="440.12299"
+         style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+         xml:space="preserve"
+         transform="matrix(0,1,-1,0,0,0)"><tspan
+           y="-261.66608"
+           x="440.12299"
+           id="tspan2995-1"
+           sodipodi:role="line">synchronize_rcu()</tspan></text>
+      <g
+         id="g4417-1"
+         transform="matrix(0,1,-1,0,730.90257,222.4928)">
+        <path
+           style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Lstart);marker-end:url(#Arrow2Lend)"
+           d="M 97.580736,477.4048 328.5624,477.07246"
+           id="path2997-2"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+        <path
+           style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 96.752718,465.38398 0,22.62742"
+           id="path4397-3"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+        <path
+           style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 329.39039,465.38397 0,22.62742"
+           id="path4397-5-4"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+      </g>
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="541.70508"
+       y="387.6217"
+       id="text4445-0"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4447-5"
+         x="541.70508"
+         y="387.6217">r3 = READ_ONCE(d);</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="541.2406"
+       y="646.94611"
+       id="text4449-6"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4451-6"
+         x="541.2406"
+         y="646.94611">WRITE_ONCE(e, 1);</tspan></text>
+    <path
+       sodipodi:type="arc"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       id="path4652-7-7-5"
+       sodipodi:cx="358.85669"
+       sodipodi:cy="142.87541"
+       sodipodi:rx="10.960155"
+       sodipodi:ry="10.253048"
+       d="m 358.86939,132.62237 a 10.960155,10.253048 0 1 1 -0.0228,0"
+       transform="translate(182.44393,281.23704)"
+       sodipodi:start="4.7135481"
+       sodipodi:end="10.994651"
+       sodipodi:open="true" />
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="540.94702"
+       y="427.29443"
+       id="text4648-4-3-1"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4650-4-5-7"
+         x="540.94702"
+         y="427.29443">QS</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="686.27747"
+       y="461.83929"
+       id="text4453-7"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4455-1"
+         x="686.27747"
+         y="461.83929">r4 = READ_ONCE(b);</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="686.27747"
+       y="669.26422"
+       id="text4457-9"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4459-2"
+         x="686.27747"
+         y="669.26422">r5 = READ_ONCE(e);</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="686.27747"
+       y="445.04358"
+       id="text4429-8-9-33"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4431-9-4-2"
+         x="686.27747"
+         y="445.04358">rcu_read_lock();</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="686.27747"
+       y="684.53094"
+       id="text4429-8-9-3-8"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4431-9-4-4-5"
+         x="686.27747"
+         y="684.53094">rcu_read_unlock();</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="685.11914"
+       y="422.79153"
+       id="text4648-9"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4650-7"
+         x="685.11914"
+         y="422.79153">QS</tspan></text>
+    <path
+       sodipodi:type="arc"
+       style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       id="path4652-8"
+       sodipodi:cx="358.85669"
+       sodipodi:cy="142.87541"
+       sodipodi:rx="10.960155"
+       sodipodi:ry="10.253048"
+       d="m 358.86939,132.62237 a 10.960155,10.253048 0 1 1 -0.0228,0"
+       transform="translate(326.61602,276.73415)"
+       sodipodi:start="4.7135481"
+       sodipodi:end="10.994651"
+       sodipodi:open="true" />
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="397.85934"
+       y="609.59003"
+       id="text4648-5"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4650-77"
+         x="397.85934"
+         y="609.59003">QS</tspan></text>
+    <path
+       sodipodi:type="arc"
+       style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       id="path4652-80"
+       sodipodi:cx="358.85669"
+       sodipodi:cy="142.87541"
+       sodipodi:rx="10.960155"
+       sodipodi:ry="10.253048"
+       d="m 358.86939,132.62237 a 10.960155,10.253048 0 1 1 -0.0228,0"
+       transform="translate(39.356201,463.53264)"
+       sodipodi:start="4.7135481"
+       sodipodi:end="10.994651"
+       sodipodi:open="true" />
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="256.75986"
+       y="586.99133"
+       id="text4648-5-2"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4650-77-7"
+         x="256.75986"
+         y="586.99133">QS</tspan></text>
+    <path
+       sodipodi:type="arc"
+       style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       id="path4652-80-5"
+       sodipodi:cx="358.85669"
+       sodipodi:cy="142.87541"
+       sodipodi:rx="10.960155"
+       sodipodi:ry="10.253048"
+       d="m 358.86939,132.62237 a 10.960155,10.253048 0 1 1 -0.0228,0"
+       transform="translate(-101.74328,440.93395)"
+       sodipodi:start="4.7135481"
+       sodipodi:end="10.994651"
+       sodipodi:open="true" />
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="546.22791"
+       y="213.91006"
+       id="text4461-2-5"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4463-2-6"
+         x="546.22791"
+         y="213.91006">thread3()</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+       x="684.00067"
+       y="213.91006"
+       id="text4461-2-1"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4463-2-0"
+         x="684.00067"
+         y="213.91006">thread4()</tspan></text>
+  </g>
+</svg>
diff --git a/Documentation/RCU/Design/Requirements/Requirements.html b/Documentation/RCU/Design/Requirements/Requirements.html
new file mode 100644 (file)
index 0000000..a725f99
--- /dev/null
@@ -0,0 +1,2897 @@
+<!-- DO NOT HAND EDIT. -->
+<!-- Instead, edit Documentation/RCU/Design/Requirements/Requirements.htmlx and run 'sh htmlqqz.sh Documentation/RCU/Design/Requirements/Requirements' -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+        "http://www.w3.org/TR/html4/loose.dtd">
+        <html>
+        <head><title>A Tour Through RCU's Requirements [LWN.net]</title>
+        <meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+
+<h1>A Tour Through RCU's Requirements</h1>
+
+<p>Copyright IBM Corporation, 2015</p>
+<p>Author: Paul E.&nbsp;McKenney</p>
+<p><i>The initial version of this document appeared in the
+<a href="https://lwn.net/">LWN</a> articles
+<a href="https://lwn.net/Articles/652156/">here</a>,
+<a href="https://lwn.net/Articles/652677/">here</a>, and
+<a href="https://lwn.net/Articles/653326/">here</a>.</i></p>
+
+<h2>Introduction</h2>
+
+<p>
+Read-copy update (RCU) is a synchronization mechanism that is often
+used as a replacement for reader-writer locking.
+RCU is unusual in that updaters do not block readers,
+which means that RCU's read-side primitives can be exceedingly fast
+and scalable.
+In addition, updaters can make useful forward progress concurrently
+with readers.
+However, all this concurrency between RCU readers and updaters does raise
+the question of exactly what RCU readers are doing, which in turn
+raises the question of exactly what RCU's requirements are.
+
+<p>
+This document therefore summarizes RCU's requirements, and can be thought
+of as an informal, high-level specification for RCU.
+It is important to understand that RCU's specification is primarily
+empirical in nature;
+in fact, I learned about many of these requirements the hard way.
+This situation might cause some consternation, however, not only
+has this learning process been a lot of fun, but it has also been
+a great privilege to work with so many people willing to apply
+technologies in interesting new ways.
+
+<p>
+All that aside, here are the categories of currently known RCU requirements:
+</p>
+
+<ol>
+<li>   <a href="#Fundamental Requirements">
+       Fundamental Requirements</a>
+<li>   <a href="#Fundamental Non-Requirements">Fundamental Non-Requirements</a>
+<li>   <a href="#Parallelism Facts of Life">
+       Parallelism Facts of Life</a>
+<li>   <a href="#Quality-of-Implementation Requirements">
+       Quality-of-Implementation Requirements</a>
+<li>   <a href="#Linux Kernel Complications">
+       Linux Kernel Complications</a>
+<li>   <a href="#Software-Engineering Requirements">
+       Software-Engineering Requirements</a>
+<li>   <a href="#Other RCU Flavors">
+       Other RCU Flavors</a>
+<li>   <a href="#Possible Future Changes">
+       Possible Future Changes</a>
+</ol>
+
+<p>
+This is followed by a <a href="#Summary">summary</a>,
+which is in turn followed by the inevitable
+<a href="#Answers to Quick Quizzes">answers to the quick quizzes</a>.
+
+<h2><a name="Fundamental Requirements">Fundamental Requirements</a></h2>
+
+<p>
+RCU's fundamental requirements are the closest thing RCU has to hard
+mathematical requirements.
+These are:
+
+<ol>
+<li>   <a href="#Grace-Period Guarantee">
+       Grace-Period Guarantee</a>
+<li>   <a href="#Publish-Subscribe Guarantee">
+       Publish-Subscribe Guarantee</a>
+<li>   <a href="#Memory-Barrier Guarantees">
+       Memory-Barrier Guarantees</a>
+<li>   <a href="#RCU Primitives Guaranteed to Execute Unconditionally">
+       RCU Primitives Guaranteed to Execute Unconditionally</a>
+<li>   <a href="#Guaranteed Read-to-Write Upgrade">
+       Guaranteed Read-to-Write Upgrade</a>
+</ol>
+
+<h3><a name="Grace-Period Guarantee">Grace-Period Guarantee</a></h3>
+
+<p>
+RCU's grace-period guarantee is unusual in being premeditated:
+Jack Slingwine and I had this guarantee firmly in mind when we started
+work on RCU (then called &ldquo;rclock&rdquo;) in the early 1990s.
+That said, the past two decades of experience with RCU have produced
+a much more detailed understanding of this guarantee.
+
+<p>
+RCU's grace-period guarantee allows updaters to wait for the completion
+of all pre-existing RCU read-side critical sections.
+An RCU read-side critical section
+begins with the marker <tt>rcu_read_lock()</tt> and ends with
+the marker <tt>rcu_read_unlock()</tt>.
+These markers may be nested, and RCU treats a nested set as one
+big RCU read-side critical section.
+Production-quality implementations of <tt>rcu_read_lock()</tt> and
+<tt>rcu_read_unlock()</tt> are extremely lightweight, and in
+fact have exactly zero overhead in Linux kernels built for production
+use with <tt>CONFIG_PREEMPT=n</tt>.
+
+<p>
+This guarantee allows ordering to be enforced with extremely low
+overhead to readers, for example:
+
+<blockquote>
+<pre>
+ 1 int x, y;
+ 2
+ 3 void thread0(void)
+ 4 {
+ 5   rcu_read_lock();
+ 6   r1 = READ_ONCE(x);
+ 7   r2 = READ_ONCE(y);
+ 8   rcu_read_unlock();
+ 9 }
+10
+11 void thread1(void)
+12 {
+13   WRITE_ONCE(x, 1);
+14   synchronize_rcu();
+15   WRITE_ONCE(y, 1);
+16 }
+</pre>
+</blockquote>
+
+<p>
+Because the <tt>synchronize_rcu()</tt> on line&nbsp;14 waits for
+all pre-existing readers, any instance of <tt>thread0()</tt> that
+loads a value of zero from <tt>x</tt> must complete before
+<tt>thread1()</tt> stores to <tt>y</tt>, so that instance must
+also load a value of zero from <tt>y</tt>.
+Similarly, any instance of <tt>thread0()</tt> that loads a value of
+one from <tt>y</tt> must have started after the
+<tt>synchronize_rcu()</tt> started, and must therefore also load
+a value of one from <tt>x</tt>.
+Therefore, the outcome:
+<blockquote>
+<pre>
+(r1 == 0 &amp;&amp; r2 == 1)
+</pre>
+</blockquote>
+cannot happen.
+
+<p><a name="Quick Quiz 1"><b>Quick Quiz 1</b>:</a>
+Wait a minute!
+You said that updaters can make useful forward progress concurrently
+with readers, but pre-existing readers will block
+<tt>synchronize_rcu()</tt>!!!
+Just who are you trying to fool???
+<br><a href="#qq1answer">Answer</a>
+
+<p>
+This scenario resembles one of the first uses of RCU in
+<a href="https://en.wikipedia.org/wiki/DYNIX">DYNIX/ptx</a>,
+which managed a distributed lock manager's transition into
+a state suitable for handling recovery from node failure,
+more or less as follows:
+
+<blockquote>
+<pre>
+ 1 #define STATE_NORMAL        0
+ 2 #define STATE_WANT_RECOVERY 1
+ 3 #define STATE_RECOVERING    2
+ 4 #define STATE_WANT_NORMAL   3
+ 5
+ 6 int state = STATE_NORMAL;
+ 7
+ 8 void do_something_dlm(void)
+ 9 {
+10   int state_snap;
+11
+12   rcu_read_lock();
+13   state_snap = READ_ONCE(state);
+14   if (state_snap == STATE_NORMAL)
+15     do_something();
+16   else
+17     do_something_carefully();
+18   rcu_read_unlock();
+19 }
+20
+21 void start_recovery(void)
+22 {
+23   WRITE_ONCE(state, STATE_WANT_RECOVERY);
+24   synchronize_rcu();
+25   WRITE_ONCE(state, STATE_RECOVERING);
+26   recovery();
+27   WRITE_ONCE(state, STATE_WANT_NORMAL);
+28   synchronize_rcu();
+29   WRITE_ONCE(state, STATE_NORMAL);
+30 }
+</pre>
+</blockquote>
+
+<p>
+The RCU read-side critical section in <tt>do_something_dlm()</tt>
+works with the <tt>synchronize_rcu()</tt> in <tt>start_recovery()</tt>
+to guarantee that <tt>do_something()</tt> never runs concurrently
+with <tt>recovery()</tt>, but with little or no synchronization
+overhead in <tt>do_something_dlm()</tt>.
+
+<p><a name="Quick Quiz 2"><b>Quick Quiz 2</b>:</a>
+Why is the <tt>synchronize_rcu()</tt> on line&nbsp;28 needed?
+<br><a href="#qq2answer">Answer</a>
+
+<p>
+In order to avoid fatal problems such as deadlocks,
+an RCU read-side critical section must not contain calls to
+<tt>synchronize_rcu()</tt>.
+Similarly, an RCU read-side critical section must not
+contain anything that waits, directly or indirectly, on completion of
+an invocation of <tt>synchronize_rcu()</tt>.
+
+<p>
+Although RCU's grace-period guarantee is useful in and of itself, with
+<a href="https://lwn.net/Articles/573497/">quite a few use cases</a>,
+it would be good to be able to use RCU to coordinate read-side
+access to linked data structures.
+For this, the grace-period guarantee is not sufficient, as can
+be seen in function <tt>add_gp_buggy()</tt> below.
+We will look at the reader's code later, but in the meantime, just think of
+the reader as locklessly picking up the <tt>gp</tt> pointer,
+and, if the value loaded is non-<tt>NULL</tt>, locklessly accessing the
+<tt>-&gt;a</tt> and <tt>-&gt;b</tt> fields.
+
+<blockquote>
+<pre>
+ 1 bool add_gp_buggy(int a, int b)
+ 2 {
+ 3   p = kmalloc(sizeof(*p), GFP_KERNEL);
+ 4   if (!p)
+ 5     return -ENOMEM;
+ 6   spin_lock(&amp;gp_lock);
+ 7   if (rcu_access_pointer(gp)) {
+ 8     spin_unlock(&amp;gp_lock);
+ 9     return false;
+10   }
+11   p-&gt;a = a;
+12   p-&gt;b = a;
+13   gp = p; /* ORDERING BUG */
+14   spin_unlock(&amp;gp_lock);
+15   return true;
+16 }
+</pre>
+</blockquote>
+
+<p>
+The problem is that both the compiler and weakly ordered CPUs are within
+their rights to reorder this code as follows:
+
+<blockquote>
+<pre>
+ 1 bool add_gp_buggy_optimized(int a, int b)
+ 2 {
+ 3   p = kmalloc(sizeof(*p), GFP_KERNEL);
+ 4   if (!p)
+ 5     return -ENOMEM;
+ 6   spin_lock(&amp;gp_lock);
+ 7   if (rcu_access_pointer(gp)) {
+ 8     spin_unlock(&amp;gp_lock);
+ 9     return false;
+10   }
+<b>11   gp = p; /* ORDERING BUG */
+12   p-&gt;a = a;
+13   p-&gt;b = a;</b>
+14   spin_unlock(&amp;gp_lock);
+15   return true;
+16 }
+</pre>
+</blockquote>
+
+<p>
+If an RCU reader fetches <tt>gp</tt> just after
+<tt>add_gp_buggy_optimized</tt> executes line&nbsp;11,
+it will see garbage in the <tt>-&gt;a</tt> and <tt>-&gt;b</tt>
+fields.
+And this is but one of many ways in which compiler and hardware optimizations
+could cause trouble.
+Therefore, we clearly need some way to prevent the compiler and the CPU from
+reordering in this manner, which brings us to the publish-subscribe
+guarantee discussed in the next section.
+
+<h3><a name="Publish-Subscribe Guarantee">Publish/Subscribe Guarantee</a></h3>
+
+<p>
+RCU's publish-subscribe guarantee allows data to be inserted
+into a linked data structure without disrupting RCU readers.
+The updater uses <tt>rcu_assign_pointer()</tt> to insert the
+new data, and readers use <tt>rcu_dereference()</tt> to
+access data, whether new or old.
+The following shows an example of insertion:
+
+<blockquote>
+<pre>
+ 1 bool add_gp(int a, int b)
+ 2 {
+ 3   p = kmalloc(sizeof(*p), GFP_KERNEL);
+ 4   if (!p)
+ 5     return -ENOMEM;
+ 6   spin_lock(&amp;gp_lock);
+ 7   if (rcu_access_pointer(gp)) {
+ 8     spin_unlock(&amp;gp_lock);
+ 9     return false;
+10   }
+11   p-&gt;a = a;
+12   p-&gt;b = a;
+13   rcu_assign_pointer(gp, p);
+14   spin_unlock(&amp;gp_lock);
+15   return true;
+16 }
+</pre>
+</blockquote>
+
+<p>
+The <tt>rcu_assign_pointer()</tt> on line&nbsp;13 is conceptually
+equivalent to a simple assignment statement, but also guarantees
+that its assignment will
+happen after the two assignments in lines&nbsp;11 and&nbsp;12,
+similar to the C11 <tt>memory_order_release</tt> store operation.
+It also prevents any number of &ldquo;interesting&rdquo; compiler
+optimizations, for example, the use of <tt>gp</tt> as a scratch
+location immediately preceding the assignment.
+
+<p><a name="Quick Quiz 3"><b>Quick Quiz 3</b>:</a>
+But <tt>rcu_assign_pointer()</tt> does nothing to prevent the
+two assignments to <tt>p-&gt;a</tt> and <tt>p-&gt;b</tt>
+from being reordered.
+Can't that also cause problems?
+<br><a href="#qq3answer">Answer</a>
+
+<p>
+It is tempting to assume that the reader need not do anything special
+to control its accesses to the RCU-protected data,
+as shown in <tt>do_something_gp_buggy()</tt> below:
+
+<blockquote>
+<pre>
+ 1 bool do_something_gp_buggy(void)
+ 2 {
+ 3   rcu_read_lock();
+ 4   p = gp;  /* OPTIMIZATIONS GALORE!!! */
+ 5   if (p) {
+ 6     do_something(p-&gt;a, p-&gt;b);
+ 7     rcu_read_unlock();
+ 8     return true;
+ 9   }
+10   rcu_read_unlock();
+11   return false;
+12 }
+</pre>
+</blockquote>
+
+<p>
+However, this temptation must be resisted because there are a
+surprisingly large number of ways that the compiler
+(to say nothing of
+<a href="https://h71000.www7.hp.com/wizard/wiz_2637.html">DEC Alpha CPUs</a>)
+can trip this code up.
+For but one example, if the compiler were short of registers, it
+might choose to refetch from <tt>gp</tt> rather than keeping
+a separate copy in <tt>p</tt> as follows:
+
+<blockquote>
+<pre>
+ 1 bool do_something_gp_buggy_optimized(void)
+ 2 {
+ 3   rcu_read_lock();
+ 4   if (gp) { /* OPTIMIZATIONS GALORE!!! */
+<b> 5     do_something(gp-&gt;a, gp-&gt;b);</b>
+ 6     rcu_read_unlock();
+ 7     return true;
+ 8   }
+ 9   rcu_read_unlock();
+10   return false;
+11 }
+</pre>
+</blockquote>
+
+<p>
+If this function ran concurrently with a series of updates that
+replaced the current structure with a new one,
+the fetches of <tt>gp-&gt;a</tt>
+and <tt>gp-&gt;b</tt> might well come from two different structures,
+which could cause serious confusion.
+To prevent this (and much else besides), <tt>do_something_gp()</tt> uses
+<tt>rcu_dereference()</tt> to fetch from <tt>gp</tt>:
+
+<blockquote>
+<pre>
+ 1 bool do_something_gp(void)
+ 2 {
+ 3   rcu_read_lock();
+ 4   p = rcu_dereference(gp);
+ 5   if (p) {
+ 6     do_something(p-&gt;a, p-&gt;b);
+ 7     rcu_read_unlock();
+ 8     return true;
+ 9   }
+10   rcu_read_unlock();
+11   return false;
+12 }
+</pre>
+</blockquote>
+
+<p>
+The <tt>rcu_dereference()</tt> uses volatile casts and (for DEC Alpha)
+memory barriers in the Linux kernel.
+Should a
+<a href="http://www.rdrop.com/users/paulmck/RCU/consume.2015.07.13a.pdf">high-quality implementation of C11 <tt>memory_order_consume</tt> [PDF]</a>
+ever appear, then <tt>rcu_dereference()</tt> could be implemented
+as a <tt>memory_order_consume</tt> load.
+Regardless of the exact implementation, a pointer fetched by
+<tt>rcu_dereference()</tt> may not be used outside of the
+outermost RCU read-side critical section containing that
+<tt>rcu_dereference()</tt>, unless protection of
+the corresponding data element has been passed from RCU to some
+other synchronization mechanism, most commonly locking or
+<a href="https://www.kernel.org/doc/Documentation/RCU/rcuref.txt">reference counting</a>.
+
+<p>
+In short, updaters use <tt>rcu_assign_pointer()</tt> and readers
+use <tt>rcu_dereference()</tt>, and these two RCU API elements
+work together to ensure that readers have a consistent view of
+newly added data elements.
+
+<p>
+Of course, it is also necessary to remove elements from RCU-protected
+data structures, for example, using the following process:
+
+<ol>
+<li>   Remove the data element from the enclosing structure.
+<li>   Wait for all pre-existing RCU read-side critical sections
+       to complete (because only pre-existing readers can possibly have
+       a reference to the newly removed data element).
+<li>   At this point, only the updater has a reference to the
+       newly removed data element, so it can safely reclaim
+       the data element, for example, by passing it to <tt>kfree()</tt>.
+</ol>
+
+This process is implemented by <tt>remove_gp_synchronous()</tt>:
+
+<blockquote>
+<pre>
+ 1 bool remove_gp_synchronous(void)
+ 2 {
+ 3   struct foo *p;
+ 4
+ 5   spin_lock(&amp;gp_lock);
+ 6   p = rcu_access_pointer(gp);
+ 7   if (!p) {
+ 8     spin_unlock(&amp;gp_lock);
+ 9     return false;
+10   }
+11   rcu_assign_pointer(gp, NULL);
+12   spin_unlock(&amp;gp_lock);
+13   synchronize_rcu();
+14   kfree(p);
+15   return true;
+16 }
+</pre>
+</blockquote>
+
+<p>
+This function is straightforward, with line&nbsp;13 waiting for a grace
+period before line&nbsp;14 frees the old data element.
+This waiting ensures that readers will reach line&nbsp;7 of
+<tt>do_something_gp()</tt> before the data element referenced by
+<tt>p</tt> is freed.
+The <tt>rcu_access_pointer()</tt> on line&nbsp;6 is similar to
+<tt>rcu_dereference()</tt>, except that:
+
+<ol>
+<li>   The value returned by <tt>rcu_access_pointer()</tt>
+       cannot be dereferenced.
+       If you want to access the value pointed to as well as
+       the pointer itself, use <tt>rcu_dereference()</tt>
+       instead of <tt>rcu_access_pointer()</tt>.
+<li>   The call to <tt>rcu_access_pointer()</tt> need not be
+       protected.
+       In contrast, <tt>rcu_dereference()</tt> must either be
+       within an RCU read-side critical section or in a code
+       segment where the pointer cannot change, for example, in
+       code protected by the corresponding update-side lock.
+</ol>
+
+<p><a name="Quick Quiz 4"><b>Quick Quiz 4</b>:</a>
+Without the <tt>rcu_dereference()</tt> or the
+<tt>rcu_access_pointer()</tt>, what destructive optimizations
+might the compiler make use of?
+<br><a href="#qq4answer">Answer</a>
+
+<p>
+In short, RCU's publish-subscribe guarantee is provided by the combination
+of <tt>rcu_assign_pointer()</tt> and <tt>rcu_dereference()</tt>.
+This guarantee allows data elements to be safely added to RCU-protected
+linked data structures without disrupting RCU readers.
+This guarantee can be used in combination with the grace-period
+guarantee to also allow data elements to be removed from RCU-protected
+linked data structures, again without disrupting RCU readers.
+
+<p>
+This guarantee was only partially premeditated.
+DYNIX/ptx used an explicit memory barrier for publication, but had nothing
+resembling <tt>rcu_dereference()</tt> for subscription, nor did it
+have anything resembling the <tt>smp_read_barrier_depends()</tt>
+that was later subsumed into <tt>rcu_dereference()</tt>.
+The need for these operations made itself known quite suddenly at a
+late-1990s meeting with the DEC Alpha architects, back in the days when
+DEC was still a free-standing company.
+It took the Alpha architects a good hour to convince me that any sort
+of barrier would ever be needed, and it then took me a good <i>two</i> hours
+to convince them that their documentation did not make this point clear.
+More recent work with the C and C++ standards committees have provided
+much education on tricks and traps from the compiler.
+In short, compilers were much less tricky in the early 1990s, but in
+2015, don't even think about omitting <tt>rcu_dereference()</tt>!
+
+<h3><a name="Memory-Barrier Guarantees">Memory-Barrier Guarantees</a></h3>
+
+<p>
+The previous section's simple linked-data-structure scenario clearly
+demonstrates the need for RCU's stringent memory-ordering guarantees on
+systems with more than one CPU:
+
+<ol>
+<li>   Each CPU that has an RCU read-side critical section that
+       begins before <tt>synchronize_rcu()</tt> starts is
+       guaranteed to execute a full memory barrier between the time
+       that the RCU read-side critical section ends and the time that
+       <tt>synchronize_rcu()</tt> returns.
+       Without this guarantee, a pre-existing RCU read-side critical section
+       might hold a reference to the newly removed <tt>struct foo</tt>
+       after the <tt>kfree()</tt> on line&nbsp;14 of
+       <tt>remove_gp_synchronous()</tt>.
+<li>   Each CPU that has an RCU read-side critical section that ends
+       after <tt>synchronize_rcu()</tt> returns is guaranteed
+       to execute a full memory barrier between the time that
+       <tt>synchronize_rcu()</tt> begins and the time that the RCU
+       read-side critical section begins.
+       Without this guarantee, a later RCU read-side critical section
+       running after the <tt>kfree()</tt> on line&nbsp;14 of
+       <tt>remove_gp_synchronous()</tt> might
+       later run <tt>do_something_gp()</tt> and find the
+       newly deleted <tt>struct foo</tt>.
+<li>   If the task invoking <tt>synchronize_rcu()</tt> remains
+       on a given CPU, then that CPU is guaranteed to execute a full
+       memory barrier sometime during the execution of
+       <tt>synchronize_rcu()</tt>.
+       This guarantee ensures that the <tt>kfree()</tt> on
+       line&nbsp;14 of <tt>remove_gp_synchronous()</tt> really does
+       execute after the removal on line&nbsp;11.
+<li>   If the task invoking <tt>synchronize_rcu()</tt> migrates
+       among a group of CPUs during that invocation, then each of the
+       CPUs in that group is guaranteed to execute a full memory barrier
+       sometime during the execution of <tt>synchronize_rcu()</tt>.
+       This guarantee also ensures that the <tt>kfree()</tt> on
+       line&nbsp;14 of <tt>remove_gp_synchronous()</tt> really does
+       execute after the removal on
+       line&nbsp;11, but also in the case where the thread executing the
+       <tt>synchronize_rcu()</tt> migrates in the meantime.
+</ol>
+
+<p><a name="Quick Quiz 5"><b>Quick Quiz 5</b>:</a>
+Given that multiple CPUs can start RCU read-side critical sections
+at any time without any ordering whatsoever, how can RCU possibly tell whether
+or not a given RCU read-side critical section starts before a
+given instance of <tt>synchronize_rcu()</tt>?
+<br><a href="#qq5answer">Answer</a>
+
+<p><a name="Quick Quiz 6"><b>Quick Quiz 6</b>:</a>
+The first and second guarantees require unbelievably strict ordering!
+Are all these memory barriers <i> really</i> required?
+<br><a href="#qq6answer">Answer</a>
+
+<p>
+Note that these memory-barrier requirements do not replace the fundamental
+RCU requirement that a grace period wait for all pre-existing readers.
+On the contrary, the memory barriers called out in this section must operate in
+such a way as to <i>enforce</i> this fundamental requirement.
+Of course, different implementations enforce this requirement in different
+ways, but enforce it they must.
+
+<h3><a name="RCU Primitives Guaranteed to Execute Unconditionally">RCU Primitives Guaranteed to Execute Unconditionally</a></h3>
+
+<p>
+The common-case RCU primitives are unconditional.
+They are invoked, they do their job, and they return, with no possibility
+of error, and no need to retry.
+This is a key RCU design philosophy.
+
+<p>
+However, this philosophy is pragmatic rather than pigheaded.
+If someone comes up with a good justification for a particular conditional
+RCU primitive, it might well be implemented and added.
+After all, this guarantee was reverse-engineered, not premeditated.
+The unconditional nature of the RCU primitives was initially an
+accident of implementation, and later experience with synchronization
+primitives with conditional primitives caused me to elevate this
+accident to a guarantee.
+Therefore, the justification for adding a conditional primitive to
+RCU would need to be based on detailed and compelling use cases.
+
+<h3><a name="Guaranteed Read-to-Write Upgrade">Guaranteed Read-to-Write Upgrade</a></h3>
+
+<p>
+As far as RCU is concerned, it is always possible to carry out an
+update within an RCU read-side critical section.
+For example, that RCU read-side critical section might search for
+a given data element, and then might acquire the update-side
+spinlock in order to update that element, all while remaining
+in that RCU read-side critical section.
+Of course, it is necessary to exit the RCU read-side critical section
+before invoking <tt>synchronize_rcu()</tt>, however, this
+inconvenience can be avoided through use of the
+<tt>call_rcu()</tt> and <tt>kfree_rcu()</tt> API members
+described later in this document.
+
+<p><a name="Quick Quiz 7"><b>Quick Quiz 7</b>:</a>
+But how does the upgrade-to-write operation exclude other readers?
+<br><a href="#qq7answer">Answer</a>
+
+<p>
+This guarantee allows lookup code to be shared between read-side
+and update-side code, and was premeditated, appearing in the earliest
+DYNIX/ptx RCU documentation.
+
+<h2><a name="Fundamental Non-Requirements">Fundamental Non-Requirements</a></h2>
+
+<p>
+RCU provides extremely lightweight readers, and its read-side guarantees,
+though quite useful, are correspondingly lightweight.
+It is therefore all too easy to assume that RCU is guaranteeing more
+than it really is.
+Of course, the list of things that RCU does not guarantee is infinitely
+long, however, the following sections list a few non-guarantees that
+have caused confusion.
+Except where otherwise noted, these non-guarantees were premeditated.
+
+<ol>
+<li>   <a href="#Readers Impose Minimal Ordering">
+       Readers Impose Minimal Ordering</a>
+<li>   <a href="#Readers Do Not Exclude Updaters">
+       Readers Do Not Exclude Updaters</a>
+<li>   <a href="#Updaters Only Wait For Old Readers">
+       Updaters Only Wait For Old Readers</a>
+<li>   <a href="#Grace Periods Don't Partition Read-Side Critical Sections">
+       Grace Periods Don't Partition Read-Side Critical Sections</a>
+<li>   <a href="#Read-Side Critical Sections Don't Partition Grace Periods">
+       Read-Side Critical Sections Don't Partition Grace Periods</a>
+<li>   <a href="#Disabling Preemption Does Not Block Grace Periods">
+       Disabling Preemption Does Not Block Grace Periods</a>
+</ol>
+
+<h3><a name="Readers Impose Minimal Ordering">Readers Impose Minimal Ordering</a></h3>
+
+<p>
+Reader-side markers such as <tt>rcu_read_lock()</tt> and
+<tt>rcu_read_unlock()</tt> provide absolutely no ordering guarantees
+except through their interaction with the grace-period APIs such as
+<tt>synchronize_rcu()</tt>.
+To see this, consider the following pair of threads:
+
+<blockquote>
+<pre>
+ 1 void thread0(void)
+ 2 {
+ 3   rcu_read_lock();
+ 4   WRITE_ONCE(x, 1);
+ 5   rcu_read_unlock();
+ 6   rcu_read_lock();
+ 7   WRITE_ONCE(y, 1);
+ 8   rcu_read_unlock();
+ 9 }
+10
+11 void thread1(void)
+12 {
+13   rcu_read_lock();
+14   r1 = READ_ONCE(y);
+15   rcu_read_unlock();
+16   rcu_read_lock();
+17   r2 = READ_ONCE(x);
+18   rcu_read_unlock();
+19 }
+</pre>
+</blockquote>
+
+<p>
+After <tt>thread0()</tt> and <tt>thread1()</tt> execute
+concurrently, it is quite possible to have
+
+<blockquote>
+<pre>
+(r1 == 1 &amp;&amp; r2 == 0)
+</pre>
+</blockquote>
+
+(that is, <tt>y</tt> appears to have been assigned before <tt>x</tt>),
+which would not be possible if <tt>rcu_read_lock()</tt> and
+<tt>rcu_read_unlock()</tt> had much in the way of ordering
+properties.
+But they do not, so the CPU is within its rights
+to do significant reordering.
+This is by design:  Any significant ordering constraints would slow down
+these fast-path APIs.
+
+<p><a name="Quick Quiz 8"><b>Quick Quiz 8</b>:</a>
+Can't the compiler also reorder this code?
+<br><a href="#qq8answer">Answer</a>
+
+<h3><a name="Readers Do Not Exclude Updaters">Readers Do Not Exclude Updaters</a></h3>
+
+<p>
+Neither <tt>rcu_read_lock()</tt> nor <tt>rcu_read_unlock()</tt>
+exclude updates.
+All they do is to prevent grace periods from ending.
+The following example illustrates this:
+
+<blockquote>
+<pre>
+ 1 void thread0(void)
+ 2 {
+ 3   rcu_read_lock();
+ 4   r1 = READ_ONCE(y);
+ 5   if (r1) {
+ 6     do_something_with_nonzero_x();
+ 7     r2 = READ_ONCE(x);
+ 8     WARN_ON(!r2); /* BUG!!! */
+ 9   }
+10   rcu_read_unlock();
+11 }
+12
+13 void thread1(void)
+14 {
+15   spin_lock(&amp;my_lock);
+16   WRITE_ONCE(x, 1);
+17   WRITE_ONCE(y, 1);
+18   spin_unlock(&amp;my_lock);
+19 }
+</pre>
+</blockquote>
+
+<p>
+If the <tt>thread0()</tt> function's <tt>rcu_read_lock()</tt>
+excluded the <tt>thread1()</tt> function's update,
+the <tt>WARN_ON()</tt> could never fire.
+But the fact is that <tt>rcu_read_lock()</tt> does not exclude
+much of anything aside from subsequent grace periods, of which
+<tt>thread1()</tt> has none, so the
+<tt>WARN_ON()</tt> can and does fire.
+
+<h3><a name="Updaters Only Wait For Old Readers">Updaters Only Wait For Old Readers</a></h3>
+
+<p>
+It might be tempting to assume that after <tt>synchronize_rcu()</tt>
+completes, there are no readers executing.
+This temptation must be avoided because
+new readers can start immediately after <tt>synchronize_rcu()</tt>
+starts, and <tt>synchronize_rcu()</tt> is under no
+obligation to wait for these new readers.
+
+<p><a name="Quick Quiz 9"><b>Quick Quiz 9</b>:</a>
+Suppose that synchronize_rcu() did wait until all readers had completed.
+Would the updater be able to rely on this?
+<br><a href="#qq9answer">Answer</a>
+
+<h3><a name="Grace Periods Don't Partition Read-Side Critical Sections">
+Grace Periods Don't Partition Read-Side Critical Sections</a></h3>
+
+<p>
+It is tempting to assume that if any part of one RCU read-side critical
+section precedes a given grace period, and if any part of another RCU
+read-side critical section follows that same grace period, then all of
+the first RCU read-side critical section must precede all of the second.
+However, this just isn't the case: A single grace period does not
+partition the set of RCU read-side critical sections.
+An example of this situation can be illustrated as follows, where
+<tt>x</tt>, <tt>y</tt>, and <tt>z</tt> are initially all zero:
+
+<blockquote>
+<pre>
+ 1 void thread0(void)
+ 2 {
+ 3   rcu_read_lock();
+ 4   WRITE_ONCE(a, 1);
+ 5   WRITE_ONCE(b, 1);
+ 6   rcu_read_unlock();
+ 7 }
+ 8
+ 9 void thread1(void)
+10 {
+11   r1 = READ_ONCE(a);
+12   synchronize_rcu();
+13   WRITE_ONCE(c, 1);
+14 }
+15
+16 void thread2(void)
+17 {
+18   rcu_read_lock();
+19   r2 = READ_ONCE(b);
+20   r3 = READ_ONCE(c);
+21   rcu_read_unlock();
+22 }
+</pre>
+</blockquote>
+
+<p>
+It turns out that the outcome:
+
+<blockquote>
+<pre>
+(r1 == 1 &amp;&amp; r2 == 0 &amp;&amp; r3 == 1)
+</pre>
+</blockquote>
+
+is entirely possible.
+The following figure show how this can happen, with each circled
+<tt>QS</tt> indicating the point at which RCU recorded a
+<i>quiescent state</i> for each thread, that is, a state in which
+RCU knows that the thread cannot be in the midst of an RCU read-side
+critical section that started before the current grace period:
+
+<p><img src="GPpartitionReaders1.svg" alt="GPpartitionReaders1.svg" width="60%"></p>
+
+<p>
+If it is necessary to partition RCU read-side critical sections in this
+manner, it is necessary to use two grace periods, where the first
+grace period is known to end before the second grace period starts:
+
+<blockquote>
+<pre>
+ 1 void thread0(void)
+ 2 {
+ 3   rcu_read_lock();
+ 4   WRITE_ONCE(a, 1);
+ 5   WRITE_ONCE(b, 1);
+ 6   rcu_read_unlock();
+ 7 }
+ 8
+ 9 void thread1(void)
+10 {
+11   r1 = READ_ONCE(a);
+12   synchronize_rcu();
+13   WRITE_ONCE(c, 1);
+14 }
+15
+16 void thread2(void)
+17 {
+18   r2 = READ_ONCE(c);
+19   synchronize_rcu();
+20   WRITE_ONCE(d, 1);
+21 }
+22
+23 void thread3(void)
+24 {
+25   rcu_read_lock();
+26   r3 = READ_ONCE(b);
+27   r4 = READ_ONCE(d);
+28   rcu_read_unlock();
+29 }
+</pre>
+</blockquote>
+
+<p>
+Here, if <tt>(r1 == 1)</tt>, then
+<tt>thread0()</tt>'s write to <tt>b</tt> must happen
+before the end of <tt>thread1()</tt>'s grace period.
+If in addition <tt>(r4 == 1)</tt>, then
+<tt>thread3()</tt>'s read from <tt>b</tt> must happen
+after the beginning of <tt>thread2()</tt>'s grace period.
+If it is also the case that <tt>(r2 == 1)</tt>, then the
+end of <tt>thread1()</tt>'s grace period must precede the
+beginning of <tt>thread2()</tt>'s grace period.
+This mean that the two RCU read-side critical sections cannot overlap,
+guaranteeing that <tt>(r3 == 1)</tt>.
+As a result, the outcome:
+
+<blockquote>
+<pre>
+(r1 == 1 &amp;&amp; r2 == 1 &amp;&amp; r3 == 0 &amp;&amp; r4 == 1)
+</pre>
+</blockquote>
+
+cannot happen.
+
+<p>
+This non-requirement was also non-premeditated, but became apparent
+when studying RCU's interaction with memory ordering.
+
+<h3><a name="Read-Side Critical Sections Don't Partition Grace Periods">
+Read-Side Critical Sections Don't Partition Grace Periods</a></h3>
+
+<p>
+It is also tempting to assume that if an RCU read-side critical section
+happens between a pair of grace periods, then those grace periods cannot
+overlap.
+However, this temptation leads nowhere good, as can be illustrated by
+the following, with all variables initially zero:
+
+<blockquote>
+<pre>
+ 1 void thread0(void)
+ 2 {
+ 3   rcu_read_lock();
+ 4   WRITE_ONCE(a, 1);
+ 5   WRITE_ONCE(b, 1);
+ 6   rcu_read_unlock();
+ 7 }
+ 8
+ 9 void thread1(void)
+10 {
+11   r1 = READ_ONCE(a);
+12   synchronize_rcu();
+13   WRITE_ONCE(c, 1);
+14 }
+15
+16 void thread2(void)
+17 {
+18   rcu_read_lock();
+19   WRITE_ONCE(d, 1);
+20   r2 = READ_ONCE(c);
+21   rcu_read_unlock();
+22 }
+23
+24 void thread3(void)
+25 {
+26   r3 = READ_ONCE(d);
+27   synchronize_rcu();
+28   WRITE_ONCE(e, 1);
+29 }
+30
+31 void thread4(void)
+32 {
+33   rcu_read_lock();
+34   r4 = READ_ONCE(b);
+35   r5 = READ_ONCE(e);
+36   rcu_read_unlock();
+37 }
+</pre>
+</blockquote>
+
+<p>
+In this case, the outcome:
+
+<blockquote>
+<pre>
+(r1 == 1 &amp;&amp; r2 == 1 &amp;&amp; r3 == 1 &amp;&amp; r4 == 0 &amp&amp; r5 == 1)
+</pre>
+</blockquote>
+
+is entirely possible, as illustrated below:
+
+<p><img src="ReadersPartitionGP1.svg" alt="ReadersPartitionGP1.svg" width="100%"></p>
+
+<p>
+Again, an RCU read-side critical section can overlap almost all of a
+given grace period, just so long as it does not overlap the entire
+grace period.
+As a result, an RCU read-side critical section cannot partition a pair
+of RCU grace periods.
+
+<p><a name="Quick Quiz 10"><b>Quick Quiz 10</b>:</a>
+How long a sequence of grace periods, each separated by an RCU read-side
+critical section, would be required to partition the RCU read-side
+critical sections at the beginning and end of the chain?
+<br><a href="#qq10answer">Answer</a>
+
+<h3><a name="Disabling Preemption Does Not Block Grace Periods">
+Disabling Preemption Does Not Block Grace Periods</a></h3>
+
+<p>
+There was a time when disabling preemption on any given CPU would block
+subsequent grace periods.
+However, this was an accident of implementation and is not a requirement.
+And in the current Linux-kernel implementation, disabling preemption
+on a given CPU in fact does not block grace periods, as Oleg Nesterov
+<a href="https://lkml.kernel.org/g/20150614193825.GA19582@redhat.com">demonstrated</a>.
+
+<p>
+If you need a preempt-disable region to block grace periods, you need to add
+<tt>rcu_read_lock()</tt> and <tt>rcu_read_unlock()</tt>, for example
+as follows:
+
+<blockquote>
+<pre>
+ 1 preempt_disable();
+ 2 rcu_read_lock();
+ 3 do_something();
+ 4 rcu_read_unlock();
+ 5 preempt_enable();
+ 6
+ 7 /* Spinlocks implicitly disable preemption. */
+ 8 spin_lock(&amp;mylock);
+ 9 rcu_read_lock();
+10 do_something();
+11 rcu_read_unlock();
+12 spin_unlock(&amp;mylock);
+</pre>
+</blockquote>
+
+<p>
+In theory, you could enter the RCU read-side critical section first,
+but it is more efficient to keep the entire RCU read-side critical
+section contained in the preempt-disable region as shown above.
+Of course, RCU read-side critical sections that extend outside of
+preempt-disable regions will work correctly, but such critical sections
+can be preempted, which forces <tt>rcu_read_unlock()</tt> to do
+more work.
+And no, this is <i>not</i> an invitation to enclose all of your RCU
+read-side critical sections within preempt-disable regions, because
+doing so would degrade real-time response.
+
+<p>
+This non-requirement appeared with preemptible RCU.
+If you need a grace period that waits on non-preemptible code regions, use
+<a href="#Sched Flavor">RCU-sched</a>.
+
+<h2><a name="Parallelism Facts of Life">Parallelism Facts of Life</a></h2>
+
+<p>
+These parallelism facts of life are by no means specific to RCU, but
+the RCU implementation must abide by them.
+They therefore bear repeating:
+
+<ol>
+<li>   Any CPU or task may be delayed at any time,
+       and any attempts to avoid these delays by disabling
+       preemption, interrupts, or whatever are completely futile.
+       This is most obvious in preemptible user-level
+       environments and in virtualized environments (where
+       a given guest OS's VCPUs can be preempted at any time by
+       the underlying hypervisor), but can also happen in bare-metal
+       environments due to ECC errors, NMIs, and other hardware
+       events.
+       Although a delay of more than about 20 seconds can result
+       in splats, the RCU implementation is obligated to use
+       algorithms that can tolerate extremely long delays, but where
+       &ldquo;extremely long&rdquo; is not long enough to allow
+       wrap-around when incrementing a 64-bit counter.
+<li>   Both the compiler and the CPU can reorder memory accesses.
+       Where it matters, RCU must use compiler directives and
+       memory-barrier instructions to preserve ordering.
+<li>   Conflicting writes to memory locations in any given cache line
+       will result in expensive cache misses.
+       Greater numbers of concurrent writes and more-frequent
+       concurrent writes will result in more dramatic slowdowns.
+       RCU is therefore obligated to use algorithms that have
+       sufficient locality to avoid significant performance and
+       scalability problems.
+<li>   As a rough rule of thumb, only one CPU's worth of processing
+       may be carried out under the protection of any given exclusive
+       lock.
+       RCU must therefore use scalable locking designs.
+<li>   Counters are finite, especially on 32-bit systems.
+       RCU's use of counters must therefore tolerate counter wrap,
+       or be designed such that counter wrap would take way more
+       time than a single system is likely to run.
+       An uptime of ten years is quite possible, a runtime
+       of a century much less so.
+       As an example of the latter, RCU's dyntick-idle nesting counter
+       allows 54 bits for interrupt nesting level (this counter
+       is 64 bits even on a 32-bit system).
+       Overflowing this counter requires 2<sup>54</sup>
+       half-interrupts on a given CPU without that CPU ever going idle.
+       If a half-interrupt happened every microsecond, it would take
+       570 years of runtime to overflow this counter, which is currently
+       believed to be an acceptably long time.
+<li>   Linux systems can have thousands of CPUs running a single
+       Linux kernel in a single shared-memory environment.
+       RCU must therefore pay close attention to high-end scalability.
+</ol>
+
+<p>
+This last parallelism fact of life means that RCU must pay special
+attention to the preceding facts of life.
+The idea that Linux might scale to systems with thousands of CPUs would
+have been met with some skepticism in the 1990s, but these requirements
+would have otherwise have been unsurprising, even in the early 1990s.
+
+<h2><a name="Quality-of-Implementation Requirements">Quality-of-Implementation Requirements</a></h2>
+
+<p>
+These sections list quality-of-implementation requirements.
+Although an RCU implementation that ignores these requirements could
+still be used, it would likely be subject to limitations that would
+make it inappropriate for industrial-strength production use.
+Classes of quality-of-implementation requirements are as follows:
+
+<ol>
+<li>   <a href="#Specialization">Specialization</a>
+<li>   <a href="#Performance and Scalability">Performance and Scalability</a>
+<li>   <a href="#Composability">Composability</a>
+<li>   <a href="#Corner Cases">Corner Cases</a>
+</ol>
+
+<p>
+These classes is covered in the following sections.
+
+<h3><a name="Specialization">Specialization</a></h3>
+
+<p>
+RCU is and always has been intended primarily for read-mostly situations, as
+illustrated by the following figure.
+This means that RCU's read-side primitives are optimized, often at the
+expense of its update-side primitives.
+
+<p><img src="RCUApplicability.svg" alt="RCUApplicability.svg" width="70%"></p>
+
+<p>
+This focus on read-mostly situations means that RCU must interoperate
+with other synchronization primitives.
+For example, the <tt>add_gp()</tt> and <tt>remove_gp_synchronous()</tt>
+examples discussed earlier use RCU to protect readers and locking to
+coordinate updaters.
+However, the need extends much farther, requiring that a variety of
+synchronization primitives be legal within RCU read-side critical sections,
+including spinlocks, sequence locks, atomic operations, reference
+counters, and memory barriers.
+
+<p><a name="Quick Quiz 11"><b>Quick Quiz 11</b>:</a>
+What about sleeping locks?
+<br><a href="#qq11answer">Answer</a>
+
+<p>
+It often comes as a surprise that many algorithms do not require a
+consistent view of data, but many can function in that mode,
+with network routing being the poster child.
+Internet routing algorithms take significant time to propagate
+updates, so that by the time an update arrives at a given system,
+that system has been sending network traffic the wrong way for
+a considerable length of time.
+Having a few threads continue to send traffic the wrong way for a
+few more milliseconds is clearly not a problem:  In the worst case,
+TCP retransmissions will eventually get the data where it needs to go.
+In general, when tracking the state of the universe outside of the
+computer, some level of inconsistency must be tolerated due to
+speed-of-light delays if nothing else.
+
+<p>
+Furthermore, uncertainty about external state is inherent in many cases.
+For example, a pair of veternarians might use heartbeat to determine
+whether or not a given cat was alive.
+But how long should they wait after the last heartbeat to decide that
+the cat is in fact dead?
+Waiting less than 400 milliseconds makes no sense because this would
+mean that a relaxed cat would be considered to cycle between death
+and life more than 100 times per minute.
+Moreover, just as with human beings, a cat's heart might stop for
+some period of time, so the exact wait period is a judgment call.
+One of our pair of veternarians might wait 30 seconds before pronouncing
+the cat dead, while the other might insist on waiting a full minute.
+The two veternarians would then disagree on the state of the cat during
+the final 30 seconds of the minute following the last heartbeat, as
+fancifully illustrated below:
+
+<p><img src="2013-08-is-it-dead.png" alt="2013-08-is-it-dead.png" width="431"></p>
+
+<p>
+Interestingly enough, this same situation applies to hardware.
+When push comes to shove, how do we tell whether or not some
+external server has failed?
+We send messages to it periodically, and declare it failed if we
+don't receive a response within a given period of time.
+Policy decisions can usually tolerate short
+periods of inconsistency.
+The policy was decided some time ago, and is only now being put into
+effect, so a few milliseconds of delay is normally inconsequential.
+
+<p>
+However, there are algorithms that absolutely must see consistent data.
+For example, the translation between a user-level SystemV semaphore
+ID to the corresponding in-kernel data structure is protected by RCU,
+but it is absolutely forbidden to update a semaphore that has just been
+removed.
+In the Linux kernel, this need for consistency is accommodated by acquiring
+spinlocks located in the in-kernel data structure from within
+the RCU read-side critical section, and this is indicated by the
+green box in the figure above.
+Many other techniques may be used, and are in fact used within the
+Linux kernel.
+
+<p>
+In short, RCU is not required to maintain consistency, and other
+mechanisms may be used in concert with RCU when consistency is required.
+RCU's specialization allows it to do its job extremely well, and its
+ability to interoperate with other synchronization mechanisms allows
+the right mix of synchronization tools to be used for a given job.
+
+<h3><a name="Performance and Scalability">Performance and Scalability</a></h3>
+
+<p>
+Energy efficiency is a critical component of performance today,
+and Linux-kernel RCU implementations must therefore avoid unnecessarily
+awakening idle CPUs.
+I cannot claim that this requirement was premeditated.
+In fact, I learned of it during a telephone conversation in which I
+was given &ldquo;frank and open&rdquo; feedback on the importance
+of energy efficiency in battery-powered systems and on specific
+energy-efficiency shortcomings of the Linux-kernel RCU implementation.
+In my experience, the battery-powered embedded community will consider
+any unnecessary wakeups to be extremely unfriendly acts.
+So much so that mere Linux-kernel-mailing-list posts are
+insufficient to vent their ire.
+
+<p>
+Memory consumption is not particularly important for in most
+situations, and has become decreasingly
+so as memory sizes have expanded and memory
+costs have plummeted.
+However, as I learned from Matt Mackall's
+<a href="http://elinux.org/Linux_Tiny-FAQ">bloatwatch</a>
+efforts, memory footprint is critically important on single-CPU systems with
+non-preemptible (<tt>CONFIG_PREEMPT=n</tt>) kernels, and thus
+<a href="https://lkml.kernel.org/g/20090113221724.GA15307@linux.vnet.ibm.com">tiny RCU</a>
+was born.
+Josh Triplett has since taken over the small-memory banner with his
+<a href="https://tiny.wiki.kernel.org/">Linux kernel tinification</a>
+project, which resulted in
+<a href="#Sleepable RCU">SRCU</a>
+becoming optional for those kernels not needing it.
+
+<p>
+The remaining performance requirements are, for the most part,
+unsurprising.
+For example, in keeping with RCU's read-side specialization,
+<tt>rcu_dereference()</tt> should have negligible overhead (for
+example, suppression of a few minor compiler optimizations).
+Similarly, in non-preemptible environments, <tt>rcu_read_lock()</tt> and
+<tt>rcu_read_unlock()</tt> should have exactly zero overhead.
+
+<p>
+In preemptible environments, in the case where the RCU read-side
+critical section was not preempted (as will be the case for the
+highest-priority real-time process), <tt>rcu_read_lock()</tt> and
+<tt>rcu_read_unlock()</tt> should have minimal overhead.
+In particular, they should not contain atomic read-modify-write
+operations, memory-barrier instructions, preemption disabling,
+interrupt disabling, or backwards branches.
+However, in the case where the RCU read-side critical section was preempted,
+<tt>rcu_read_unlock()</tt> may acquire spinlocks and disable interrupts.
+This is why it is better to nest an RCU read-side critical section
+within a preempt-disable region than vice versa, at least in cases
+where that critical section is short enough to avoid unduly degrading
+real-time latencies.
+
+<p>
+The <tt>synchronize_rcu()</tt> grace-period-wait primitive is
+optimized for throughput.
+It may therefore incur several milliseconds of latency in addition to
+the duration of the longest RCU read-side critical section.
+On the other hand, multiple concurrent invocations of
+<tt>synchronize_rcu()</tt> are required to use batching optimizations
+so that they can be satisfied by a single underlying grace-period-wait
+operation.
+For example, in the Linux kernel, it is not unusual for a single
+grace-period-wait operation to serve more than
+<a href="https://www.usenix.org/conference/2004-usenix-annual-technical-conference/making-rcu-safe-deep-sub-millisecond-response">1,000 separate invocations</a>
+of <tt>synchronize_rcu()</tt>, thus amortizing the per-invocation
+overhead down to nearly zero.
+However, the grace-period optimization is also required to avoid
+measurable degradation of real-time scheduling and interrupt latencies.
+
+<p>
+In some cases, the multi-millisecond <tt>synchronize_rcu()</tt>
+latencies are unacceptable.
+In these cases, <tt>synchronize_rcu_expedited()</tt> may be used
+instead, reducing the grace-period latency down to a few tens of
+microseconds on small systems, at least in cases where the RCU read-side
+critical sections are short.
+There are currently no special latency requirements for
+<tt>synchronize_rcu_expedited()</tt> on large systems, but,
+consistent with the empirical nature of the RCU specification,
+that is subject to change.
+However, there most definitely are scalability requirements:
+A storm of <tt>synchronize_rcu_expedited()</tt> invocations on 4096
+CPUs should at least make reasonable forward progress.
+In return for its shorter latencies, <tt>synchronize_rcu_expedited()</tt>
+is permitted to impose modest degradation of real-time latency
+on non-idle online CPUs.
+That said, it will likely be necessary to take further steps to reduce this
+degradation, hopefully to roughly that of a scheduling-clock interrupt.
+
+<p>
+There are a number of situations where even
+<tt>synchronize_rcu_expedited()</tt>'s reduced grace-period
+latency is unacceptable.
+In these situations, the asynchronous <tt>call_rcu()</tt> can be
+used in place of <tt>synchronize_rcu()</tt> as follows:
+
+<blockquote>
+<pre>
+ 1 struct foo {
+ 2   int a;
+ 3   int b;
+ 4   struct rcu_head rh;
+ 5 };
+ 6
+ 7 static void remove_gp_cb(struct rcu_head *rhp)
+ 8 {
+ 9   struct foo *p = container_of(rhp, struct foo, rh);
+10
+11   kfree(p);
+12 }
+13
+14 bool remove_gp_asynchronous(void)
+15 {
+16   struct foo *p;
+17
+18   spin_lock(&amp;gp_lock);
+19   p = rcu_dereference(gp);
+20   if (!p) {
+21     spin_unlock(&amp;gp_lock);
+22     return false;
+23   }
+24   rcu_assign_pointer(gp, NULL);
+25   call_rcu(&amp;p-&gt;rh, remove_gp_cb);
+26   spin_unlock(&amp;gp_lock);
+27   return true;
+28 }
+</pre>
+</blockquote>
+
+<p>
+A definition of <tt>struct foo</tt> is finally needed, and appears
+on lines&nbsp;1-5.
+The function <tt>remove_gp_cb()</tt> is passed to <tt>call_rcu()</tt>
+on line&nbsp;25, and will be invoked after the end of a subsequent
+grace period.
+This gets the same effect as <tt>remove_gp_synchronous()</tt>,
+but without forcing the updater to wait for a grace period to elapse.
+The <tt>call_rcu()</tt> function may be used in a number of
+situations where neither <tt>synchronize_rcu()</tt> nor
+<tt>synchronize_rcu_expedited()</tt> would be legal,
+including within preempt-disable code, <tt>local_bh_disable()</tt> code,
+interrupt-disable code, and interrupt handlers.
+However, even <tt>call_rcu()</tt> is illegal within NMI handlers.
+The callback function (<tt>remove_gp_cb()</tt> in this case) will be
+executed within softirq (software interrupt) environment within the
+Linux kernel,
+either within a real softirq handler or under the protection
+of <tt>local_bh_disable()</tt>.
+In both the Linux kernel and in userspace, it is bad practice to
+write an RCU callback function that takes too long.
+Long-running operations should be relegated to separate threads or
+(in the Linux kernel) workqueues.
+
+<p><a name="Quick Quiz 12"><b>Quick Quiz 12</b>:</a>
+Why does line&nbsp;19 use <tt>rcu_access_pointer()</tt>?
+After all, <tt>call_rcu()</tt> on line&nbsp;25 stores into the
+structure, which would interact badly with concurrent insertions.
+Doesn't this mean that <tt>rcu_dereference()</tt> is required?
+<br><a href="#qq12answer">Answer</a>
+
+<p>
+However, all that <tt>remove_gp_cb()</tt> is doing is
+invoking <tt>kfree()</tt> on the data element.
+This is a common idiom, and is supported by <tt>kfree_rcu()</tt>,
+which allows &ldquo;fire and forget&rdquo; operation as shown below:
+
+<blockquote>
+<pre>
+ 1 struct foo {
+ 2   int a;
+ 3   int b;
+ 4   struct rcu_head rh;
+ 5 };
+ 6
+ 7 bool remove_gp_faf(void)
+ 8 {
+ 9   struct foo *p;
+10
+11   spin_lock(&amp;gp_lock);
+12   p = rcu_dereference(gp);
+13   if (!p) {
+14     spin_unlock(&amp;gp_lock);
+15     return false;
+16   }
+17   rcu_assign_pointer(gp, NULL);
+18   kfree_rcu(p, rh);
+19   spin_unlock(&amp;gp_lock);
+20   return true;
+21 }
+</pre>
+</blockquote>
+
+<p>
+Note that <tt>remove_gp_faf()</tt> simply invokes
+<tt>kfree_rcu()</tt> and proceeds, without any need to pay any
+further attention to the subsequent grace period and <tt>kfree()</tt>.
+It is permissible to invoke <tt>kfree_rcu()</tt> from the same
+environments as for <tt>call_rcu()</tt>.
+Interestingly enough, DYNIX/ptx had the equivalents of
+<tt>call_rcu()</tt> and <tt>kfree_rcu()</tt>, but not
+<tt>synchronize_rcu()</tt>.
+This was due to the fact that RCU was not heavily used within DYNIX/ptx,
+so the very few places that needed something like
+<tt>synchronize_rcu()</tt> simply open-coded it.
+
+<p><a name="Quick Quiz 13"><b>Quick Quiz 13</b>:</a>
+Earlier it was claimed that <tt>call_rcu()</tt> and
+<tt>kfree_rcu()</tt> allowed updaters to avoid being blocked
+by readers.
+But how can that be correct, given that the invocation of the callback
+and the freeing of the memory (respectively) must still wait for
+a grace period to elapse?
+<br><a href="#qq13answer">Answer</a>
+
+<p>
+But what if the updater must wait for the completion of code to be
+executed after the end of the grace period, but has other tasks
+that can be carried out in the meantime?
+The polling-style <tt>get_state_synchronize_rcu()</tt> and
+<tt>cond_synchronize_rcu()</tt> functions may be used for this
+purpose, as shown below:
+
+<blockquote>
+<pre>
+ 1 bool remove_gp_poll(void)
+ 2 {
+ 3   struct foo *p;
+ 4   unsigned long s;
+ 5
+ 6   spin_lock(&amp;gp_lock);
+ 7   p = rcu_access_pointer(gp);
+ 8   if (!p) {
+ 9     spin_unlock(&amp;gp_lock);
+10     return false;
+11   }
+12   rcu_assign_pointer(gp, NULL);
+13   spin_unlock(&amp;gp_lock);
+14   s = get_state_synchronize_rcu();
+15   do_something_while_waiting();
+16   cond_synchronize_rcu(s);
+17   kfree(p);
+18   return true;
+19 }
+</pre>
+</blockquote>
+
+<p>
+On line&nbsp;14, <tt>get_state_synchronize_rcu()</tt> obtains a
+&ldquo;cookie&rdquo; from RCU,
+then line&nbsp;15 carries out other tasks,
+and finally, line&nbsp;16 returns immediately if a grace period has
+elapsed in the meantime, but otherwise waits as required.
+The need for <tt>get_state_synchronize_rcu</tt> and
+<tt>cond_synchronize_rcu()</tt> has appeared quite recently,
+so it is too early to tell whether they will stand the test of time.
+
+<p>
+RCU thus provides a range of tools to allow updaters to strike the
+required tradeoff between latency, flexibility and CPU overhead.
+
+<h3><a name="Composability">Composability</a></h3>
+
+<p>
+Composability has received much attention in recent years, perhaps in part
+due to the collision of multicore hardware with object-oriented techniques
+designed in single-threaded environments for single-threaded use.
+And in theory, RCU read-side critical sections may be composed, and in
+fact may be nested arbitrarily deeply.
+In practice, as with all real-world implementations of composable
+constructs, there are limitations.
+
+<p>
+Implementations of RCU for which <tt>rcu_read_lock()</tt>
+and <tt>rcu_read_unlock()</tt> generate no code, such as
+Linux-kernel RCU when <tt>CONFIG_PREEMPT=n</tt>, can be
+nested arbitrarily deeply.
+After all, there is no overhead.
+Except that if all these instances of <tt>rcu_read_lock()</tt>
+and <tt>rcu_read_unlock()</tt> are visible to the compiler,
+compilation will eventually fail due to exhausting memory,
+mass storage, or user patience, whichever comes first.
+If the nesting is not visible to the compiler, as is the case with
+mutually recursive functions each in its own translation unit,
+stack overflow will result.
+If the nesting takes the form of loops, either the control variable
+will overflow or (in the Linux kernel) you will get an RCU CPU stall warning.
+Nevertheless, this class of RCU implementations is one
+of the most composable constructs in existence.
+
+<p>
+RCU implementations that explicitly track nesting depth
+are limited by the nesting-depth counter.
+For example, the Linux kernel's preemptible RCU limits nesting to
+<tt>INT_MAX</tt>.
+This should suffice for almost all practical purposes.
+That said, a consecutive pair of RCU read-side critical sections
+between which there is an operation that waits for a grace period
+cannot be enclosed in another RCU read-side critical section.
+This is because it is not legal to wait for a grace period within
+an RCU read-side critical section:  To do so would result either
+in deadlock or
+in RCU implicitly splitting the enclosing RCU read-side critical
+section, neither of which is conducive to a long-lived and prosperous
+kernel.
+
+<p>
+It is worth noting that RCU is not alone in limiting composability.
+For example, many transactional-memory implementations prohibit
+composing a pair of transactions separated by an irrevocable
+operation (for example, a network receive operation).
+For another example, lock-based critical sections can be composed
+surprisingly freely, but only if deadlock is avoided.
+
+<p>
+In short, although RCU read-side critical sections are highly composable,
+care is required in some situations, just as is the case for any other
+composable synchronization mechanism.
+
+<h3><a name="Corner Cases">Corner Cases</a></h3>
+
+<p>
+A given RCU workload might have an endless and intense stream of
+RCU read-side critical sections, perhaps even so intense that there
+was never a point in time during which there was not at least one
+RCU read-side critical section in flight.
+RCU cannot allow this situation to block grace periods:  As long as
+all the RCU read-side critical sections are finite, grace periods
+must also be finite.
+
+<p>
+That said, preemptible RCU implementations could potentially result
+in RCU read-side critical sections being preempted for long durations,
+which has the effect of creating a long-duration RCU read-side
+critical section.
+This situation can arise only in heavily loaded systems, but systems using
+real-time priorities are of course more vulnerable.
+Therefore, RCU priority boosting is provided to help deal with this
+case.
+That said, the exact requirements on RCU priority boosting will likely
+evolve as more experience accumulates.
+
+<p>
+Other workloads might have very high update rates.
+Although one can argue that such workloads should instead use
+something other than RCU, the fact remains that RCU must
+handle such workloads gracefully.
+This requirement is another factor driving batching of grace periods,
+but it is also the driving force behind the checks for large numbers
+of queued RCU callbacks in the <tt>call_rcu()</tt> code path.
+Finally, high update rates should not delay RCU read-side critical
+sections, although some read-side delays can occur when using
+<tt>synchronize_rcu_expedited()</tt>, courtesy of this function's use
+of <tt>try_stop_cpus()</tt>.
+(In the future, <tt>synchronize_rcu_expedited()</tt> will be
+converted to use lighter-weight inter-processor interrupts (IPIs),
+but this will still disturb readers, though to a much smaller degree.)
+
+<p>
+Although all three of these corner cases were understood in the early
+1990s, a simple user-level test consisting of <tt>close(open(path))</tt>
+in a tight loop
+in the early 2000s suddenly provided a much deeper appreciation of the
+high-update-rate corner case.
+This test also motivated addition of some RCU code to react to high update
+rates, for example, if a given CPU finds itself with more than 10,000
+RCU callbacks queued, it will cause RCU to take evasive action by
+more aggressively starting grace periods and more aggressively forcing
+completion of grace-period processing.
+This evasive action causes the grace period to complete more quickly,
+but at the cost of restricting RCU's batching optimizations, thus
+increasing the CPU overhead incurred by that grace period.
+
+<h2><a name="Software-Engineering Requirements">
+Software-Engineering Requirements</a></h2>
+
+<p>
+Between Murphy's Law and &ldquo;To err is human&rdquo;, it is necessary to
+guard against mishaps and misuse:
+
+<ol>
+<li>   It is all too easy to forget to use <tt>rcu_read_lock()</tt>
+       everywhere that it is needed, so kernels built with
+       <tt>CONFIG_PROVE_RCU=y</tt> will spat if
+       <tt>rcu_dereference()</tt> is used outside of an
+       RCU read-side critical section.
+       Update-side code can use <tt>rcu_dereference_protected()</tt>,
+       which takes a
+       <a href="https://lwn.net/Articles/371986/">lockdep expression</a>
+       to indicate what is providing the protection.
+       If the indicated protection is not provided, a lockdep splat
+       is emitted.
+
+       <p>
+       Code shared between readers and updaters can use
+       <tt>rcu_dereference_check()</tt>, which also takes a
+       lockdep expression, and emits a lockdep splat if neither
+       <tt>rcu_read_lock()</tt> nor the indicated protection
+       is in place.
+       In addition, <tt>rcu_dereference_raw()</tt> is used in those
+       (hopefully rare) cases where the required protection cannot
+       be easily described.
+       Finally, <tt>rcu_read_lock_held()</tt> is provided to
+       allow a function to verify that it has been invoked within
+       an RCU read-side critical section.
+       I was made aware of this set of requirements shortly after Thomas
+       Gleixner audited a number of RCU uses.
+<li>   A given function might wish to check for RCU-related preconditions
+       upon entry, before using any other RCU API.
+       The <tt>rcu_lockdep_assert()</tt> does this job,
+       asserting the expression in kernels having lockdep enabled
+       and doing nothing otherwise.
+<li>   It is also easy to forget to use <tt>rcu_assign_pointer()</tt>
+       and <tt>rcu_dereference()</tt>, perhaps (incorrectly)
+       substituting a simple assignment.
+       To catch this sort of error, a given RCU-protected pointer may be
+       tagged with <tt>__rcu</tt>, after which running sparse
+       with <tt>CONFIG_SPARSE_RCU_POINTER=y</tt> will complain
+       about simple-assignment accesses to that pointer.
+       Arnd Bergmann made me aware of this requirement, and also
+       supplied the needed
+       <a href="https://lwn.net/Articles/376011/">patch series</a>.
+<li>   Kernels built with <tt>CONFIG_DEBUG_OBJECTS_RCU_HEAD=y</tt>
+       will splat if a data element is passed to <tt>call_rcu()</tt>
+       twice in a row, without a grace period in between.
+       (This error is similar to a double free.)
+       The corresponding <tt>rcu_head</tt> structures that are
+       dynamically allocated are automatically tracked, but
+       <tt>rcu_head</tt> structures allocated on the stack
+       must be initialized with <tt>init_rcu_head_on_stack()</tt>
+       and cleaned up with <tt>destroy_rcu_head_on_stack()</tt>.
+       Similarly, statically allocated non-stack <tt>rcu_head</tt>
+       structures must be initialized with <tt>init_rcu_head()</tt>
+       and cleaned up with <tt>destroy_rcu_head()</tt>.
+       Mathieu Desnoyers made me aware of this requirement, and also
+       supplied the needed
+       <a href="https://lkml.kernel.org/g/20100319013024.GA28456@Krystal">patch</a>.
+<li>   An infinite loop in an RCU read-side critical section will
+       eventually trigger an RCU CPU stall warning splat, with
+       the duration of &ldquo;eventually&rdquo; being controlled by the
+       <tt>RCU_CPU_STALL_TIMEOUT</tt> <tt>Kconfig</tt> option, or,
+       alternatively, by the
+       <tt>rcupdate.rcu_cpu_stall_timeout</tt> boot/sysfs
+       parameter.
+       However, RCU is not obligated to produce this splat
+       unless there is a grace period waiting on that particular
+       RCU read-side critical section.
+       <p>
+       Some extreme workloads might intentionally delay
+       RCU grace periods, and systems running those workloads can
+       be booted with <tt>rcupdate.rcu_cpu_stall_suppress</tt>
+       to suppress the splats.
+       This kernel parameter may also be set via <tt>sysfs</tt>.
+       Furthermore, RCU CPU stall warnings are counter-productive
+       during sysrq dumps and during panics.
+       RCU therefore supplies the <tt>rcu_sysrq_start()</tt> and
+       <tt>rcu_sysrq_end()</tt> API members to be called before
+       and after long sysrq dumps.
+       RCU also supplies the <tt>rcu_panic()</tt> notifier that is
+       automatically invoked at the beginning of a panic to suppress
+       further RCU CPU stall warnings.
+
+       <p>
+       This requirement made itself known in the early 1990s, pretty
+       much the first time that it was necessary to debug a CPU stall.
+       That said, the initial implementation in DYNIX/ptx was quite
+       generic in comparison with that of Linux.
+<li>   Although it would be very good to detect pointers leaking out
+       of RCU read-side critical sections, there is currently no
+       good way of doing this.
+       One complication is the need to distinguish between pointers
+       leaking and pointers that have been handed off from RCU to
+       some other synchronization mechanism, for example, reference
+       counting.
+<li>   In kernels built with <tt>CONFIG_RCU_TRACE=y</tt>, RCU-related
+       information is provided via both debugfs and event tracing.
+<li>   Open-coded use of <tt>rcu_assign_pointer()</tt> and
+       <tt>rcu_dereference()</tt> to create typical linked
+       data structures can be surprisingly error-prone.
+       Therefore, RCU-protected
+       <a href="https://lwn.net/Articles/609973/#RCU List APIs">linked lists</a>
+       and, more recently, RCU-protected
+       <a href="https://lwn.net/Articles/612100/">hash tables</a>
+       are available.
+       Many other special-purpose RCU-protected data structures are
+       available in the Linux kernel and the userspace RCU library.
+<li>   Some linked structures are created at compile time, but still
+       require <tt>__rcu</tt> checking.
+       The <tt>RCU_POINTER_INITIALIZER()</tt> macro serves this
+       purpose.
+<li>   It is not necessary to use <tt>rcu_assign_pointer()</tt>
+       when creating linked structures that are to be published via
+       a single external pointer.
+       The <tt>RCU_INIT_POINTER()</tt> macro is provided for
+       this task and also for assigning <tt>NULL</tt> pointers
+       at runtime.
+</ol>
+
+<p>
+This not a hard-and-fast list:  RCU's diagnostic capabilities will
+continue to be guided by the number and type of usage bugs found
+in real-world RCU usage.
+
+<h2><a name="Linux Kernel Complications">Linux Kernel Complications</a></h2>
+
+<p>
+The Linux kernel provides an interesting environment for all kinds of
+software, including RCU.
+Some of the relevant points of interest are as follows:
+
+<ol>
+<li>   <a href="#Configuration">Configuration</a>.
+<li>   <a href="#Firmware Interface">Firmware Interface</a>.
+<li>   <a href="#Early Boot">Early Boot</a>.
+<li>   <a href="#Interrupts and NMIs">
+       Interrupts and non-maskable interrupts (NMIs)</a>.
+<li>   <a href="#Loadable Modules">Loadable Modules</a>.
+<li>   <a href="#Hotplug CPU">Hotplug CPU</a>.
+<li>   <a href="#Scheduler and RCU">Scheduler and RCU</a>.
+<li>   <a href="#Tracing and RCU">Tracing and RCU</a>.
+<li>   <a href="#Energy Efficiency">Energy Efficiency</a>.
+<li>   <a href="#Memory Efficiency">Memory Efficiency</a>.
+<li>   <a href="#Performance, Scalability, Response Time, and Reliability">
+       Performance, Scalability, Response Time, and Reliability</a>.
+</ol>
+
+<p>
+This list is probably incomplete, but it does give a feel for the
+most notable Linux-kernel complications.
+Each of the following sections covers one of the above topics.
+
+<h3><a name="Configuration">Configuration</a></h3>
+
+<p>
+RCU's goal is automatic configuration, so that almost nobody
+needs to worry about RCU's <tt>Kconfig</tt> options.
+And for almost all users, RCU does in fact work well
+&ldquo;out of the box.&rdquo;
+
+<p>
+However, there are specialized use cases that are handled by
+kernel boot parameters and <tt>Kconfig</tt> options.
+Unfortunately, the <tt>Kconfig</tt> system will explicitly ask users
+about new <tt>Kconfig</tt> options, which requires almost all of them
+be hidden behind a <tt>CONFIG_RCU_EXPERT</tt> <tt>Kconfig</tt> option.
+
+<p>
+This all should be quite obvious, but the fact remains that
+Linus Torvalds recently had to
+<a href="https://lkml.kernel.org/g/CA+55aFy4wcCwaL4okTs8wXhGZ5h-ibecy_Meg9C4MNQrUnwMcg@mail.gmail.com">remind</a>
+me of this requirement.
+
+<h3><a name="Firmware Interface">Firmware Interface</a></h3>
+
+<p>
+In many cases, kernel obtains information about the system from the
+firmware, and sometimes things are lost in translation.
+Or the translation is accurate, but the original message is bogus.
+
+<p>
+For example, some systems' firmware overreports the number of CPUs,
+sometimes by a large factor.
+If RCU naively believed the firmware, as it used to do,
+it would create too many per-CPU kthreads.
+Although the resulting system will still run correctly, the extra
+kthreads needlessly consume memory and can cause confusion
+when they show up in <tt>ps</tt> listings.
+
+<p>
+RCU must therefore wait for a given CPU to actually come online before
+it can allow itself to believe that the CPU actually exists.
+The resulting &ldquo;ghost CPUs&rdquo; (which are never going to
+come online) cause a number of
+<a href="https://paulmck.livejournal.com/37494.html">interesting complications</a>.
+
+<h3><a name="Early Boot">Early Boot</a></h3>
+
+<p>
+The Linux kernel's boot sequence is an interesting process,
+and RCU is used early, even before <tt>rcu_init()</tt>
+is invoked.
+In fact, a number of RCU's primitives can be used as soon as the
+initial task's <tt>task_struct</tt> is available and the
+boot CPU's per-CPU variables are set up.
+The read-side primitives (<tt>rcu_read_lock()</tt>,
+<tt>rcu_read_unlock()</tt>, <tt>rcu_dereference()</tt>,
+and <tt>rcu_access_pointer()</tt>) will operate normally very early on,
+as will <tt>rcu_assign_pointer()</tt>.
+
+<p>
+Although <tt>call_rcu()</tt> may be invoked at any
+time during boot, callbacks are not guaranteed to be invoked until after
+the scheduler is fully up and running.
+This delay in callback invocation is due to the fact that RCU does not
+invoke callbacks until it is fully initialized, and this full initialization
+cannot occur until after the scheduler has initialized itself to the
+point where RCU can spawn and run its kthreads.
+In theory, it would be possible to invoke callbacks earlier,
+however, this is not a panacea because there would be severe restrictions
+on what operations those callbacks could invoke.
+
+<p>
+Perhaps surprisingly, <tt>synchronize_rcu()</tt>,
+<a href="#Bottom-Half Flavor"><tt>synchronize_rcu_bh()</tt></a>
+(<a href="#Bottom-Half Flavor">discussed below</a>),
+and
+<a href="#Sched Flavor"><tt>synchronize_sched()</tt></a>
+will all operate normally
+during very early boot, the reason being that there is only one CPU
+and preemption is disabled.
+This means that the call <tt>synchronize_rcu()</tt> (or friends)
+itself is a quiescent
+state and thus a grace period, so the early-boot implementation can
+be a no-op.
+
+<p>
+Both <tt>synchronize_rcu_bh()</tt> and <tt>synchronize_sched()</tt>
+continue to operate normally through the remainder of boot, courtesy
+of the fact that preemption is disabled across their RCU read-side
+critical sections and also courtesy of the fact that there is still
+only one CPU.
+However, once the scheduler starts initializing, preemption is enabled.
+There is still only a single CPU, but the fact that preemption is enabled
+means that the no-op implementation of <tt>synchronize_rcu()</tt> no
+longer works in <tt>CONFIG_PREEMPT=y</tt> kernels.
+Therefore, as soon as the scheduler starts initializing, the early-boot
+fastpath is disabled.
+This means that <tt>synchronize_rcu()</tt> switches to its runtime
+mode of operation where it posts callbacks, which in turn means that
+any call to <tt>synchronize_rcu()</tt> will block until the corresponding
+callback is invoked.
+Unfortunately, the callback cannot be invoked until RCU's runtime
+grace-period machinery is up and running, which cannot happen until
+the scheduler has initialized itself sufficiently to allow RCU's
+kthreads to be spawned.
+Therefore, invoking <tt>synchronize_rcu()</tt> during scheduler
+initialization can result in deadlock.
+
+<p><a name="Quick Quiz 14"><b>Quick Quiz 14</b>:</a>
+So what happens with <tt>synchronize_rcu()</tt> during
+scheduler initialization for <tt>CONFIG_PREEMPT=n</tt>
+kernels?
+<br><a href="#qq14answer">Answer</a>
+
+<p>
+I learned of these boot-time requirements as a result of a series of
+system hangs.
+
+<h3><a name="Interrupts and NMIs">Interrupts and NMIs</a></h3>
+
+<p>
+The Linux kernel has interrupts, and RCU read-side critical sections are
+legal within interrupt handlers and within interrupt-disabled regions
+of code, as are invocations of <tt>call_rcu()</tt>.
+
+<p>
+Some Linux-kernel architectures can enter an interrupt handler from
+non-idle process context, and then just never leave it, instead stealthily
+transitioning back to process context.
+This trick is sometimes used to invoke system calls from inside the kernel.
+These &ldquo;half-interrupts&rdquo; mean that RCU has to be very careful
+about how it counts interrupt nesting levels.
+I learned of this requirement the hard way during a rewrite
+of RCU's dyntick-idle code.
+
+<p>
+The Linux kernel has non-maskable interrupts (NMIs), and
+RCU read-side critical sections are legal within NMI handlers.
+Thankfully, RCU update-side primitives, including
+<tt>call_rcu()</tt>, are prohibited within NMI handlers.
+
+<p>
+The name notwithstanding, some Linux-kernel architectures
+can have nested NMIs, which RCU must handle correctly.
+Andy Lutomirski
+<a href="https://lkml.kernel.org/g/CALCETrXLq1y7e_dKFPgou-FKHB6Pu-r8+t-6Ds+8=va7anBWDA@mail.gmail.com">surprised me</a>
+with this requirement;
+he also kindly surprised me with
+<a href="https://lkml.kernel.org/g/CALCETrXSY9JpW3uE6H8WYk81sg56qasA2aqmjMPsq5dOtzso=g@mail.gmail.com">an algorithm</a>
+that meets this requirement.
+
+<h3><a name="Loadable Modules">Loadable Modules</a></h3>
+
+<p>
+The Linux kernel has loadable modules, and these modules can
+also be unloaded.
+After a given module has been unloaded, any attempt to call
+one of its functions results in a segmentation fault.
+The module-unload functions must therefore cancel any
+delayed calls to loadable-module functions, for example,
+any outstanding <tt>mod_timer()</tt> must be dealt with
+via <tt>del_timer_sync()</tt> or similar.
+
+<p>
+Unfortunately, there is no way to cancel an RCU callback;
+once you invoke <tt>call_rcu()</tt>, the callback function is
+going to eventually be invoked, unless the system goes down first.
+Because it is normally considered socially irresponsible to crash the system
+in response to a module unload request, we need some other way
+to deal with in-flight RCU callbacks.
+
+<p>
+RCU therefore provides
+<tt><a href="https://lwn.net/Articles/217484/">rcu_barrier()</a></tt>,
+which waits until all in-flight RCU callbacks have been invoked.
+If a module uses <tt>call_rcu()</tt>, its exit function should therefore
+prevent any future invocation of <tt>call_rcu()</tt>, then invoke
+<tt>rcu_barrier()</tt>.
+In theory, the underlying module-unload code could invoke
+<tt>rcu_barrier()</tt> unconditionally, but in practice this would
+incur unacceptable latencies.
+
+<p>
+Nikita Danilov noted this requirement for an analogous filesystem-unmount
+situation, and Dipankar Sarma incorporated <tt>rcu_barrier()</tt> into RCU.
+The need for <tt>rcu_barrier()</tt> for module unloading became
+apparent later.
+
+<h3><a name="Hotplug CPU">Hotplug CPU</a></h3>
+
+<p>
+The Linux kernel supports CPU hotplug, which means that CPUs
+can come and go.
+It is of course illegal to use any RCU API member from an offline CPU.
+This requirement was present from day one in DYNIX/ptx, but
+on the other hand, the Linux kernel's CPU-hotplug implementation
+is &ldquo;interesting.&rdquo;
+
+<p>
+The Linux-kernel CPU-hotplug implementation has notifiers that
+are used to allow the various kernel subsystems (including RCU)
+to respond appropriately to a given CPU-hotplug operation.
+Most RCU operations may be invoked from CPU-hotplug notifiers,
+including even normal synchronous grace-period operations
+such as <tt>synchronize_rcu()</tt>.
+However, expedited grace-period operations such as
+<tt>synchronize_rcu_expedited()</tt> are not supported,
+due to the fact that current implementations block CPU-hotplug
+operations, which could result in deadlock.
+
+<p>
+In addition, all-callback-wait operations such as
+<tt>rcu_barrier()</tt> are also not supported, due to the
+fact that there are phases of CPU-hotplug operations where
+the outgoing CPU's callbacks will not be invoked until after
+the CPU-hotplug operation ends, which could also result in deadlock.
+
+<h3><a name="Scheduler and RCU">Scheduler and RCU</a></h3>
+
+<p>
+RCU depends on the scheduler, and the scheduler uses RCU to
+protect some of its data structures.
+This means the scheduler is forbidden from acquiring
+the runqueue locks and the priority-inheritance locks
+in the middle of an outermost RCU read-side critical section unless either
+(1)&nbsp;it releases them before exiting that same
+RCU read-side critical section, or
+(2)&nbsp;interrupts are disabled across
+that entire RCU read-side critical section.
+This same prohibition also applies (recursively!) to any lock that is acquired
+while holding any lock to which this prohibition applies.
+Adhering to this rule prevents preemptible RCU from invoking
+<tt>rcu_read_unlock_special()</tt> while either runqueue or
+priority-inheritance locks are held, thus avoiding deadlock.
+
+<p>
+Prior to v4.4, it was only necessary to disable preemption across
+RCU read-side critical sections that acquired scheduler locks.
+In v4.4, expedited grace periods started using IPIs, and these
+IPIs could force a <tt>rcu_read_unlock()</tt> to take the slowpath.
+Therefore, this expedited-grace-period change required disabling of
+interrupts, not just preemption.
+
+<p>
+For RCU's part, the preemptible-RCU <tt>rcu_read_unlock()</tt>
+implementation must be written carefully to avoid similar deadlocks.
+In particular, <tt>rcu_read_unlock()</tt> must tolerate an
+interrupt where the interrupt handler invokes both
+<tt>rcu_read_lock()</tt> and <tt>rcu_read_unlock()</tt>.
+This possibility requires <tt>rcu_read_unlock()</tt> to use
+negative nesting levels to avoid destructive recursion via
+interrupt handler's use of RCU.
+
+<p>
+This pair of mutual scheduler-RCU requirements came as a
+<a href="https://lwn.net/Articles/453002/">complete surprise</a>.
+
+<p>
+As noted above, RCU makes use of kthreads, and it is necessary to
+avoid excessive CPU-time accumulation by these kthreads.
+This requirement was no surprise, but RCU's violation of it
+when running context-switch-heavy workloads when built with
+<tt>CONFIG_NO_HZ_FULL=y</tt>
+<a href="http://www.rdrop.com/users/paulmck/scalability/paper/BareMetal.2015.01.15b.pdf">did come as a surprise [PDF]</a>.
+RCU has made good progress towards meeting this requirement, even
+for context-switch-have <tt>CONFIG_NO_HZ_FULL=y</tt> workloads,
+but there is room for further improvement.
+
+<h3><a name="Tracing and RCU">Tracing and RCU</a></h3>
+
+<p>
+It is possible to use tracing on RCU code, but tracing itself
+uses RCU.
+For this reason, <tt>rcu_dereference_raw_notrace()</tt>
+is provided for use by tracing, which avoids the destructive
+recursion that could otherwise ensue.
+This API is also used by virtualization in some architectures,
+where RCU readers execute in environments in which tracing
+cannot be used.
+The tracing folks both located the requirement and provided the
+needed fix, so this surprise requirement was relatively painless.
+
+<h3><a name="Energy Efficiency">Energy Efficiency</a></h3>
+
+<p>
+Interrupting idle CPUs is considered socially unacceptable,
+especially by people with battery-powered embedded systems.
+RCU therefore conserves energy by detecting which CPUs are
+idle, including tracking CPUs that have been interrupted from idle.
+This is a large part of the energy-efficiency requirement,
+so I learned of this via an irate phone call.
+
+<p>
+Because RCU avoids interrupting idle CPUs, it is illegal to
+execute an RCU read-side critical section on an idle CPU.
+(Kernels built with <tt>CONFIG_PROVE_RCU=y</tt> will splat
+if you try it.)
+The <tt>RCU_NONIDLE()</tt> macro and <tt>_rcuidle</tt>
+event tracing is provided to work around this restriction.
+In addition, <tt>rcu_is_watching()</tt> may be used to
+test whether or not it is currently legal to run RCU read-side
+critical sections on this CPU.
+I learned of the need for diagnostics on the one hand
+and <tt>RCU_NONIDLE()</tt> on the other while inspecting
+idle-loop code.
+Steven Rostedt supplied <tt>_rcuidle</tt> event tracing,
+which is used quite heavily in the idle loop.
+
+<p>
+It is similarly socially unacceptable to interrupt an
+<tt>nohz_full</tt> CPU running in userspace.
+RCU must therefore track <tt>nohz_full</tt> userspace
+execution.
+And in
+<a href="https://lwn.net/Articles/558284/"><tt>CONFIG_NO_HZ_FULL_SYSIDLE=y</tt></a>
+kernels, RCU must separately track idle CPUs on the one hand and
+CPUs that are either idle or executing in userspace on the other.
+In both cases, RCU must be able to sample state at two points in
+time, and be able to determine whether or not some other CPU spent
+any time idle and/or executing in userspace.
+
+<p>
+These energy-efficiency requirements have proven quite difficult to
+understand and to meet, for example, there have been more than five
+clean-sheet rewrites of RCU's energy-efficiency code, the last of
+which was finally able to demonstrate
+<a href="http://www.rdrop.com/users/paulmck/realtime/paper/AMPenergy.2013.04.19a.pdf">real energy savings running on real hardware [PDF]</a>.
+As noted earlier,
+I learned of many of these requirements via angry phone calls:
+Flaming me on the Linux-kernel mailing list was apparently not
+sufficient to fully vent their ire at RCU's energy-efficiency bugs!
+
+<h3><a name="Memory Efficiency">Memory Efficiency</a></h3>
+
+<p>
+Although small-memory non-realtime systems can simply use Tiny RCU,
+code size is only one aspect of memory efficiency.
+Another aspect is the size of the <tt>rcu_head</tt> structure
+used by <tt>call_rcu()</tt> and <tt>kfree_rcu()</tt>.
+Although this structure contains nothing more than a pair of pointers,
+it does appear in many RCU-protected data structures, including
+some that are size critical.
+The <tt>page</tt> structure is a case in point, as evidenced by
+the many occurrences of the <tt>union</tt> keyword within that structure.
+
+<p>
+This need for memory efficiency is one reason that RCU uses hand-crafted
+singly linked lists to track the <tt>rcu_head</tt> structures that
+are waiting for a grace period to elapse.
+It is also the reason why <tt>rcu_head</tt> structures do not contain
+debug information, such as fields tracking the file and line of the
+<tt>call_rcu()</tt> or <tt>kfree_rcu()</tt> that posted them.
+Although this information might appear in debug-only kernel builds at some
+point, in the meantime, the <tt>-&gt;func</tt> field will often provide
+the needed debug information.
+
+<p>
+However, in some cases, the need for memory efficiency leads to even
+more extreme measures.
+Returning to the <tt>page</tt> structure, the <tt>rcu_head</tt> field
+shares storage with a great many other structures that are used at
+various points in the corresponding page's lifetime.
+In order to correctly resolve certain
+<a href="https://lkml.kernel.org/g/1439976106-137226-1-git-send-email-kirill.shutemov@linux.intel.com">race conditions</a>,
+the Linux kernel's memory-management subsystem needs a particular bit
+to remain zero during all phases of grace-period processing,
+and that bit happens to map to the bottom bit of the
+<tt>rcu_head</tt> structure's <tt>-&gt;next</tt> field.
+RCU makes this guarantee as long as <tt>call_rcu()</tt>
+is used to post the callback, as opposed to <tt>kfree_rcu()</tt>
+or some future &ldquo;lazy&rdquo;
+variant of <tt>call_rcu()</tt> that might one day be created for
+energy-efficiency purposes.
+
+<h3><a name="Performance, Scalability, Response Time, and Reliability">
+Performance, Scalability, Response Time, and Reliability</a></h3>
+
+<p>
+Expanding on the
+<a href="#Performance and Scalability">earlier discussion</a>,
+RCU is used heavily by hot code paths in performance-critical
+portions of the Linux kernel's networking, security, virtualization,
+and scheduling code paths.
+RCU must therefore use efficient implementations, especially in its
+read-side primitives.
+To that end, it would be good if preemptible RCU's implementation
+of <tt>rcu_read_lock()</tt> could be inlined, however, doing
+this requires resolving <tt>#include</tt> issues with the
+<tt>task_struct</tt> structure.
+
+<p>
+The Linux kernel supports hardware configurations with up to
+4096 CPUs, which means that RCU must be extremely scalable.
+Algorithms that involve frequent acquisitions of global locks or
+frequent atomic operations on global variables simply cannot be
+tolerated within the RCU implementation.
+RCU therefore makes heavy use of a combining tree based on the
+<tt>rcu_node</tt> structure.
+RCU is required to tolerate all CPUs continuously invoking any
+combination of RCU's runtime primitives with minimal per-operation
+overhead.
+In fact, in many cases, increasing load must <i>decrease</i> the
+per-operation overhead, witness the batching optimizations for
+<tt>synchronize_rcu()</tt>, <tt>call_rcu()</tt>,
+<tt>synchronize_rcu_expedited()</tt>, and <tt>rcu_barrier()</tt>.
+As a general rule, RCU must cheerfully accept whatever the
+rest of the Linux kernel decides to throw at it.
+
+<p>
+The Linux kernel is used for real-time workloads, especially
+in conjunction with the
+<a href="https://rt.wiki.kernel.org/index.php/Main_Page">-rt patchset</a>.
+The real-time-latency response requirements are such that the
+traditional approach of disabling preemption across RCU
+read-side critical sections is inappropriate.
+Kernels built with <tt>CONFIG_PREEMPT=y</tt> therefore
+use an RCU implementation that allows RCU read-side critical
+sections to be preempted.
+This requirement made its presence known after users made it
+clear that an earlier
+<a href="https://lwn.net/Articles/107930/">real-time patch</a>
+did not meet their needs, in conjunction with some
+<a href="https://lkml.kernel.org/g/20050318002026.GA2693@us.ibm.com">RCU issues</a>
+encountered by a very early version of the -rt patchset.
+
+<p>
+In addition, RCU must make do with a sub-100-microsecond real-time latency
+budget.
+In fact, on smaller systems with the -rt patchset, the Linux kernel
+provides sub-20-microsecond real-time latencies for the whole kernel,
+including RCU.
+RCU's scalability and latency must therefore be sufficient for
+these sorts of configurations.
+To my surprise, the sub-100-microsecond real-time latency budget
+<a href="http://www.rdrop.com/users/paulmck/realtime/paper/bigrt.2013.01.31a.LCA.pdf">
+applies to even the largest systems [PDF]</a>,
+up to and including systems with 4096 CPUs.
+This real-time requirement motivated the grace-period kthread, which
+also simplified handling of a number of race conditions.
+
+<p>
+Finally, RCU's status as a synchronization primitive means that
+any RCU failure can result in arbitrary memory corruption that can be
+extremely difficult to debug.
+This means that RCU must be extremely reliable, which in
+practice also means that RCU must have an aggressive stress-test
+suite.
+This stress-test suite is called <tt>rcutorture</tt>.
+
+<p>
+Although the need for <tt>rcutorture</tt> was no surprise,
+the current immense popularity of the Linux kernel is posing
+interesting&mdash;and perhaps unprecedented&mdash;validation
+challenges.
+To see this, keep in mind that there are well over one billion
+instances of the Linux kernel running today, given Android
+smartphones, Linux-powered televisions, and servers.
+This number can be expected to increase sharply with the advent of
+the celebrated Internet of Things.
+
+<p>
+Suppose that RCU contains a race condition that manifests on average
+once per million years of runtime.
+This bug will be occurring about three times per <i>day</i> across
+the installed base.
+RCU could simply hide behind hardware error rates, given that no one
+should really expect their smartphone to last for a million years.
+However, anyone taking too much comfort from this thought should
+consider the fact that in most jurisdictions, a successful multi-year
+test of a given mechanism, which might include a Linux kernel,
+suffices for a number of types of safety-critical certifications.
+In fact, rumor has it that the Linux kernel is already being used
+in production for safety-critical applications.
+I don't know about you, but I would feel quite bad if a bug in RCU
+killed someone.
+Which might explain my recent focus on validation and verification.
+
+<h2><a name="Other RCU Flavors">Other RCU Flavors</a></h2>
+
+<p>
+One of the more surprising things about RCU is that there are now
+no fewer than five <i>flavors</i>, or API families.
+In addition, the primary flavor that has been the sole focus up to
+this point has two different implementations, non-preemptible and
+preemptible.
+The other four flavors are listed below, with requirements for each
+described in a separate section.
+
+<ol>
+<li>   <a href="#Bottom-Half Flavor">Bottom-Half Flavor</a>
+<li>   <a href="#Sched Flavor">Sched Flavor</a>
+<li>   <a href="#Sleepable RCU">Sleepable RCU</a>
+<li>   <a href="#Tasks RCU">Tasks RCU</a>
+</ol>
+
+<h3><a name="Bottom-Half Flavor">Bottom-Half Flavor</a></h3>
+
+<p>
+The softirq-disable (AKA &ldquo;bottom-half&rdquo;,
+hence the &ldquo;_bh&rdquo; abbreviations)
+flavor of RCU, or <i>RCU-bh</i>, was developed by
+Dipankar Sarma to provide a flavor of RCU that could withstand the
+network-based denial-of-service attacks researched by Robert
+Olsson.
+These attacks placed so much networking load on the system
+that some of the CPUs never exited softirq execution,
+which in turn prevented those CPUs from ever executing a context switch,
+which, in the RCU implementation of that time, prevented grace periods
+from ever ending.
+The result was an out-of-memory condition and a system hang.
+
+<p>
+The solution was the creation of RCU-bh, which does
+<tt>local_bh_disable()</tt>
+across its read-side critical sections, and which uses the transition
+from one type of softirq processing to another as a quiescent state
+in addition to context switch, idle, user mode, and offline.
+This means that RCU-bh grace periods can complete even when some of
+the CPUs execute in softirq indefinitely, thus allowing algorithms
+based on RCU-bh to withstand network-based denial-of-service attacks.
+
+<p>
+Because
+<tt>rcu_read_lock_bh()</tt> and <tt>rcu_read_unlock_bh()</tt>
+disable and re-enable softirq handlers, any attempt to start a softirq
+handlers during the
+RCU-bh read-side critical section will be deferred.
+In this case, <tt>rcu_read_unlock_bh()</tt>
+will invoke softirq processing, which can take considerable time.
+One can of course argue that this softirq overhead should be associated
+with the code following the RCU-bh read-side critical section rather
+than <tt>rcu_read_unlock_bh()</tt>, but the fact
+is that most profiling tools cannot be expected to make this sort
+of fine distinction.
+For example, suppose that a three-millisecond-long RCU-bh read-side
+critical section executes during a time of heavy networking load.
+There will very likely be an attempt to invoke at least one softirq
+handler during that three milliseconds, but any such invocation will
+be delayed until the time of the <tt>rcu_read_unlock_bh()</tt>.
+This can of course make it appear at first glance as if
+<tt>rcu_read_unlock_bh()</tt> was executing very slowly.
+
+<p>
+The
+<a href="https://lwn.net/Articles/609973/#RCU Per-Flavor API Table">RCU-bh API</a>
+includes
+<tt>rcu_read_lock_bh()</tt>,
+<tt>rcu_read_unlock_bh()</tt>,
+<tt>rcu_dereference_bh()</tt>,
+<tt>rcu_dereference_bh_check()</tt>,
+<tt>synchronize_rcu_bh()</tt>,
+<tt>synchronize_rcu_bh_expedited()</tt>,
+<tt>call_rcu_bh()</tt>,
+<tt>rcu_barrier_bh()</tt>, and
+<tt>rcu_read_lock_bh_held()</tt>.
+
+<h3><a name="Sched Flavor">Sched Flavor</a></h3>
+
+<p>
+Before preemptible RCU, waiting for an RCU grace period had the
+side effect of also waiting for all pre-existing interrupt
+and NMI handlers.
+However, there are legitimate preemptible-RCU implementations that
+do not have this property, given that any point in the code outside
+of an RCU read-side critical section can be a quiescent state.
+Therefore, <i>RCU-sched</i> was created, which follows &ldquo;classic&rdquo;
+RCU in that an RCU-sched grace period waits for for pre-existing
+interrupt and NMI handlers.
+In kernels built with <tt>CONFIG_PREEMPT=n</tt>, the RCU and RCU-sched
+APIs have identical implementations, while kernels built with
+<tt>CONFIG_PREEMPT=y</tt> provide a separate implementation for each.
+
+<p>
+Note well that in <tt>CONFIG_PREEMPT=y</tt> kernels,
+<tt>rcu_read_lock_sched()</tt> and <tt>rcu_read_unlock_sched()</tt>
+disable and re-enable preemption, respectively.
+This means that if there was a preemption attempt during the
+RCU-sched read-side critical section, <tt>rcu_read_unlock_sched()</tt>
+will enter the scheduler, with all the latency and overhead entailed.
+Just as with <tt>rcu_read_unlock_bh()</tt>, this can make it look
+as if <tt>rcu_read_unlock_sched()</tt> was executing very slowly.
+However, the highest-priority task won't be preempted, so that task
+will enjoy low-overhead <tt>rcu_read_unlock_sched()</tt> invocations.
+
+<p>
+The
+<a href="https://lwn.net/Articles/609973/#RCU Per-Flavor API Table">RCU-sched API</a>
+includes
+<tt>rcu_read_lock_sched()</tt>,
+<tt>rcu_read_unlock_sched()</tt>,
+<tt>rcu_read_lock_sched_notrace()</tt>,
+<tt>rcu_read_unlock_sched_notrace()</tt>,
+<tt>rcu_dereference_sched()</tt>,
+<tt>rcu_dereference_sched_check()</tt>,
+<tt>synchronize_sched()</tt>,
+<tt>synchronize_rcu_sched_expedited()</tt>,
+<tt>call_rcu_sched()</tt>,
+<tt>rcu_barrier_sched()</tt>, and
+<tt>rcu_read_lock_sched_held()</tt>.
+However, anything that disables preemption also marks an RCU-sched
+read-side critical section, including
+<tt>preempt_disable()</tt> and <tt>preempt_enable()</tt>,
+<tt>local_irq_save()</tt> and <tt>local_irq_restore()</tt>,
+and so on.
+
+<h3><a name="Sleepable RCU">Sleepable RCU</a></h3>
+
+<p>
+For well over a decade, someone saying &ldquo;I need to block within
+an RCU read-side critical section&rdquo; was a reliable indication
+that this someone did not understand RCU.
+After all, if you are always blocking in an RCU read-side critical
+section, you can probably afford to use a higher-overhead synchronization
+mechanism.
+However, that changed with the advent of the Linux kernel's notifiers,
+whose RCU read-side critical
+sections almost never sleep, but sometimes need to.
+This resulted in the introduction of
+<a href="https://lwn.net/Articles/202847/">sleepable RCU</a>,
+or <i>SRCU</i>.
+
+<p>
+SRCU allows different domains to be defined, with each such domain
+defined by an instance of an <tt>srcu_struct</tt> structure.
+A pointer to this structure must be passed in to each SRCU function,
+for example, <tt>synchronize_srcu(&amp;ss)</tt>, where
+<tt>ss</tt> is the <tt>srcu_struct</tt> structure.
+The key benefit of these domains is that a slow SRCU reader in one
+domain does not delay an SRCU grace period in some other domain.
+That said, one consequence of these domains is that read-side code
+must pass a &ldquo;cookie&rdquo; from <tt>srcu_read_lock()</tt>
+to <tt>srcu_read_unlock()</tt>, for example, as follows:
+
+<blockquote>
+<pre>
+ 1 int idx;
+ 2
+ 3 idx = srcu_read_lock(&amp;ss);
+ 4 do_something();
+ 5 srcu_read_unlock(&amp;ss, idx);
+</pre>
+</blockquote>
+
+<p>
+As noted above, it is legal to block within SRCU read-side critical sections,
+however, with great power comes great responsibility.
+If you block forever in one of a given domain's SRCU read-side critical
+sections, then that domain's grace periods will also be blocked forever.
+Of course, one good way to block forever is to deadlock, which can
+happen if any operation in a given domain's SRCU read-side critical
+section can block waiting, either directly or indirectly, for that domain's
+grace period to elapse.
+For example, this results in a self-deadlock:
+
+<blockquote>
+<pre>
+ 1 int idx;
+ 2
+ 3 idx = srcu_read_lock(&amp;ss);
+ 4 do_something();
+ 5 synchronize_srcu(&amp;ss);
+ 6 srcu_read_unlock(&amp;ss, idx);
+</pre>
+</blockquote>
+
+<p>
+However, if line&nbsp;5 acquired a mutex that was held across
+a <tt>synchronize_srcu()</tt> for domain <tt>ss</tt>,
+deadlock would still be possible.
+Furthermore, if line&nbsp;5 acquired a mutex that was held across
+a <tt>synchronize_srcu()</tt> for some other domain <tt>ss1</tt>,
+and if an <tt>ss1</tt>-domain SRCU read-side critical section
+acquired another mutex that was held across as <tt>ss</tt>-domain
+<tt>synchronize_srcu()</tt>,
+deadlock would again be possible.
+Such a deadlock cycle could extend across an arbitrarily large number
+of different SRCU domains.
+Again, with great power comes great responsibility.
+
+<p>
+Unlike the other RCU flavors, SRCU read-side critical sections can
+run on idle and even offline CPUs.
+This ability requires that <tt>srcu_read_lock()</tt> and
+<tt>srcu_read_unlock()</tt> contain memory barriers, which means
+that SRCU readers will run a bit slower than would RCU readers.
+It also motivates the <tt>smp_mb__after_srcu_read_unlock()</tt>
+API, which, in combination with <tt>srcu_read_unlock()</tt>,
+guarantees a full memory barrier.
+
+<p>
+The
+<a href="https://lwn.net/Articles/609973/#RCU Per-Flavor API Table">SRCU API</a>
+includes
+<tt>srcu_read_lock()</tt>,
+<tt>srcu_read_unlock()</tt>,
+<tt>srcu_dereference()</tt>,
+<tt>srcu_dereference_check()</tt>,
+<tt>synchronize_srcu()</tt>,
+<tt>synchronize_srcu_expedited()</tt>,
+<tt>call_srcu()</tt>,
+<tt>srcu_barrier()</tt>, and
+<tt>srcu_read_lock_held()</tt>.
+It also includes
+<tt>DEFINE_SRCU()</tt>,
+<tt>DEFINE_STATIC_SRCU()</tt>, and
+<tt>init_srcu_struct()</tt>
+APIs for defining and initializing <tt>srcu_struct</tt> structures.
+
+<h3><a name="Tasks RCU">Tasks RCU</a></h3>
+
+<p>
+Some forms of tracing use &ldquo;tramopolines&rdquo; to handle the
+binary rewriting required to install different types of probes.
+It would be good to be able to free old trampolines, which sounds
+like a job for some form of RCU.
+However, because it is necessary to be able to install a trace
+anywhere in the code, it is not possible to use read-side markers
+such as <tt>rcu_read_lock()</tt> and <tt>rcu_read_unlock()</tt>.
+In addition, it does not work to have these markers in the trampoline
+itself, because there would need to be instructions following
+<tt>rcu_read_unlock()</tt>.
+Although <tt>synchronize_rcu()</tt> would guarantee that execution
+reached the <tt>rcu_read_unlock()</tt>, it would not be able to
+guarantee that execution had completely left the trampoline.
+
+<p>
+The solution, in the form of
+<a href="https://lwn.net/Articles/607117/"><i>Tasks RCU</i></a>,
+is to have implicit
+read-side critical sections that are delimited by voluntary context
+switches, that is, calls to <tt>schedule()</tt>,
+<tt>cond_resched_rcu_qs()</tt>, and
+<tt>synchronize_rcu_tasks()</tt>.
+In addition, transitions to and from userspace execution also delimit
+tasks-RCU read-side critical sections.
+
+<p>
+The tasks-RCU API is quite compact, consisting only of
+<tt>call_rcu_tasks()</tt>,
+<tt>synchronize_rcu_tasks()</tt>, and
+<tt>rcu_barrier_tasks()</tt>.
+
+<h2><a name="Possible Future Changes">Possible Future Changes</a></h2>
+
+<p>
+One of the tricks that RCU uses to attain update-side scalability is
+to increase grace-period latency with increasing numbers of CPUs.
+If this becomes a serious problem, it will be necessary to rework the
+grace-period state machine so as to avoid the need for the additional
+latency.
+
+<p>
+Expedited grace periods scan the CPUs, so their latency and overhead
+increases with increasing numbers of CPUs.
+If this becomes a serious problem on large systems, it will be necessary
+to do some redesign to avoid this scalability problem.
+
+<p>
+RCU disables CPU hotplug in a few places, perhaps most notably in the
+expedited grace-period and <tt>rcu_barrier()</tt> operations.
+If there is a strong reason to use expedited grace periods in CPU-hotplug
+notifiers, it will be necessary to avoid disabling CPU hotplug.
+This would introduce some complexity, so there had better be a <i>very</i>
+good reason.
+
+<p>
+The tradeoff between grace-period latency on the one hand and interruptions
+of other CPUs on the other hand may need to be re-examined.
+The desire is of course for zero grace-period latency as well as zero
+interprocessor interrupts undertaken during an expedited grace period
+operation.
+While this ideal is unlikely to be achievable, it is quite possible that
+further improvements can be made.
+
+<p>
+The multiprocessor implementations of RCU use a combining tree that
+groups CPUs so as to reduce lock contention and increase cache locality.
+However, this combining tree does not spread its memory across NUMA
+nodes nor does it align the CPU groups with hardware features such
+as sockets or cores.
+Such spreading and alignment is currently believed to be unnecessary
+because the hotpath read-side primitives do not access the combining
+tree, nor does <tt>call_rcu()</tt> in the common case.
+If you believe that your architecture needs such spreading and alignment,
+then your architecture should also benefit from the
+<tt>rcutree.rcu_fanout_leaf</tt> boot parameter, which can be set
+to the number of CPUs in a socket, NUMA node, or whatever.
+If the number of CPUs is too large, use a fraction of the number of
+CPUs.
+If the number of CPUs is a large prime number, well, that certainly
+is an &ldquo;interesting&rdquo; architectural choice!
+More flexible arrangements might be considered, but only if
+<tt>rcutree.rcu_fanout_leaf</tt> has proven inadequate, and only
+if the inadequacy has been demonstrated by a carefully run and
+realistic system-level workload.
+
+<p>
+Please note that arrangements that require RCU to remap CPU numbers will
+require extremely good demonstration of need and full exploration of
+alternatives.
+
+<p>
+There is an embarrassingly large number of flavors of RCU, and this
+number has been increasing over time.
+Perhaps it will be possible to combine some at some future date.
+
+<p>
+RCU's various kthreads are reasonably recent additions.
+It is quite likely that adjustments will be required to more gracefully
+handle extreme loads.
+It might also be necessary to be able to relate CPU utilization by
+RCU's kthreads and softirq handlers to the code that instigated this
+CPU utilization.
+For example, RCU callback overhead might be charged back to the
+originating <tt>call_rcu()</tt> instance, though probably not
+in production kernels.
+
+<h2><a name="Summary">Summary</a></h2>
+
+<p>
+This document has presented more than two decade's worth of RCU
+requirements.
+Given that the requirements keep changing, this will not be the last
+word on this subject, but at least it serves to get an important
+subset of the requirements set forth.
+
+<h2><a name="Acknowledgments">Acknowledgments</a></h2>
+
+I am grateful to Steven Rostedt, Lai Jiangshan, Ingo Molnar,
+Oleg Nesterov, Borislav Petkov, Peter Zijlstra, Boqun Feng, and
+Andy Lutomirski for their help in rendering
+this article human readable, and to Michelle Rankin for her support
+of this effort.
+Other contributions are acknowledged in the Linux kernel's git archive.
+The cartoon is copyright (c) 2013 by Melissa Broussard,
+and is provided
+under the terms of the Creative Commons Attribution-Share Alike 3.0
+United States license.
+
+<h3><a name="Answers to Quick Quizzes">
+Answers to Quick Quizzes</a></h3>
+
+<a name="qq1answer"></a>
+<p><b>Quick Quiz 1</b>:
+Wait a minute!
+You said that updaters can make useful forward progress concurrently
+with readers, but pre-existing readers will block
+<tt>synchronize_rcu()</tt>!!!
+Just who are you trying to fool???
+
+
+</p><p><b>Answer</b>:
+First, if updaters do not wish to be blocked by readers, they can use
+<tt>call_rcu()</tt> or <tt>kfree_rcu()</tt>, which will
+be discussed later.
+Second, even when using <tt>synchronize_rcu()</tt>, the other
+update-side code does run concurrently with readers, whether pre-existing
+or not.
+
+
+</p><p><a href="#Quick%20Quiz%201"><b>Back to Quick Quiz 1</b>.</a>
+
+<a name="qq2answer"></a>
+<p><b>Quick Quiz 2</b>:
+Why is the <tt>synchronize_rcu()</tt> on line&nbsp;28 needed?
+
+
+</p><p><b>Answer</b>:
+Without that extra grace period, memory reordering could result in
+<tt>do_something_dlm()</tt> executing <tt>do_something()</tt>
+concurrently with the last bits of <tt>recovery()</tt>.
+
+
+</p><p><a href="#Quick%20Quiz%202"><b>Back to Quick Quiz 2</b>.</a>
+
+<a name="qq3answer"></a>
+<p><b>Quick Quiz 3</b>:
+But <tt>rcu_assign_pointer()</tt> does nothing to prevent the
+two assignments to <tt>p-&gt;a</tt> and <tt>p-&gt;b</tt>
+from being reordered.
+Can't that also cause problems?
+
+
+</p><p><b>Answer</b>:
+No, it cannot.
+The readers cannot see either of these two fields until
+the assignment to <tt>gp</tt>, by which time both fields are
+fully initialized.
+So reordering the assignments
+to <tt>p-&gt;a</tt> and <tt>p-&gt;b</tt> cannot possibly
+cause any problems.
+
+
+</p><p><a href="#Quick%20Quiz%203"><b>Back to Quick Quiz 3</b>.</a>
+
+<a name="qq4answer"></a>
+<p><b>Quick Quiz 4</b>:
+Without the <tt>rcu_dereference()</tt> or the
+<tt>rcu_access_pointer()</tt>, what destructive optimizations
+might the compiler make use of?
+
+
+</p><p><b>Answer</b>:
+Let's start with what happens to <tt>do_something_gp()</tt>
+if it fails to use <tt>rcu_dereference()</tt>.
+It could reuse a value formerly fetched from this same pointer.
+It could also fetch the pointer from <tt>gp</tt> in a byte-at-a-time
+manner, resulting in <i>load tearing</i>, in turn resulting a bytewise
+mash-up of two distince pointer values.
+It might even use value-speculation optimizations, where it makes a wrong
+guess, but by the time it gets around to checking the value, an update
+has changed the pointer to match the wrong guess.
+Too bad about any dereferences that returned pre-initialization garbage
+in the meantime!
+
+<p>
+For <tt>remove_gp_synchronous()</tt>, as long as all modifications
+to <tt>gp</tt> are carried out while holding <tt>gp_lock</tt>,
+the above optimizations are harmless.
+However,
+with <tt>CONFIG_SPARSE_RCU_POINTER=y</tt>,
+<tt>sparse</tt> will complain if you
+define <tt>gp</tt> with <tt>__rcu</tt> and then
+access it without using
+either <tt>rcu_access_pointer()</tt> or <tt>rcu_dereference()</tt>.
+
+
+</p><p><a href="#Quick%20Quiz%204"><b>Back to Quick Quiz 4</b>.</a>
+
+<a name="qq5answer"></a>
+<p><b>Quick Quiz 5</b>:
+Given that multiple CPUs can start RCU read-side critical sections
+at any time without any ordering whatsoever, how can RCU possibly tell whether
+or not a given RCU read-side critical section starts before a
+given instance of <tt>synchronize_rcu()</tt>?
+
+
+</p><p><b>Answer</b>:
+If RCU cannot tell whether or not a given
+RCU read-side critical section starts before a
+given instance of <tt>synchronize_rcu()</tt>,
+then it must assume that the RCU read-side critical section
+started first.
+In other words, a given instance of <tt>synchronize_rcu()</tt>
+can avoid waiting on a given RCU read-side critical section only
+if it can prove that <tt>synchronize_rcu()</tt> started first.
+
+
+</p><p><a href="#Quick%20Quiz%205"><b>Back to Quick Quiz 5</b>.</a>
+
+<a name="qq6answer"></a>
+<p><b>Quick Quiz 6</b>:
+The first and second guarantees require unbelievably strict ordering!
+Are all these memory barriers <i> really</i> required?
+
+
+</p><p><b>Answer</b>:
+Yes, they really are required.
+To see why the first guarantee is required, consider the following
+sequence of events:
+
+<ol>
+<li>   CPU 1: <tt>rcu_read_lock()</tt>
+<li>   CPU 1: <tt>q = rcu_dereference(gp);
+       /* Very likely to return p. */</tt>
+<li>   CPU 0: <tt>list_del_rcu(p);</tt>
+<li>   CPU 0: <tt>synchronize_rcu()</tt> starts.
+<li>   CPU 1: <tt>do_something_with(q-&gt;a);
+       /* No smp_mb(), so might happen after kfree(). */</tt>
+<li>   CPU 1: <tt>rcu_read_unlock()</tt>
+<li>   CPU 0: <tt>synchronize_rcu()</tt> returns.
+<li>   CPU 0: <tt>kfree(p);</tt>
+</ol>
+
+<p>
+Therefore, there absolutely must be a full memory barrier between the
+end of the RCU read-side critical section and the end of the
+grace period.
+
+<p>
+The sequence of events demonstrating the necessity of the second rule
+is roughly similar:
+
+<ol>
+<li>   CPU 0: <tt>list_del_rcu(p);</tt>
+<li>   CPU 0: <tt>synchronize_rcu()</tt> starts.
+<li>   CPU 1: <tt>rcu_read_lock()</tt>
+<li>   CPU 1: <tt>q = rcu_dereference(gp);
+       /* Might return p if no memory barrier. */</tt>
+<li>   CPU 0: <tt>synchronize_rcu()</tt> returns.
+<li>   CPU 0: <tt>kfree(p);</tt>
+<li>   CPU 1: <tt>do_something_with(q-&gt;a); /* Boom!!! */</tt>
+<li>   CPU 1: <tt>rcu_read_unlock()</tt>
+</ol>
+
+<p>
+And similarly, without a memory barrier between the beginning of the
+grace period and the beginning of the RCU read-side critical section,
+CPU&nbsp;1 might end up accessing the freelist.
+
+<p>
+The &ldquo;as if&rdquo; rule of course applies, so that any implementation
+that acts as if the appropriate memory barriers were in place is a
+correct implementation.
+That said, it is much easier to fool yourself into believing that you have
+adhered to the as-if rule than it is to actually adhere to it!
+
+
+</p><p><a href="#Quick%20Quiz%206"><b>Back to Quick Quiz 6</b>.</a>
+
+<a name="qq7answer"></a>
+<p><b>Quick Quiz 7</b>:
+But how does the upgrade-to-write operation exclude other readers?
+
+
+</p><p><b>Answer</b>:
+It doesn't, just like normal RCU updates, which also do not exclude
+RCU readers.
+
+
+</p><p><a href="#Quick%20Quiz%207"><b>Back to Quick Quiz 7</b>.</a>
+
+<a name="qq8answer"></a>
+<p><b>Quick Quiz 8</b>:
+Can't the compiler also reorder this code?
+
+
+</p><p><b>Answer</b>:
+No, the volatile casts in <tt>READ_ONCE()</tt> and
+<tt>WRITE_ONCE()</tt> prevent the compiler from reordering in
+this particular case.
+
+
+</p><p><a href="#Quick%20Quiz%208"><b>Back to Quick Quiz 8</b>.</a>
+
+<a name="qq9answer"></a>
+<p><b>Quick Quiz 9</b>:
+Suppose that synchronize_rcu() did wait until all readers had completed.
+Would the updater be able to rely on this?
+
+
+</p><p><b>Answer</b>:
+No.
+Even if <tt>synchronize_rcu()</tt> were to wait until
+all readers had completed, a new reader might start immediately after
+<tt>synchronize_rcu()</tt> completed.
+Therefore, the code following
+<tt>synchronize_rcu()</tt> cannot rely on there being no readers
+in any case.
+
+
+</p><p><a href="#Quick%20Quiz%209"><b>Back to Quick Quiz 9</b>.</a>
+
+<a name="qq10answer"></a>
+<p><b>Quick Quiz 10</b>:
+How long a sequence of grace periods, each separated by an RCU read-side
+critical section, would be required to partition the RCU read-side
+critical sections at the beginning and end of the chain?
+
+
+</p><p><b>Answer</b>:
+In theory, an infinite number.
+In practice, an unknown number that is sensitive to both implementation
+details and timing considerations.
+Therefore, even in practice, RCU users must abide by the theoretical rather
+than the practical answer.
+
+
+</p><p><a href="#Quick%20Quiz%2010"><b>Back to Quick Quiz 10</b>.</a>
+
+<a name="qq11answer"></a>
+<p><b>Quick Quiz 11</b>:
+What about sleeping locks?
+
+
+</p><p><b>Answer</b>:
+These are forbidden within Linux-kernel RCU read-side critical sections
+because it is not legal to place a quiescent state (in this case,
+voluntary context switch) within an RCU read-side critical section.
+However, sleeping locks may be used within userspace RCU read-side critical
+sections, and also within Linux-kernel sleepable RCU
+<a href="#Sleepable RCU">(SRCU)</a>
+read-side critical sections.
+In addition, the -rt patchset turns spinlocks into a sleeping locks so
+that the corresponding critical sections can be preempted, which
+also means that these sleeplockified spinlocks (but not other sleeping locks!)
+may be acquire within -rt-Linux-kernel RCU read-side critical sections.
+
+<p>
+Note that it <i>is</i> legal for a normal RCU read-side critical section
+to conditionally acquire a sleeping locks (as in <tt>mutex_trylock()</tt>),
+but only as long as it does not loop indefinitely attempting to
+conditionally acquire that sleeping locks.
+The key point is that things like <tt>mutex_trylock()</tt>
+either return with the mutex held, or return an error indication if
+the mutex was not immediately available.
+Either way, <tt>mutex_trylock()</tt> returns immediately without sleeping.
+
+
+</p><p><a href="#Quick%20Quiz%2011"><b>Back to Quick Quiz 11</b>.</a>
+
+<a name="qq12answer"></a>
+<p><b>Quick Quiz 12</b>:
+Why does line&nbsp;19 use <tt>rcu_access_pointer()</tt>?
+After all, <tt>call_rcu()</tt> on line&nbsp;25 stores into the
+structure, which would interact badly with concurrent insertions.
+Doesn't this mean that <tt>rcu_dereference()</tt> is required?
+
+
+</p><p><b>Answer</b>:
+Presumably the <tt>-&gt;gp_lock</tt> acquired on line&nbsp;18 excludes
+any changes, including any insertions that <tt>rcu_dereference()</tt>
+would protect against.
+Therefore, any insertions will be delayed until after <tt>-&gt;gp_lock</tt>
+is released on line&nbsp;25, which in turn means that
+<tt>rcu_access_pointer()</tt> suffices.
+
+
+</p><p><a href="#Quick%20Quiz%2012"><b>Back to Quick Quiz 12</b>.</a>
+
+<a name="qq13answer"></a>
+<p><b>Quick Quiz 13</b>:
+Earlier it was claimed that <tt>call_rcu()</tt> and
+<tt>kfree_rcu()</tt> allowed updaters to avoid being blocked
+by readers.
+But how can that be correct, given that the invocation of the callback
+and the freeing of the memory (respectively) must still wait for
+a grace period to elapse?
+
+
+</p><p><b>Answer</b>:
+We could define things this way, but keep in mind that this sort of
+definition would say that updates in garbage-collected languages
+cannot complete until the next time the garbage collector runs,
+which does not seem at all reasonable.
+The key point is that in most cases, an updater using either
+<tt>call_rcu()</tt> or <tt>kfree_rcu()</tt> can proceed to the
+next update as soon as it has invoked <tt>call_rcu()</tt> or
+<tt>kfree_rcu()</tt>, without having to wait for a subsequent
+grace period.
+
+
+</p><p><a href="#Quick%20Quiz%2013"><b>Back to Quick Quiz 13</b>.</a>
+
+<a name="qq14answer"></a>
+<p><b>Quick Quiz 14</b>:
+So what happens with <tt>synchronize_rcu()</tt> during
+scheduler initialization for <tt>CONFIG_PREEMPT=n</tt>
+kernels?
+
+
+</p><p><b>Answer</b>:
+In <tt>CONFIG_PREEMPT=n</tt> kernel, <tt>synchronize_rcu()</tt>
+maps directly to <tt>synchronize_sched()</tt>.
+Therefore, <tt>synchronize_rcu()</tt> works normally throughout
+boot in <tt>CONFIG_PREEMPT=n</tt> kernels.
+However, your code must also work in <tt>CONFIG_PREEMPT=y</tt> kernels,
+so it is still necessary to avoid invoking <tt>synchronize_rcu()</tt>
+during scheduler initialization.
+
+
+</p><p><a href="#Quick%20Quiz%2014"><b>Back to Quick Quiz 14</b>.</a>
+
+
+</body></html>
diff --git a/Documentation/RCU/Design/Requirements/Requirements.htmlx b/Documentation/RCU/Design/Requirements/Requirements.htmlx
new file mode 100644 (file)
index 0000000..3a97ba4
--- /dev/null
@@ -0,0 +1,2741 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+        "http://www.w3.org/TR/html4/loose.dtd">
+        <html>
+        <head><title>A Tour Through RCU's Requirements [LWN.net]</title>
+        <meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+
+<h1>A Tour Through RCU's Requirements</h1>
+
+<p>Copyright IBM Corporation, 2015</p>
+<p>Author: Paul E.&nbsp;McKenney</p>
+<p><i>The initial version of this document appeared in the
+<a href="https://lwn.net/">LWN</a> articles
+<a href="https://lwn.net/Articles/652156/">here</a>,
+<a href="https://lwn.net/Articles/652677/">here</a>, and
+<a href="https://lwn.net/Articles/653326/">here</a>.</i></p>
+
+<h2>Introduction</h2>
+
+<p>
+Read-copy update (RCU) is a synchronization mechanism that is often
+used as a replacement for reader-writer locking.
+RCU is unusual in that updaters do not block readers,
+which means that RCU's read-side primitives can be exceedingly fast
+and scalable.
+In addition, updaters can make useful forward progress concurrently
+with readers.
+However, all this concurrency between RCU readers and updaters does raise
+the question of exactly what RCU readers are doing, which in turn
+raises the question of exactly what RCU's requirements are.
+
+<p>
+This document therefore summarizes RCU's requirements, and can be thought
+of as an informal, high-level specification for RCU.
+It is important to understand that RCU's specification is primarily
+empirical in nature;
+in fact, I learned about many of these requirements the hard way.
+This situation might cause some consternation, however, not only
+has this learning process been a lot of fun, but it has also been
+a great privilege to work with so many people willing to apply
+technologies in interesting new ways.
+
+<p>
+All that aside, here are the categories of currently known RCU requirements:
+</p>
+
+<ol>
+<li>   <a href="#Fundamental Requirements">
+       Fundamental Requirements</a>
+<li>   <a href="#Fundamental Non-Requirements">Fundamental Non-Requirements</a>
+<li>   <a href="#Parallelism Facts of Life">
+       Parallelism Facts of Life</a>
+<li>   <a href="#Quality-of-Implementation Requirements">
+       Quality-of-Implementation Requirements</a>
+<li>   <a href="#Linux Kernel Complications">
+       Linux Kernel Complications</a>
+<li>   <a href="#Software-Engineering Requirements">
+       Software-Engineering Requirements</a>
+<li>   <a href="#Other RCU Flavors">
+       Other RCU Flavors</a>
+<li>   <a href="#Possible Future Changes">
+       Possible Future Changes</a>
+</ol>
+
+<p>
+This is followed by a <a href="#Summary">summary</a>,
+which is in turn followed by the inevitable
+<a href="#Answers to Quick Quizzes">answers to the quick quizzes</a>.
+
+<h2><a name="Fundamental Requirements">Fundamental Requirements</a></h2>
+
+<p>
+RCU's fundamental requirements are the closest thing RCU has to hard
+mathematical requirements.
+These are:
+
+<ol>
+<li>   <a href="#Grace-Period Guarantee">
+       Grace-Period Guarantee</a>
+<li>   <a href="#Publish-Subscribe Guarantee">
+       Publish-Subscribe Guarantee</a>
+<li>   <a href="#Memory-Barrier Guarantees">
+       Memory-Barrier Guarantees</a>
+<li>   <a href="#RCU Primitives Guaranteed to Execute Unconditionally">
+       RCU Primitives Guaranteed to Execute Unconditionally</a>
+<li>   <a href="#Guaranteed Read-to-Write Upgrade">
+       Guaranteed Read-to-Write Upgrade</a>
+</ol>
+
+<h3><a name="Grace-Period Guarantee">Grace-Period Guarantee</a></h3>
+
+<p>
+RCU's grace-period guarantee is unusual in being premeditated:
+Jack Slingwine and I had this guarantee firmly in mind when we started
+work on RCU (then called &ldquo;rclock&rdquo;) in the early 1990s.
+That said, the past two decades of experience with RCU have produced
+a much more detailed understanding of this guarantee.
+
+<p>
+RCU's grace-period guarantee allows updaters to wait for the completion
+of all pre-existing RCU read-side critical sections.
+An RCU read-side critical section
+begins with the marker <tt>rcu_read_lock()</tt> and ends with
+the marker <tt>rcu_read_unlock()</tt>.
+These markers may be nested, and RCU treats a nested set as one
+big RCU read-side critical section.
+Production-quality implementations of <tt>rcu_read_lock()</tt> and
+<tt>rcu_read_unlock()</tt> are extremely lightweight, and in
+fact have exactly zero overhead in Linux kernels built for production
+use with <tt>CONFIG_PREEMPT=n</tt>.
+
+<p>
+This guarantee allows ordering to be enforced with extremely low
+overhead to readers, for example:
+
+<blockquote>
+<pre>
+ 1 int x, y;
+ 2
+ 3 void thread0(void)
+ 4 {
+ 5   rcu_read_lock();
+ 6   r1 = READ_ONCE(x);
+ 7   r2 = READ_ONCE(y);
+ 8   rcu_read_unlock();
+ 9 }
+10
+11 void thread1(void)
+12 {
+13   WRITE_ONCE(x, 1);
+14   synchronize_rcu();
+15   WRITE_ONCE(y, 1);
+16 }
+</pre>
+</blockquote>
+
+<p>
+Because the <tt>synchronize_rcu()</tt> on line&nbsp;14 waits for
+all pre-existing readers, any instance of <tt>thread0()</tt> that
+loads a value of zero from <tt>x</tt> must complete before
+<tt>thread1()</tt> stores to <tt>y</tt>, so that instance must
+also load a value of zero from <tt>y</tt>.
+Similarly, any instance of <tt>thread0()</tt> that loads a value of
+one from <tt>y</tt> must have started after the
+<tt>synchronize_rcu()</tt> started, and must therefore also load
+a value of one from <tt>x</tt>.
+Therefore, the outcome:
+<blockquote>
+<pre>
+(r1 == 0 &amp;&amp; r2 == 1)
+</pre>
+</blockquote>
+cannot happen.
+
+<p>@@QQ@@
+Wait a minute!
+You said that updaters can make useful forward progress concurrently
+with readers, but pre-existing readers will block
+<tt>synchronize_rcu()</tt>!!!
+Just who are you trying to fool???
+<p>@@QQA@@
+First, if updaters do not wish to be blocked by readers, they can use
+<tt>call_rcu()</tt> or <tt>kfree_rcu()</tt>, which will
+be discussed later.
+Second, even when using <tt>synchronize_rcu()</tt>, the other
+update-side code does run concurrently with readers, whether pre-existing
+or not.
+<p>@@QQE@@
+
+<p>
+This scenario resembles one of the first uses of RCU in
+<a href="https://en.wikipedia.org/wiki/DYNIX">DYNIX/ptx</a>,
+which managed a distributed lock manager's transition into
+a state suitable for handling recovery from node failure,
+more or less as follows:
+
+<blockquote>
+<pre>
+ 1 #define STATE_NORMAL        0
+ 2 #define STATE_WANT_RECOVERY 1
+ 3 #define STATE_RECOVERING    2
+ 4 #define STATE_WANT_NORMAL   3
+ 5
+ 6 int state = STATE_NORMAL;
+ 7
+ 8 void do_something_dlm(void)
+ 9 {
+10   int state_snap;
+11
+12   rcu_read_lock();
+13   state_snap = READ_ONCE(state);
+14   if (state_snap == STATE_NORMAL)
+15     do_something();
+16   else
+17     do_something_carefully();
+18   rcu_read_unlock();
+19 }
+20
+21 void start_recovery(void)
+22 {
+23   WRITE_ONCE(state, STATE_WANT_RECOVERY);
+24   synchronize_rcu();
+25   WRITE_ONCE(state, STATE_RECOVERING);
+26   recovery();
+27   WRITE_ONCE(state, STATE_WANT_NORMAL);
+28   synchronize_rcu();
+29   WRITE_ONCE(state, STATE_NORMAL);
+30 }
+</pre>
+</blockquote>
+
+<p>
+The RCU read-side critical section in <tt>do_something_dlm()</tt>
+works with the <tt>synchronize_rcu()</tt> in <tt>start_recovery()</tt>
+to guarantee that <tt>do_something()</tt> never runs concurrently
+with <tt>recovery()</tt>, but with little or no synchronization
+overhead in <tt>do_something_dlm()</tt>.
+
+<p>@@QQ@@
+Why is the <tt>synchronize_rcu()</tt> on line&nbsp;28 needed?
+<p>@@QQA@@
+Without that extra grace period, memory reordering could result in
+<tt>do_something_dlm()</tt> executing <tt>do_something()</tt>
+concurrently with the last bits of <tt>recovery()</tt>.
+<p>@@QQE@@
+
+<p>
+In order to avoid fatal problems such as deadlocks,
+an RCU read-side critical section must not contain calls to
+<tt>synchronize_rcu()</tt>.
+Similarly, an RCU read-side critical section must not
+contain anything that waits, directly or indirectly, on completion of
+an invocation of <tt>synchronize_rcu()</tt>.
+
+<p>
+Although RCU's grace-period guarantee is useful in and of itself, with
+<a href="https://lwn.net/Articles/573497/">quite a few use cases</a>,
+it would be good to be able to use RCU to coordinate read-side
+access to linked data structures.
+For this, the grace-period guarantee is not sufficient, as can
+be seen in function <tt>add_gp_buggy()</tt> below.
+We will look at the reader's code later, but in the meantime, just think of
+the reader as locklessly picking up the <tt>gp</tt> pointer,
+and, if the value loaded is non-<tt>NULL</tt>, locklessly accessing the
+<tt>-&gt;a</tt> and <tt>-&gt;b</tt> fields.
+
+<blockquote>
+<pre>
+ 1 bool add_gp_buggy(int a, int b)
+ 2 {
+ 3   p = kmalloc(sizeof(*p), GFP_KERNEL);
+ 4   if (!p)
+ 5     return -ENOMEM;
+ 6   spin_lock(&amp;gp_lock);
+ 7   if (rcu_access_pointer(gp)) {
+ 8     spin_unlock(&amp;gp_lock);
+ 9     return false;
+10   }
+11   p-&gt;a = a;
+12   p-&gt;b = a;
+13   gp = p; /* ORDERING BUG */
+14   spin_unlock(&amp;gp_lock);
+15   return true;
+16 }
+</pre>
+</blockquote>
+
+<p>
+The problem is that both the compiler and weakly ordered CPUs are within
+their rights to reorder this code as follows:
+
+<blockquote>
+<pre>
+ 1 bool add_gp_buggy_optimized(int a, int b)
+ 2 {
+ 3   p = kmalloc(sizeof(*p), GFP_KERNEL);
+ 4   if (!p)
+ 5     return -ENOMEM;
+ 6   spin_lock(&amp;gp_lock);
+ 7   if (rcu_access_pointer(gp)) {
+ 8     spin_unlock(&amp;gp_lock);
+ 9     return false;
+10   }
+<b>11   gp = p; /* ORDERING BUG */
+12   p-&gt;a = a;
+13   p-&gt;b = a;</b>
+14   spin_unlock(&amp;gp_lock);
+15   return true;
+16 }
+</pre>
+</blockquote>
+
+<p>
+If an RCU reader fetches <tt>gp</tt> just after
+<tt>add_gp_buggy_optimized</tt> executes line&nbsp;11,
+it will see garbage in the <tt>-&gt;a</tt> and <tt>-&gt;b</tt>
+fields.
+And this is but one of many ways in which compiler and hardware optimizations
+could cause trouble.
+Therefore, we clearly need some way to prevent the compiler and the CPU from
+reordering in this manner, which brings us to the publish-subscribe
+guarantee discussed in the next section.
+
+<h3><a name="Publish-Subscribe Guarantee">Publish/Subscribe Guarantee</a></h3>
+
+<p>
+RCU's publish-subscribe guarantee allows data to be inserted
+into a linked data structure without disrupting RCU readers.
+The updater uses <tt>rcu_assign_pointer()</tt> to insert the
+new data, and readers use <tt>rcu_dereference()</tt> to
+access data, whether new or old.
+The following shows an example of insertion:
+
+<blockquote>
+<pre>
+ 1 bool add_gp(int a, int b)
+ 2 {
+ 3   p = kmalloc(sizeof(*p), GFP_KERNEL);
+ 4   if (!p)
+ 5     return -ENOMEM;
+ 6   spin_lock(&amp;gp_lock);
+ 7   if (rcu_access_pointer(gp)) {
+ 8     spin_unlock(&amp;gp_lock);
+ 9     return false;
+10   }
+11   p-&gt;a = a;
+12   p-&gt;b = a;
+13   rcu_assign_pointer(gp, p);
+14   spin_unlock(&amp;gp_lock);
+15   return true;
+16 }
+</pre>
+</blockquote>
+
+<p>
+The <tt>rcu_assign_pointer()</tt> on line&nbsp;13 is conceptually
+equivalent to a simple assignment statement, but also guarantees
+that its assignment will
+happen after the two assignments in lines&nbsp;11 and&nbsp;12,
+similar to the C11 <tt>memory_order_release</tt> store operation.
+It also prevents any number of &ldquo;interesting&rdquo; compiler
+optimizations, for example, the use of <tt>gp</tt> as a scratch
+location immediately preceding the assignment.
+
+<p>@@QQ@@
+But <tt>rcu_assign_pointer()</tt> does nothing to prevent the
+two assignments to <tt>p-&gt;a</tt> and <tt>p-&gt;b</tt>
+from being reordered.
+Can't that also cause problems?
+<p>@@QQA@@
+No, it cannot.
+The readers cannot see either of these two fields until
+the assignment to <tt>gp</tt>, by which time both fields are
+fully initialized.
+So reordering the assignments
+to <tt>p-&gt;a</tt> and <tt>p-&gt;b</tt> cannot possibly
+cause any problems.
+<p>@@QQE@@
+
+<p>
+It is tempting to assume that the reader need not do anything special
+to control its accesses to the RCU-protected data,
+as shown in <tt>do_something_gp_buggy()</tt> below:
+
+<blockquote>
+<pre>
+ 1 bool do_something_gp_buggy(void)
+ 2 {
+ 3   rcu_read_lock();
+ 4   p = gp;  /* OPTIMIZATIONS GALORE!!! */
+ 5   if (p) {
+ 6     do_something(p-&gt;a, p-&gt;b);
+ 7     rcu_read_unlock();
+ 8     return true;
+ 9   }
+10   rcu_read_unlock();
+11   return false;
+12 }
+</pre>
+</blockquote>
+
+<p>
+However, this temptation must be resisted because there are a
+surprisingly large number of ways that the compiler
+(to say nothing of
+<a href="https://h71000.www7.hp.com/wizard/wiz_2637.html">DEC Alpha CPUs</a>)
+can trip this code up.
+For but one example, if the compiler were short of registers, it
+might choose to refetch from <tt>gp</tt> rather than keeping
+a separate copy in <tt>p</tt> as follows:
+
+<blockquote>
+<pre>
+ 1 bool do_something_gp_buggy_optimized(void)
+ 2 {
+ 3   rcu_read_lock();
+ 4   if (gp) { /* OPTIMIZATIONS GALORE!!! */
+<b> 5     do_something(gp-&gt;a, gp-&gt;b);</b>
+ 6     rcu_read_unlock();
+ 7     return true;
+ 8   }
+ 9   rcu_read_unlock();
+10   return false;
+11 }
+</pre>
+</blockquote>
+
+<p>
+If this function ran concurrently with a series of updates that
+replaced the current structure with a new one,
+the fetches of <tt>gp-&gt;a</tt>
+and <tt>gp-&gt;b</tt> might well come from two different structures,
+which could cause serious confusion.
+To prevent this (and much else besides), <tt>do_something_gp()</tt> uses
+<tt>rcu_dereference()</tt> to fetch from <tt>gp</tt>:
+
+<blockquote>
+<pre>
+ 1 bool do_something_gp(void)
+ 2 {
+ 3   rcu_read_lock();
+ 4   p = rcu_dereference(gp);
+ 5   if (p) {
+ 6     do_something(p-&gt;a, p-&gt;b);
+ 7     rcu_read_unlock();
+ 8     return true;
+ 9   }
+10   rcu_read_unlock();
+11   return false;
+12 }
+</pre>
+</blockquote>
+
+<p>
+The <tt>rcu_dereference()</tt> uses volatile casts and (for DEC Alpha)
+memory barriers in the Linux kernel.
+Should a
+<a href="http://www.rdrop.com/users/paulmck/RCU/consume.2015.07.13a.pdf">high-quality implementation of C11 <tt>memory_order_consume</tt> [PDF]</a>
+ever appear, then <tt>rcu_dereference()</tt> could be implemented
+as a <tt>memory_order_consume</tt> load.
+Regardless of the exact implementation, a pointer fetched by
+<tt>rcu_dereference()</tt> may not be used outside of the
+outermost RCU read-side critical section containing that
+<tt>rcu_dereference()</tt>, unless protection of
+the corresponding data element has been passed from RCU to some
+other synchronization mechanism, most commonly locking or
+<a href="https://www.kernel.org/doc/Documentation/RCU/rcuref.txt">reference counting</a>.
+
+<p>
+In short, updaters use <tt>rcu_assign_pointer()</tt> and readers
+use <tt>rcu_dereference()</tt>, and these two RCU API elements
+work together to ensure that readers have a consistent view of
+newly added data elements.
+
+<p>
+Of course, it is also necessary to remove elements from RCU-protected
+data structures, for example, using the following process:
+
+<ol>
+<li>   Remove the data element from the enclosing structure.
+<li>   Wait for all pre-existing RCU read-side critical sections
+       to complete (because only pre-existing readers can possibly have
+       a reference to the newly removed data element).
+<li>   At this point, only the updater has a reference to the
+       newly removed data element, so it can safely reclaim
+       the data element, for example, by passing it to <tt>kfree()</tt>.
+</ol>
+
+This process is implemented by <tt>remove_gp_synchronous()</tt>:
+
+<blockquote>
+<pre>
+ 1 bool remove_gp_synchronous(void)
+ 2 {
+ 3   struct foo *p;
+ 4
+ 5   spin_lock(&amp;gp_lock);
+ 6   p = rcu_access_pointer(gp);
+ 7   if (!p) {
+ 8     spin_unlock(&amp;gp_lock);
+ 9     return false;
+10   }
+11   rcu_assign_pointer(gp, NULL);
+12   spin_unlock(&amp;gp_lock);
+13   synchronize_rcu();
+14   kfree(p);
+15   return true;
+16 }
+</pre>
+</blockquote>
+
+<p>
+This function is straightforward, with line&nbsp;13 waiting for a grace
+period before line&nbsp;14 frees the old data element.
+This waiting ensures that readers will reach line&nbsp;7 of
+<tt>do_something_gp()</tt> before the data element referenced by
+<tt>p</tt> is freed.
+The <tt>rcu_access_pointer()</tt> on line&nbsp;6 is similar to
+<tt>rcu_dereference()</tt>, except that:
+
+<ol>
+<li>   The value returned by <tt>rcu_access_pointer()</tt>
+       cannot be dereferenced.
+       If you want to access the value pointed to as well as
+       the pointer itself, use <tt>rcu_dereference()</tt>
+       instead of <tt>rcu_access_pointer()</tt>.
+<li>   The call to <tt>rcu_access_pointer()</tt> need not be
+       protected.
+       In contrast, <tt>rcu_dereference()</tt> must either be
+       within an RCU read-side critical section or in a code
+       segment where the pointer cannot change, for example, in
+       code protected by the corresponding update-side lock.
+</ol>
+
+<p>@@QQ@@
+Without the <tt>rcu_dereference()</tt> or the
+<tt>rcu_access_pointer()</tt>, what destructive optimizations
+might the compiler make use of?
+<p>@@QQA@@
+Let's start with what happens to <tt>do_something_gp()</tt>
+if it fails to use <tt>rcu_dereference()</tt>.
+It could reuse a value formerly fetched from this same pointer.
+It could also fetch the pointer from <tt>gp</tt> in a byte-at-a-time
+manner, resulting in <i>load tearing</i>, in turn resulting a bytewise
+mash-up of two distince pointer values.
+It might even use value-speculation optimizations, where it makes a wrong
+guess, but by the time it gets around to checking the value, an update
+has changed the pointer to match the wrong guess.
+Too bad about any dereferences that returned pre-initialization garbage
+in the meantime!
+
+<p>
+For <tt>remove_gp_synchronous()</tt>, as long as all modifications
+to <tt>gp</tt> are carried out while holding <tt>gp_lock</tt>,
+the above optimizations are harmless.
+However,
+with <tt>CONFIG_SPARSE_RCU_POINTER=y</tt>,
+<tt>sparse</tt> will complain if you
+define <tt>gp</tt> with <tt>__rcu</tt> and then
+access it without using
+either <tt>rcu_access_pointer()</tt> or <tt>rcu_dereference()</tt>.
+<p>@@QQE@@
+
+<p>
+In short, RCU's publish-subscribe guarantee is provided by the combination
+of <tt>rcu_assign_pointer()</tt> and <tt>rcu_dereference()</tt>.
+This guarantee allows data elements to be safely added to RCU-protected
+linked data structures without disrupting RCU readers.
+This guarantee can be used in combination with the grace-period
+guarantee to also allow data elements to be removed from RCU-protected
+linked data structures, again without disrupting RCU readers.
+
+<p>
+This guarantee was only partially premeditated.
+DYNIX/ptx used an explicit memory barrier for publication, but had nothing
+resembling <tt>rcu_dereference()</tt> for subscription, nor did it
+have anything resembling the <tt>smp_read_barrier_depends()</tt>
+that was later subsumed into <tt>rcu_dereference()</tt>.
+The need for these operations made itself known quite suddenly at a
+late-1990s meeting with the DEC Alpha architects, back in the days when
+DEC was still a free-standing company.
+It took the Alpha architects a good hour to convince me that any sort
+of barrier would ever be needed, and it then took me a good <i>two</i> hours
+to convince them that their documentation did not make this point clear.
+More recent work with the C and C++ standards committees have provided
+much education on tricks and traps from the compiler.
+In short, compilers were much less tricky in the early 1990s, but in
+2015, don't even think about omitting <tt>rcu_dereference()</tt>!
+
+<h3><a name="Memory-Barrier Guarantees">Memory-Barrier Guarantees</a></h3>
+
+<p>
+The previous section's simple linked-data-structure scenario clearly
+demonstrates the need for RCU's stringent memory-ordering guarantees on
+systems with more than one CPU:
+
+<ol>
+<li>   Each CPU that has an RCU read-side critical section that
+       begins before <tt>synchronize_rcu()</tt> starts is
+       guaranteed to execute a full memory barrier between the time
+       that the RCU read-side critical section ends and the time that
+       <tt>synchronize_rcu()</tt> returns.
+       Without this guarantee, a pre-existing RCU read-side critical section
+       might hold a reference to the newly removed <tt>struct foo</tt>
+       after the <tt>kfree()</tt> on line&nbsp;14 of
+       <tt>remove_gp_synchronous()</tt>.
+<li>   Each CPU that has an RCU read-side critical section that ends
+       after <tt>synchronize_rcu()</tt> returns is guaranteed
+       to execute a full memory barrier between the time that
+       <tt>synchronize_rcu()</tt> begins and the time that the RCU
+       read-side critical section begins.
+       Without this guarantee, a later RCU read-side critical section
+       running after the <tt>kfree()</tt> on line&nbsp;14 of
+       <tt>remove_gp_synchronous()</tt> might
+       later run <tt>do_something_gp()</tt> and find the
+       newly deleted <tt>struct foo</tt>.
+<li>   If the task invoking <tt>synchronize_rcu()</tt> remains
+       on a given CPU, then that CPU is guaranteed to execute a full
+       memory barrier sometime during the execution of
+       <tt>synchronize_rcu()</tt>.
+       This guarantee ensures that the <tt>kfree()</tt> on
+       line&nbsp;14 of <tt>remove_gp_synchronous()</tt> really does
+       execute after the removal on line&nbsp;11.
+<li>   If the task invoking <tt>synchronize_rcu()</tt> migrates
+       among a group of CPUs during that invocation, then each of the
+       CPUs in that group is guaranteed to execute a full memory barrier
+       sometime during the execution of <tt>synchronize_rcu()</tt>.
+       This guarantee also ensures that the <tt>kfree()</tt> on
+       line&nbsp;14 of <tt>remove_gp_synchronous()</tt> really does
+       execute after the removal on
+       line&nbsp;11, but also in the case where the thread executing the
+       <tt>synchronize_rcu()</tt> migrates in the meantime.
+</ol>
+
+<p>@@QQ@@
+Given that multiple CPUs can start RCU read-side critical sections
+at any time without any ordering whatsoever, how can RCU possibly tell whether
+or not a given RCU read-side critical section starts before a
+given instance of <tt>synchronize_rcu()</tt>?
+<p>@@QQA@@
+If RCU cannot tell whether or not a given
+RCU read-side critical section starts before a
+given instance of <tt>synchronize_rcu()</tt>,
+then it must assume that the RCU read-side critical section
+started first.
+In other words, a given instance of <tt>synchronize_rcu()</tt>
+can avoid waiting on a given RCU read-side critical section only
+if it can prove that <tt>synchronize_rcu()</tt> started first.
+<p>@@QQE@@
+
+<p>@@QQ@@
+The first and second guarantees require unbelievably strict ordering!
+Are all these memory barriers <i> really</i> required?
+<p>@@QQA@@
+Yes, they really are required.
+To see why the first guarantee is required, consider the following
+sequence of events:
+
+<ol>
+<li>   CPU 1: <tt>rcu_read_lock()</tt>
+<li>   CPU 1: <tt>q = rcu_dereference(gp);
+       /* Very likely to return p. */</tt>
+<li>   CPU 0: <tt>list_del_rcu(p);</tt>
+<li>   CPU 0: <tt>synchronize_rcu()</tt> starts.
+<li>   CPU 1: <tt>do_something_with(q-&gt;a);
+       /* No smp_mb(), so might happen after kfree(). */</tt>
+<li>   CPU 1: <tt>rcu_read_unlock()</tt>
+<li>   CPU 0: <tt>synchronize_rcu()</tt> returns.
+<li>   CPU 0: <tt>kfree(p);</tt>
+</ol>
+
+<p>
+Therefore, there absolutely must be a full memory barrier between the
+end of the RCU read-side critical section and the end of the
+grace period.
+
+<p>
+The sequence of events demonstrating the necessity of the second rule
+is roughly similar:
+
+<ol>
+<li>   CPU 0: <tt>list_del_rcu(p);</tt>
+<li>   CPU 0: <tt>synchronize_rcu()</tt> starts.
+<li>   CPU 1: <tt>rcu_read_lock()</tt>
+<li>   CPU 1: <tt>q = rcu_dereference(gp);
+       /* Might return p if no memory barrier. */</tt>
+<li>   CPU 0: <tt>synchronize_rcu()</tt> returns.
+<li>   CPU 0: <tt>kfree(p);</tt>
+<li>   CPU 1: <tt>do_something_with(q-&gt;a); /* Boom!!! */</tt>
+<li>   CPU 1: <tt>rcu_read_unlock()</tt>
+</ol>
+
+<p>
+And similarly, without a memory barrier between the beginning of the
+grace period and the beginning of the RCU read-side critical section,
+CPU&nbsp;1 might end up accessing the freelist.
+
+<p>
+The &ldquo;as if&rdquo; rule of course applies, so that any implementation
+that acts as if the appropriate memory barriers were in place is a
+correct implementation.
+That said, it is much easier to fool yourself into believing that you have
+adhered to the as-if rule than it is to actually adhere to it!
+<p>@@QQE@@
+
+<p>
+Note that these memory-barrier requirements do not replace the fundamental
+RCU requirement that a grace period wait for all pre-existing readers.
+On the contrary, the memory barriers called out in this section must operate in
+such a way as to <i>enforce</i> this fundamental requirement.
+Of course, different implementations enforce this requirement in different
+ways, but enforce it they must.
+
+<h3><a name="RCU Primitives Guaranteed to Execute Unconditionally">RCU Primitives Guaranteed to Execute Unconditionally</a></h3>
+
+<p>
+The common-case RCU primitives are unconditional.
+They are invoked, they do their job, and they return, with no possibility
+of error, and no need to retry.
+This is a key RCU design philosophy.
+
+<p>
+However, this philosophy is pragmatic rather than pigheaded.
+If someone comes up with a good justification for a particular conditional
+RCU primitive, it might well be implemented and added.
+After all, this guarantee was reverse-engineered, not premeditated.
+The unconditional nature of the RCU primitives was initially an
+accident of implementation, and later experience with synchronization
+primitives with conditional primitives caused me to elevate this
+accident to a guarantee.
+Therefore, the justification for adding a conditional primitive to
+RCU would need to be based on detailed and compelling use cases.
+
+<h3><a name="Guaranteed Read-to-Write Upgrade">Guaranteed Read-to-Write Upgrade</a></h3>
+
+<p>
+As far as RCU is concerned, it is always possible to carry out an
+update within an RCU read-side critical section.
+For example, that RCU read-side critical section might search for
+a given data element, and then might acquire the update-side
+spinlock in order to update that element, all while remaining
+in that RCU read-side critical section.
+Of course, it is necessary to exit the RCU read-side critical section
+before invoking <tt>synchronize_rcu()</tt>, however, this
+inconvenience can be avoided through use of the
+<tt>call_rcu()</tt> and <tt>kfree_rcu()</tt> API members
+described later in this document.
+
+<p>@@QQ@@
+But how does the upgrade-to-write operation exclude other readers?
+<p>@@QQA@@
+It doesn't, just like normal RCU updates, which also do not exclude
+RCU readers.
+<p>@@QQE@@
+
+<p>
+This guarantee allows lookup code to be shared between read-side
+and update-side code, and was premeditated, appearing in the earliest
+DYNIX/ptx RCU documentation.
+
+<h2><a name="Fundamental Non-Requirements">Fundamental Non-Requirements</a></h2>
+
+<p>
+RCU provides extremely lightweight readers, and its read-side guarantees,
+though quite useful, are correspondingly lightweight.
+It is therefore all too easy to assume that RCU is guaranteeing more
+than it really is.
+Of course, the list of things that RCU does not guarantee is infinitely
+long, however, the following sections list a few non-guarantees that
+have caused confusion.
+Except where otherwise noted, these non-guarantees were premeditated.
+
+<ol>
+<li>   <a href="#Readers Impose Minimal Ordering">
+       Readers Impose Minimal Ordering</a>
+<li>   <a href="#Readers Do Not Exclude Updaters">
+       Readers Do Not Exclude Updaters</a>
+<li>   <a href="#Updaters Only Wait For Old Readers">
+       Updaters Only Wait For Old Readers</a>
+<li>   <a href="#Grace Periods Don't Partition Read-Side Critical Sections">
+       Grace Periods Don't Partition Read-Side Critical Sections</a>
+<li>   <a href="#Read-Side Critical Sections Don't Partition Grace Periods">
+       Read-Side Critical Sections Don't Partition Grace Periods</a>
+<li>   <a href="#Disabling Preemption Does Not Block Grace Periods">
+       Disabling Preemption Does Not Block Grace Periods</a>
+</ol>
+
+<h3><a name="Readers Impose Minimal Ordering">Readers Impose Minimal Ordering</a></h3>
+
+<p>
+Reader-side markers such as <tt>rcu_read_lock()</tt> and
+<tt>rcu_read_unlock()</tt> provide absolutely no ordering guarantees
+except through their interaction with the grace-period APIs such as
+<tt>synchronize_rcu()</tt>.
+To see this, consider the following pair of threads:
+
+<blockquote>
+<pre>
+ 1 void thread0(void)
+ 2 {
+ 3   rcu_read_lock();
+ 4   WRITE_ONCE(x, 1);
+ 5   rcu_read_unlock();
+ 6   rcu_read_lock();
+ 7   WRITE_ONCE(y, 1);
+ 8   rcu_read_unlock();
+ 9 }
+10
+11 void thread1(void)
+12 {
+13   rcu_read_lock();
+14   r1 = READ_ONCE(y);
+15   rcu_read_unlock();
+16   rcu_read_lock();
+17   r2 = READ_ONCE(x);
+18   rcu_read_unlock();
+19 }
+</pre>
+</blockquote>
+
+<p>
+After <tt>thread0()</tt> and <tt>thread1()</tt> execute
+concurrently, it is quite possible to have
+
+<blockquote>
+<pre>
+(r1 == 1 &amp;&amp; r2 == 0)
+</pre>
+</blockquote>
+
+(that is, <tt>y</tt> appears to have been assigned before <tt>x</tt>),
+which would not be possible if <tt>rcu_read_lock()</tt> and
+<tt>rcu_read_unlock()</tt> had much in the way of ordering
+properties.
+But they do not, so the CPU is within its rights
+to do significant reordering.
+This is by design:  Any significant ordering constraints would slow down
+these fast-path APIs.
+
+<p>@@QQ@@
+Can't the compiler also reorder this code?
+<p>@@QQA@@
+No, the volatile casts in <tt>READ_ONCE()</tt> and
+<tt>WRITE_ONCE()</tt> prevent the compiler from reordering in
+this particular case.
+<p>@@QQE@@
+
+<h3><a name="Readers Do Not Exclude Updaters">Readers Do Not Exclude Updaters</a></h3>
+
+<p>
+Neither <tt>rcu_read_lock()</tt> nor <tt>rcu_read_unlock()</tt>
+exclude updates.
+All they do is to prevent grace periods from ending.
+The following example illustrates this:
+
+<blockquote>
+<pre>
+ 1 void thread0(void)
+ 2 {
+ 3   rcu_read_lock();
+ 4   r1 = READ_ONCE(y);
+ 5   if (r1) {
+ 6     do_something_with_nonzero_x();
+ 7     r2 = READ_ONCE(x);
+ 8     WARN_ON(!r2); /* BUG!!! */
+ 9   }
+10   rcu_read_unlock();
+11 }
+12
+13 void thread1(void)
+14 {
+15   spin_lock(&amp;my_lock);
+16   WRITE_ONCE(x, 1);
+17   WRITE_ONCE(y, 1);
+18   spin_unlock(&amp;my_lock);
+19 }
+</pre>
+</blockquote>
+
+<p>
+If the <tt>thread0()</tt> function's <tt>rcu_read_lock()</tt>
+excluded the <tt>thread1()</tt> function's update,
+the <tt>WARN_ON()</tt> could never fire.
+But the fact is that <tt>rcu_read_lock()</tt> does not exclude
+much of anything aside from subsequent grace periods, of which
+<tt>thread1()</tt> has none, so the
+<tt>WARN_ON()</tt> can and does fire.
+
+<h3><a name="Updaters Only Wait For Old Readers">Updaters Only Wait For Old Readers</a></h3>
+
+<p>
+It might be tempting to assume that after <tt>synchronize_rcu()</tt>
+completes, there are no readers executing.
+This temptation must be avoided because
+new readers can start immediately after <tt>synchronize_rcu()</tt>
+starts, and <tt>synchronize_rcu()</tt> is under no
+obligation to wait for these new readers.
+
+<p>@@QQ@@
+Suppose that synchronize_rcu() did wait until all readers had completed.
+Would the updater be able to rely on this?
+<p>@@QQA@@
+No.
+Even if <tt>synchronize_rcu()</tt> were to wait until
+all readers had completed, a new reader might start immediately after
+<tt>synchronize_rcu()</tt> completed.
+Therefore, the code following
+<tt>synchronize_rcu()</tt> cannot rely on there being no readers
+in any case.
+<p>@@QQE@@
+
+<h3><a name="Grace Periods Don't Partition Read-Side Critical Sections">
+Grace Periods Don't Partition Read-Side Critical Sections</a></h3>
+
+<p>
+It is tempting to assume that if any part of one RCU read-side critical
+section precedes a given grace period, and if any part of another RCU
+read-side critical section follows that same grace period, then all of
+the first RCU read-side critical section must precede all of the second.
+However, this just isn't the case: A single grace period does not
+partition the set of RCU read-side critical sections.
+An example of this situation can be illustrated as follows, where
+<tt>x</tt>, <tt>y</tt>, and <tt>z</tt> are initially all zero:
+
+<blockquote>
+<pre>
+ 1 void thread0(void)
+ 2 {
+ 3   rcu_read_lock();
+ 4   WRITE_ONCE(a, 1);
+ 5   WRITE_ONCE(b, 1);
+ 6   rcu_read_unlock();
+ 7 }
+ 8
+ 9 void thread1(void)
+10 {
+11   r1 = READ_ONCE(a);
+12   synchronize_rcu();
+13   WRITE_ONCE(c, 1);
+14 }
+15
+16 void thread2(void)
+17 {
+18   rcu_read_lock();
+19   r2 = READ_ONCE(b);
+20   r3 = READ_ONCE(c);
+21   rcu_read_unlock();
+22 }
+</pre>
+</blockquote>
+
+<p>
+It turns out that the outcome:
+
+<blockquote>
+<pre>
+(r1 == 1 &amp;&amp; r2 == 0 &amp;&amp; r3 == 1)
+</pre>
+</blockquote>
+
+is entirely possible.
+The following figure show how this can happen, with each circled
+<tt>QS</tt> indicating the point at which RCU recorded a
+<i>quiescent state</i> for each thread, that is, a state in which
+RCU knows that the thread cannot be in the midst of an RCU read-side
+critical section that started before the current grace period:
+
+<p><img src="GPpartitionReaders1.svg" alt="GPpartitionReaders1.svg" width="60%"></p>
+
+<p>
+If it is necessary to partition RCU read-side critical sections in this
+manner, it is necessary to use two grace periods, where the first
+grace period is known to end before the second grace period starts:
+
+<blockquote>
+<pre>
+ 1 void thread0(void)
+ 2 {
+ 3   rcu_read_lock();
+ 4   WRITE_ONCE(a, 1);
+ 5   WRITE_ONCE(b, 1);
+ 6   rcu_read_unlock();
+ 7 }
+ 8
+ 9 void thread1(void)
+10 {
+11   r1 = READ_ONCE(a);
+12   synchronize_rcu();
+13   WRITE_ONCE(c, 1);
+14 }
+15
+16 void thread2(void)
+17 {
+18   r2 = READ_ONCE(c);
+19   synchronize_rcu();
+20   WRITE_ONCE(d, 1);
+21 }
+22
+23 void thread3(void)
+24 {
+25   rcu_read_lock();
+26   r3 = READ_ONCE(b);
+27   r4 = READ_ONCE(d);
+28   rcu_read_unlock();
+29 }
+</pre>
+</blockquote>
+
+<p>
+Here, if <tt>(r1 == 1)</tt>, then
+<tt>thread0()</tt>'s write to <tt>b</tt> must happen
+before the end of <tt>thread1()</tt>'s grace period.
+If in addition <tt>(r4 == 1)</tt>, then
+<tt>thread3()</tt>'s read from <tt>b</tt> must happen
+after the beginning of <tt>thread2()</tt>'s grace period.
+If it is also the case that <tt>(r2 == 1)</tt>, then the
+end of <tt>thread1()</tt>'s grace period must precede the
+beginning of <tt>thread2()</tt>'s grace period.
+This mean that the two RCU read-side critical sections cannot overlap,
+guaranteeing that <tt>(r3 == 1)</tt>.
+As a result, the outcome:
+
+<blockquote>
+<pre>
+(r1 == 1 &amp;&amp; r2 == 1 &amp;&amp; r3 == 0 &amp;&amp; r4 == 1)
+</pre>
+</blockquote>
+
+cannot happen.
+
+<p>
+This non-requirement was also non-premeditated, but became apparent
+when studying RCU's interaction with memory ordering.
+
+<h3><a name="Read-Side Critical Sections Don't Partition Grace Periods">
+Read-Side Critical Sections Don't Partition Grace Periods</a></h3>
+
+<p>
+It is also tempting to assume that if an RCU read-side critical section
+happens between a pair of grace periods, then those grace periods cannot
+overlap.
+However, this temptation leads nowhere good, as can be illustrated by
+the following, with all variables initially zero:
+
+<blockquote>
+<pre>
+ 1 void thread0(void)
+ 2 {
+ 3   rcu_read_lock();
+ 4   WRITE_ONCE(a, 1);
+ 5   WRITE_ONCE(b, 1);
+ 6   rcu_read_unlock();
+ 7 }
+ 8
+ 9 void thread1(void)
+10 {
+11   r1 = READ_ONCE(a);
+12   synchronize_rcu();
+13   WRITE_ONCE(c, 1);
+14 }
+15
+16 void thread2(void)
+17 {
+18   rcu_read_lock();
+19   WRITE_ONCE(d, 1);
+20   r2 = READ_ONCE(c);
+21   rcu_read_unlock();
+22 }
+23
+24 void thread3(void)
+25 {
+26   r3 = READ_ONCE(d);
+27   synchronize_rcu();
+28   WRITE_ONCE(e, 1);
+29 }
+30
+31 void thread4(void)
+32 {
+33   rcu_read_lock();
+34   r4 = READ_ONCE(b);
+35   r5 = READ_ONCE(e);
+36   rcu_read_unlock();
+37 }
+</pre>
+</blockquote>
+
+<p>
+In this case, the outcome:
+
+<blockquote>
+<pre>
+(r1 == 1 &amp;&amp; r2 == 1 &amp;&amp; r3 == 1 &amp;&amp; r4 == 0 &amp&amp; r5 == 1)
+</pre>
+</blockquote>
+
+is entirely possible, as illustrated below:
+
+<p><img src="ReadersPartitionGP1.svg" alt="ReadersPartitionGP1.svg" width="100%"></p>
+
+<p>
+Again, an RCU read-side critical section can overlap almost all of a
+given grace period, just so long as it does not overlap the entire
+grace period.
+As a result, an RCU read-side critical section cannot partition a pair
+of RCU grace periods.
+
+<p>@@QQ@@
+How long a sequence of grace periods, each separated by an RCU read-side
+critical section, would be required to partition the RCU read-side
+critical sections at the beginning and end of the chain?
+<p>@@QQA@@
+In theory, an infinite number.
+In practice, an unknown number that is sensitive to both implementation
+details and timing considerations.
+Therefore, even in practice, RCU users must abide by the theoretical rather
+than the practical answer.
+<p>@@QQE@@
+
+<h3><a name="Disabling Preemption Does Not Block Grace Periods">
+Disabling Preemption Does Not Block Grace Periods</a></h3>
+
+<p>
+There was a time when disabling preemption on any given CPU would block
+subsequent grace periods.
+However, this was an accident of implementation and is not a requirement.
+And in the current Linux-kernel implementation, disabling preemption
+on a given CPU in fact does not block grace periods, as Oleg Nesterov
+<a href="https://lkml.kernel.org/g/20150614193825.GA19582@redhat.com">demonstrated</a>.
+
+<p>
+If you need a preempt-disable region to block grace periods, you need to add
+<tt>rcu_read_lock()</tt> and <tt>rcu_read_unlock()</tt>, for example
+as follows:
+
+<blockquote>
+<pre>
+ 1 preempt_disable();
+ 2 rcu_read_lock();
+ 3 do_something();
+ 4 rcu_read_unlock();
+ 5 preempt_enable();
+ 6
+ 7 /* Spinlocks implicitly disable preemption. */
+ 8 spin_lock(&amp;mylock);
+ 9 rcu_read_lock();
+10 do_something();
+11 rcu_read_unlock();
+12 spin_unlock(&amp;mylock);
+</pre>
+</blockquote>
+
+<p>
+In theory, you could enter the RCU read-side critical section first,
+but it is more efficient to keep the entire RCU read-side critical
+section contained in the preempt-disable region as shown above.
+Of course, RCU read-side critical sections that extend outside of
+preempt-disable regions will work correctly, but such critical sections
+can be preempted, which forces <tt>rcu_read_unlock()</tt> to do
+more work.
+And no, this is <i>not</i> an invitation to enclose all of your RCU
+read-side critical sections within preempt-disable regions, because
+doing so would degrade real-time response.
+
+<p>
+This non-requirement appeared with preemptible RCU.
+If you need a grace period that waits on non-preemptible code regions, use
+<a href="#Sched Flavor">RCU-sched</a>.
+
+<h2><a name="Parallelism Facts of Life">Parallelism Facts of Life</a></h2>
+
+<p>
+These parallelism facts of life are by no means specific to RCU, but
+the RCU implementation must abide by them.
+They therefore bear repeating:
+
+<ol>
+<li>   Any CPU or task may be delayed at any time,
+       and any attempts to avoid these delays by disabling
+       preemption, interrupts, or whatever are completely futile.
+       This is most obvious in preemptible user-level
+       environments and in virtualized environments (where
+       a given guest OS's VCPUs can be preempted at any time by
+       the underlying hypervisor), but can also happen in bare-metal
+       environments due to ECC errors, NMIs, and other hardware
+       events.
+       Although a delay of more than about 20 seconds can result
+       in splats, the RCU implementation is obligated to use
+       algorithms that can tolerate extremely long delays, but where
+       &ldquo;extremely long&rdquo; is not long enough to allow
+       wrap-around when incrementing a 64-bit counter.
+<li>   Both the compiler and the CPU can reorder memory accesses.
+       Where it matters, RCU must use compiler directives and
+       memory-barrier instructions to preserve ordering.
+<li>   Conflicting writes to memory locations in any given cache line
+       will result in expensive cache misses.
+       Greater numbers of concurrent writes and more-frequent
+       concurrent writes will result in more dramatic slowdowns.
+       RCU is therefore obligated to use algorithms that have
+       sufficient locality to avoid significant performance and
+       scalability problems.
+<li>   As a rough rule of thumb, only one CPU's worth of processing
+       may be carried out under the protection of any given exclusive
+       lock.
+       RCU must therefore use scalable locking designs.
+<li>   Counters are finite, especially on 32-bit systems.
+       RCU's use of counters must therefore tolerate counter wrap,
+       or be designed such that counter wrap would take way more
+       time than a single system is likely to run.
+       An uptime of ten years is quite possible, a runtime
+       of a century much less so.
+       As an example of the latter, RCU's dyntick-idle nesting counter
+       allows 54 bits for interrupt nesting level (this counter
+       is 64 bits even on a 32-bit system).
+       Overflowing this counter requires 2<sup>54</sup>
+       half-interrupts on a given CPU without that CPU ever going idle.
+       If a half-interrupt happened every microsecond, it would take
+       570 years of runtime to overflow this counter, which is currently
+       believed to be an acceptably long time.
+<li>   Linux systems can have thousands of CPUs running a single
+       Linux kernel in a single shared-memory environment.
+       RCU must therefore pay close attention to high-end scalability.
+</ol>
+
+<p>
+This last parallelism fact of life means that RCU must pay special
+attention to the preceding facts of life.
+The idea that Linux might scale to systems with thousands of CPUs would
+have been met with some skepticism in the 1990s, but these requirements
+would have otherwise have been unsurprising, even in the early 1990s.
+
+<h2><a name="Quality-of-Implementation Requirements">Quality-of-Implementation Requirements</a></h2>
+
+<p>
+These sections list quality-of-implementation requirements.
+Although an RCU implementation that ignores these requirements could
+still be used, it would likely be subject to limitations that would
+make it inappropriate for industrial-strength production use.
+Classes of quality-of-implementation requirements are as follows:
+
+<ol>
+<li>   <a href="#Specialization">Specialization</a>
+<li>   <a href="#Performance and Scalability">Performance and Scalability</a>
+<li>   <a href="#Composability">Composability</a>
+<li>   <a href="#Corner Cases">Corner Cases</a>
+</ol>
+
+<p>
+These classes is covered in the following sections.
+
+<h3><a name="Specialization">Specialization</a></h3>
+
+<p>
+RCU is and always has been intended primarily for read-mostly situations, as
+illustrated by the following figure.
+This means that RCU's read-side primitives are optimized, often at the
+expense of its update-side primitives.
+
+<p><img src="RCUApplicability.svg" alt="RCUApplicability.svg" width="70%"></p>
+
+<p>
+This focus on read-mostly situations means that RCU must interoperate
+with other synchronization primitives.
+For example, the <tt>add_gp()</tt> and <tt>remove_gp_synchronous()</tt>
+examples discussed earlier use RCU to protect readers and locking to
+coordinate updaters.
+However, the need extends much farther, requiring that a variety of
+synchronization primitives be legal within RCU read-side critical sections,
+including spinlocks, sequence locks, atomic operations, reference
+counters, and memory barriers.
+
+<p>@@QQ@@
+What about sleeping locks?
+<p>@@QQA@@
+These are forbidden within Linux-kernel RCU read-side critical sections
+because it is not legal to place a quiescent state (in this case,
+voluntary context switch) within an RCU read-side critical section.
+However, sleeping locks may be used within userspace RCU read-side critical
+sections, and also within Linux-kernel sleepable RCU
+<a href="#Sleepable RCU">(SRCU)</a>
+read-side critical sections.
+In addition, the -rt patchset turns spinlocks into a sleeping locks so
+that the corresponding critical sections can be preempted, which
+also means that these sleeplockified spinlocks (but not other sleeping locks!)
+may be acquire within -rt-Linux-kernel RCU read-side critical sections.
+
+<p>
+Note that it <i>is</i> legal for a normal RCU read-side critical section
+to conditionally acquire a sleeping locks (as in <tt>mutex_trylock()</tt>),
+but only as long as it does not loop indefinitely attempting to
+conditionally acquire that sleeping locks.
+The key point is that things like <tt>mutex_trylock()</tt>
+either return with the mutex held, or return an error indication if
+the mutex was not immediately available.
+Either way, <tt>mutex_trylock()</tt> returns immediately without sleeping.
+<p>@@QQE@@
+
+<p>
+It often comes as a surprise that many algorithms do not require a
+consistent view of data, but many can function in that mode,
+with network routing being the poster child.
+Internet routing algorithms take significant time to propagate
+updates, so that by the time an update arrives at a given system,
+that system has been sending network traffic the wrong way for
+a considerable length of time.
+Having a few threads continue to send traffic the wrong way for a
+few more milliseconds is clearly not a problem:  In the worst case,
+TCP retransmissions will eventually get the data where it needs to go.
+In general, when tracking the state of the universe outside of the
+computer, some level of inconsistency must be tolerated due to
+speed-of-light delays if nothing else.
+
+<p>
+Furthermore, uncertainty about external state is inherent in many cases.
+For example, a pair of veternarians might use heartbeat to determine
+whether or not a given cat was alive.
+But how long should they wait after the last heartbeat to decide that
+the cat is in fact dead?
+Waiting less than 400 milliseconds makes no sense because this would
+mean that a relaxed cat would be considered to cycle between death
+and life more than 100 times per minute.
+Moreover, just as with human beings, a cat's heart might stop for
+some period of time, so the exact wait period is a judgment call.
+One of our pair of veternarians might wait 30 seconds before pronouncing
+the cat dead, while the other might insist on waiting a full minute.
+The two veternarians would then disagree on the state of the cat during
+the final 30 seconds of the minute following the last heartbeat, as
+fancifully illustrated below:
+
+<p><img src="2013-08-is-it-dead.png" alt="2013-08-is-it-dead.png" width="431"></p>
+
+<p>
+Interestingly enough, this same situation applies to hardware.
+When push comes to shove, how do we tell whether or not some
+external server has failed?
+We send messages to it periodically, and declare it failed if we
+don't receive a response within a given period of time.
+Policy decisions can usually tolerate short
+periods of inconsistency.
+The policy was decided some time ago, and is only now being put into
+effect, so a few milliseconds of delay is normally inconsequential.
+
+<p>
+However, there are algorithms that absolutely must see consistent data.
+For example, the translation between a user-level SystemV semaphore
+ID to the corresponding in-kernel data structure is protected by RCU,
+but it is absolutely forbidden to update a semaphore that has just been
+removed.
+In the Linux kernel, this need for consistency is accommodated by acquiring
+spinlocks located in the in-kernel data structure from within
+the RCU read-side critical section, and this is indicated by the
+green box in the figure above.
+Many other techniques may be used, and are in fact used within the
+Linux kernel.
+
+<p>
+In short, RCU is not required to maintain consistency, and other
+mechanisms may be used in concert with RCU when consistency is required.
+RCU's specialization allows it to do its job extremely well, and its
+ability to interoperate with other synchronization mechanisms allows
+the right mix of synchronization tools to be used for a given job.
+
+<h3><a name="Performance and Scalability">Performance and Scalability</a></h3>
+
+<p>
+Energy efficiency is a critical component of performance today,
+and Linux-kernel RCU implementations must therefore avoid unnecessarily
+awakening idle CPUs.
+I cannot claim that this requirement was premeditated.
+In fact, I learned of it during a telephone conversation in which I
+was given &ldquo;frank and open&rdquo; feedback on the importance
+of energy efficiency in battery-powered systems and on specific
+energy-efficiency shortcomings of the Linux-kernel RCU implementation.
+In my experience, the battery-powered embedded community will consider
+any unnecessary wakeups to be extremely unfriendly acts.
+So much so that mere Linux-kernel-mailing-list posts are
+insufficient to vent their ire.
+
+<p>
+Memory consumption is not particularly important for in most
+situations, and has become decreasingly
+so as memory sizes have expanded and memory
+costs have plummeted.
+However, as I learned from Matt Mackall's
+<a href="http://elinux.org/Linux_Tiny-FAQ">bloatwatch</a>
+efforts, memory footprint is critically important on single-CPU systems with
+non-preemptible (<tt>CONFIG_PREEMPT=n</tt>) kernels, and thus
+<a href="https://lkml.kernel.org/g/20090113221724.GA15307@linux.vnet.ibm.com">tiny RCU</a>
+was born.
+Josh Triplett has since taken over the small-memory banner with his
+<a href="https://tiny.wiki.kernel.org/">Linux kernel tinification</a>
+project, which resulted in
+<a href="#Sleepable RCU">SRCU</a>
+becoming optional for those kernels not needing it.
+
+<p>
+The remaining performance requirements are, for the most part,
+unsurprising.
+For example, in keeping with RCU's read-side specialization,
+<tt>rcu_dereference()</tt> should have negligible overhead (for
+example, suppression of a few minor compiler optimizations).
+Similarly, in non-preemptible environments, <tt>rcu_read_lock()</tt> and
+<tt>rcu_read_unlock()</tt> should have exactly zero overhead.
+
+<p>
+In preemptible environments, in the case where the RCU read-side
+critical section was not preempted (as will be the case for the
+highest-priority real-time process), <tt>rcu_read_lock()</tt> and
+<tt>rcu_read_unlock()</tt> should have minimal overhead.
+In particular, they should not contain atomic read-modify-write
+operations, memory-barrier instructions, preemption disabling,
+interrupt disabling, or backwards branches.
+However, in the case where the RCU read-side critical section was preempted,
+<tt>rcu_read_unlock()</tt> may acquire spinlocks and disable interrupts.
+This is why it is better to nest an RCU read-side critical section
+within a preempt-disable region than vice versa, at least in cases
+where that critical section is short enough to avoid unduly degrading
+real-time latencies.
+
+<p>
+The <tt>synchronize_rcu()</tt> grace-period-wait primitive is
+optimized for throughput.
+It may therefore incur several milliseconds of latency in addition to
+the duration of the longest RCU read-side critical section.
+On the other hand, multiple concurrent invocations of
+<tt>synchronize_rcu()</tt> are required to use batching optimizations
+so that they can be satisfied by a single underlying grace-period-wait
+operation.
+For example, in the Linux kernel, it is not unusual for a single
+grace-period-wait operation to serve more than
+<a href="https://www.usenix.org/conference/2004-usenix-annual-technical-conference/making-rcu-safe-deep-sub-millisecond-response">1,000 separate invocations</a>
+of <tt>synchronize_rcu()</tt>, thus amortizing the per-invocation
+overhead down to nearly zero.
+However, the grace-period optimization is also required to avoid
+measurable degradation of real-time scheduling and interrupt latencies.
+
+<p>
+In some cases, the multi-millisecond <tt>synchronize_rcu()</tt>
+latencies are unacceptable.
+In these cases, <tt>synchronize_rcu_expedited()</tt> may be used
+instead, reducing the grace-period latency down to a few tens of
+microseconds on small systems, at least in cases where the RCU read-side
+critical sections are short.
+There are currently no special latency requirements for
+<tt>synchronize_rcu_expedited()</tt> on large systems, but,
+consistent with the empirical nature of the RCU specification,
+that is subject to change.
+However, there most definitely are scalability requirements:
+A storm of <tt>synchronize_rcu_expedited()</tt> invocations on 4096
+CPUs should at least make reasonable forward progress.
+In return for its shorter latencies, <tt>synchronize_rcu_expedited()</tt>
+is permitted to impose modest degradation of real-time latency
+on non-idle online CPUs.
+That said, it will likely be necessary to take further steps to reduce this
+degradation, hopefully to roughly that of a scheduling-clock interrupt.
+
+<p>
+There are a number of situations where even
+<tt>synchronize_rcu_expedited()</tt>'s reduced grace-period
+latency is unacceptable.
+In these situations, the asynchronous <tt>call_rcu()</tt> can be
+used in place of <tt>synchronize_rcu()</tt> as follows:
+
+<blockquote>
+<pre>
+ 1 struct foo {
+ 2   int a;
+ 3   int b;
+ 4   struct rcu_head rh;
+ 5 };
+ 6
+ 7 static void remove_gp_cb(struct rcu_head *rhp)
+ 8 {
+ 9   struct foo *p = container_of(rhp, struct foo, rh);
+10
+11   kfree(p);
+12 }
+13
+14 bool remove_gp_asynchronous(void)
+15 {
+16   struct foo *p;
+17
+18   spin_lock(&amp;gp_lock);
+19   p = rcu_dereference(gp);
+20   if (!p) {
+21     spin_unlock(&amp;gp_lock);
+22     return false;
+23   }
+24   rcu_assign_pointer(gp, NULL);
+25   call_rcu(&amp;p-&gt;rh, remove_gp_cb);
+26   spin_unlock(&amp;gp_lock);
+27   return true;
+28 }
+</pre>
+</blockquote>
+
+<p>
+A definition of <tt>struct foo</tt> is finally needed, and appears
+on lines&nbsp;1-5.
+The function <tt>remove_gp_cb()</tt> is passed to <tt>call_rcu()</tt>
+on line&nbsp;25, and will be invoked after the end of a subsequent
+grace period.
+This gets the same effect as <tt>remove_gp_synchronous()</tt>,
+but without forcing the updater to wait for a grace period to elapse.
+The <tt>call_rcu()</tt> function may be used in a number of
+situations where neither <tt>synchronize_rcu()</tt> nor
+<tt>synchronize_rcu_expedited()</tt> would be legal,
+including within preempt-disable code, <tt>local_bh_disable()</tt> code,
+interrupt-disable code, and interrupt handlers.
+However, even <tt>call_rcu()</tt> is illegal within NMI handlers.
+The callback function (<tt>remove_gp_cb()</tt> in this case) will be
+executed within softirq (software interrupt) environment within the
+Linux kernel,
+either within a real softirq handler or under the protection
+of <tt>local_bh_disable()</tt>.
+In both the Linux kernel and in userspace, it is bad practice to
+write an RCU callback function that takes too long.
+Long-running operations should be relegated to separate threads or
+(in the Linux kernel) workqueues.
+
+<p>@@QQ@@
+Why does line&nbsp;19 use <tt>rcu_access_pointer()</tt>?
+After all, <tt>call_rcu()</tt> on line&nbsp;25 stores into the
+structure, which would interact badly with concurrent insertions.
+Doesn't this mean that <tt>rcu_dereference()</tt> is required?
+<p>@@QQA@@
+Presumably the <tt>-&gt;gp_lock</tt> acquired on line&nbsp;18 excludes
+any changes, including any insertions that <tt>rcu_dereference()</tt>
+would protect against.
+Therefore, any insertions will be delayed until after <tt>-&gt;gp_lock</tt>
+is released on line&nbsp;25, which in turn means that
+<tt>rcu_access_pointer()</tt> suffices.
+<p>@@QQE@@
+
+<p>
+However, all that <tt>remove_gp_cb()</tt> is doing is
+invoking <tt>kfree()</tt> on the data element.
+This is a common idiom, and is supported by <tt>kfree_rcu()</tt>,
+which allows &ldquo;fire and forget&rdquo; operation as shown below:
+
+<blockquote>
+<pre>
+ 1 struct foo {
+ 2   int a;
+ 3   int b;
+ 4   struct rcu_head rh;
+ 5 };
+ 6
+ 7 bool remove_gp_faf(void)
+ 8 {
+ 9   struct foo *p;
+10
+11   spin_lock(&amp;gp_lock);
+12   p = rcu_dereference(gp);
+13   if (!p) {
+14     spin_unlock(&amp;gp_lock);
+15     return false;
+16   }
+17   rcu_assign_pointer(gp, NULL);
+18   kfree_rcu(p, rh);
+19   spin_unlock(&amp;gp_lock);
+20   return true;
+21 }
+</pre>
+</blockquote>
+
+<p>
+Note that <tt>remove_gp_faf()</tt> simply invokes
+<tt>kfree_rcu()</tt> and proceeds, without any need to pay any
+further attention to the subsequent grace period and <tt>kfree()</tt>.
+It is permissible to invoke <tt>kfree_rcu()</tt> from the same
+environments as for <tt>call_rcu()</tt>.
+Interestingly enough, DYNIX/ptx had the equivalents of
+<tt>call_rcu()</tt> and <tt>kfree_rcu()</tt>, but not
+<tt>synchronize_rcu()</tt>.
+This was due to the fact that RCU was not heavily used within DYNIX/ptx,
+so the very few places that needed something like
+<tt>synchronize_rcu()</tt> simply open-coded it.
+
+<p>@@QQ@@
+Earlier it was claimed that <tt>call_rcu()</tt> and
+<tt>kfree_rcu()</tt> allowed updaters to avoid being blocked
+by readers.
+But how can that be correct, given that the invocation of the callback
+and the freeing of the memory (respectively) must still wait for
+a grace period to elapse?
+<p>@@QQA@@
+We could define things this way, but keep in mind that this sort of
+definition would say that updates in garbage-collected languages
+cannot complete until the next time the garbage collector runs,
+which does not seem at all reasonable.
+The key point is that in most cases, an updater using either
+<tt>call_rcu()</tt> or <tt>kfree_rcu()</tt> can proceed to the
+next update as soon as it has invoked <tt>call_rcu()</tt> or
+<tt>kfree_rcu()</tt>, without having to wait for a subsequent
+grace period.
+<p>@@QQE@@
+
+<p>
+But what if the updater must wait for the completion of code to be
+executed after the end of the grace period, but has other tasks
+that can be carried out in the meantime?
+The polling-style <tt>get_state_synchronize_rcu()</tt> and
+<tt>cond_synchronize_rcu()</tt> functions may be used for this
+purpose, as shown below:
+
+<blockquote>
+<pre>
+ 1 bool remove_gp_poll(void)
+ 2 {
+ 3   struct foo *p;
+ 4   unsigned long s;
+ 5
+ 6   spin_lock(&amp;gp_lock);
+ 7   p = rcu_access_pointer(gp);
+ 8   if (!p) {
+ 9     spin_unlock(&amp;gp_lock);
+10     return false;
+11   }
+12   rcu_assign_pointer(gp, NULL);
+13   spin_unlock(&amp;gp_lock);
+14   s = get_state_synchronize_rcu();
+15   do_something_while_waiting();
+16   cond_synchronize_rcu(s);
+17   kfree(p);
+18   return true;
+19 }
+</pre>
+</blockquote>
+
+<p>
+On line&nbsp;14, <tt>get_state_synchronize_rcu()</tt> obtains a
+&ldquo;cookie&rdquo; from RCU,
+then line&nbsp;15 carries out other tasks,
+and finally, line&nbsp;16 returns immediately if a grace period has
+elapsed in the meantime, but otherwise waits as required.
+The need for <tt>get_state_synchronize_rcu</tt> and
+<tt>cond_synchronize_rcu()</tt> has appeared quite recently,
+so it is too early to tell whether they will stand the test of time.
+
+<p>
+RCU thus provides a range of tools to allow updaters to strike the
+required tradeoff between latency, flexibility and CPU overhead.
+
+<h3><a name="Composability">Composability</a></h3>
+
+<p>
+Composability has received much attention in recent years, perhaps in part
+due to the collision of multicore hardware with object-oriented techniques
+designed in single-threaded environments for single-threaded use.
+And in theory, RCU read-side critical sections may be composed, and in
+fact may be nested arbitrarily deeply.
+In practice, as with all real-world implementations of composable
+constructs, there are limitations.
+
+<p>
+Implementations of RCU for which <tt>rcu_read_lock()</tt>
+and <tt>rcu_read_unlock()</tt> generate no code, such as
+Linux-kernel RCU when <tt>CONFIG_PREEMPT=n</tt>, can be
+nested arbitrarily deeply.
+After all, there is no overhead.
+Except that if all these instances of <tt>rcu_read_lock()</tt>
+and <tt>rcu_read_unlock()</tt> are visible to the compiler,
+compilation will eventually fail due to exhausting memory,
+mass storage, or user patience, whichever comes first.
+If the nesting is not visible to the compiler, as is the case with
+mutually recursive functions each in its own translation unit,
+stack overflow will result.
+If the nesting takes the form of loops, either the control variable
+will overflow or (in the Linux kernel) you will get an RCU CPU stall warning.
+Nevertheless, this class of RCU implementations is one
+of the most composable constructs in existence.
+
+<p>
+RCU implementations that explicitly track nesting depth
+are limited by the nesting-depth counter.
+For example, the Linux kernel's preemptible RCU limits nesting to
+<tt>INT_MAX</tt>.
+This should suffice for almost all practical purposes.
+That said, a consecutive pair of RCU read-side critical sections
+between which there is an operation that waits for a grace period
+cannot be enclosed in another RCU read-side critical section.
+This is because it is not legal to wait for a grace period within
+an RCU read-side critical section:  To do so would result either
+in deadlock or
+in RCU implicitly splitting the enclosing RCU read-side critical
+section, neither of which is conducive to a long-lived and prosperous
+kernel.
+
+<p>
+It is worth noting that RCU is not alone in limiting composability.
+For example, many transactional-memory implementations prohibit
+composing a pair of transactions separated by an irrevocable
+operation (for example, a network receive operation).
+For another example, lock-based critical sections can be composed
+surprisingly freely, but only if deadlock is avoided.
+
+<p>
+In short, although RCU read-side critical sections are highly composable,
+care is required in some situations, just as is the case for any other
+composable synchronization mechanism.
+
+<h3><a name="Corner Cases">Corner Cases</a></h3>
+
+<p>
+A given RCU workload might have an endless and intense stream of
+RCU read-side critical sections, perhaps even so intense that there
+was never a point in time during which there was not at least one
+RCU read-side critical section in flight.
+RCU cannot allow this situation to block grace periods:  As long as
+all the RCU read-side critical sections are finite, grace periods
+must also be finite.
+
+<p>
+That said, preemptible RCU implementations could potentially result
+in RCU read-side critical sections being preempted for long durations,
+which has the effect of creating a long-duration RCU read-side
+critical section.
+This situation can arise only in heavily loaded systems, but systems using
+real-time priorities are of course more vulnerable.
+Therefore, RCU priority boosting is provided to help deal with this
+case.
+That said, the exact requirements on RCU priority boosting will likely
+evolve as more experience accumulates.
+
+<p>
+Other workloads might have very high update rates.
+Although one can argue that such workloads should instead use
+something other than RCU, the fact remains that RCU must
+handle such workloads gracefully.
+This requirement is another factor driving batching of grace periods,
+but it is also the driving force behind the checks for large numbers
+of queued RCU callbacks in the <tt>call_rcu()</tt> code path.
+Finally, high update rates should not delay RCU read-side critical
+sections, although some read-side delays can occur when using
+<tt>synchronize_rcu_expedited()</tt>, courtesy of this function's use
+of <tt>try_stop_cpus()</tt>.
+(In the future, <tt>synchronize_rcu_expedited()</tt> will be
+converted to use lighter-weight inter-processor interrupts (IPIs),
+but this will still disturb readers, though to a much smaller degree.)
+
+<p>
+Although all three of these corner cases were understood in the early
+1990s, a simple user-level test consisting of <tt>close(open(path))</tt>
+in a tight loop
+in the early 2000s suddenly provided a much deeper appreciation of the
+high-update-rate corner case.
+This test also motivated addition of some RCU code to react to high update
+rates, for example, if a given CPU finds itself with more than 10,000
+RCU callbacks queued, it will cause RCU to take evasive action by
+more aggressively starting grace periods and more aggressively forcing
+completion of grace-period processing.
+This evasive action causes the grace period to complete more quickly,
+but at the cost of restricting RCU's batching optimizations, thus
+increasing the CPU overhead incurred by that grace period.
+
+<h2><a name="Software-Engineering Requirements">
+Software-Engineering Requirements</a></h2>
+
+<p>
+Between Murphy's Law and &ldquo;To err is human&rdquo;, it is necessary to
+guard against mishaps and misuse:
+
+<ol>
+<li>   It is all too easy to forget to use <tt>rcu_read_lock()</tt>
+       everywhere that it is needed, so kernels built with
+       <tt>CONFIG_PROVE_RCU=y</tt> will spat if
+       <tt>rcu_dereference()</tt> is used outside of an
+       RCU read-side critical section.
+       Update-side code can use <tt>rcu_dereference_protected()</tt>,
+       which takes a
+       <a href="https://lwn.net/Articles/371986/">lockdep expression</a>
+       to indicate what is providing the protection.
+       If the indicated protection is not provided, a lockdep splat
+       is emitted.
+
+       <p>
+       Code shared between readers and updaters can use
+       <tt>rcu_dereference_check()</tt>, which also takes a
+       lockdep expression, and emits a lockdep splat if neither
+       <tt>rcu_read_lock()</tt> nor the indicated protection
+       is in place.
+       In addition, <tt>rcu_dereference_raw()</tt> is used in those
+       (hopefully rare) cases where the required protection cannot
+       be easily described.
+       Finally, <tt>rcu_read_lock_held()</tt> is provided to
+       allow a function to verify that it has been invoked within
+       an RCU read-side critical section.
+       I was made aware of this set of requirements shortly after Thomas
+       Gleixner audited a number of RCU uses.
+<li>   A given function might wish to check for RCU-related preconditions
+       upon entry, before using any other RCU API.
+       The <tt>rcu_lockdep_assert()</tt> does this job,
+       asserting the expression in kernels having lockdep enabled
+       and doing nothing otherwise.
+<li>   It is also easy to forget to use <tt>rcu_assign_pointer()</tt>
+       and <tt>rcu_dereference()</tt>, perhaps (incorrectly)
+       substituting a simple assignment.
+       To catch this sort of error, a given RCU-protected pointer may be
+       tagged with <tt>__rcu</tt>, after which running sparse
+       with <tt>CONFIG_SPARSE_RCU_POINTER=y</tt> will complain
+       about simple-assignment accesses to that pointer.
+       Arnd Bergmann made me aware of this requirement, and also
+       supplied the needed
+       <a href="https://lwn.net/Articles/376011/">patch series</a>.
+<li>   Kernels built with <tt>CONFIG_DEBUG_OBJECTS_RCU_HEAD=y</tt>
+       will splat if a data element is passed to <tt>call_rcu()</tt>
+       twice in a row, without a grace period in between.
+       (This error is similar to a double free.)
+       The corresponding <tt>rcu_head</tt> structures that are
+       dynamically allocated are automatically tracked, but
+       <tt>rcu_head</tt> structures allocated on the stack
+       must be initialized with <tt>init_rcu_head_on_stack()</tt>
+       and cleaned up with <tt>destroy_rcu_head_on_stack()</tt>.
+       Similarly, statically allocated non-stack <tt>rcu_head</tt>
+       structures must be initialized with <tt>init_rcu_head()</tt>
+       and cleaned up with <tt>destroy_rcu_head()</tt>.
+       Mathieu Desnoyers made me aware of this requirement, and also
+       supplied the needed
+       <a href="https://lkml.kernel.org/g/20100319013024.GA28456@Krystal">patch</a>.
+<li>   An infinite loop in an RCU read-side critical section will
+       eventually trigger an RCU CPU stall warning splat, with
+       the duration of &ldquo;eventually&rdquo; being controlled by the
+       <tt>RCU_CPU_STALL_TIMEOUT</tt> <tt>Kconfig</tt> option, or,
+       alternatively, by the
+       <tt>rcupdate.rcu_cpu_stall_timeout</tt> boot/sysfs
+       parameter.
+       However, RCU is not obligated to produce this splat
+       unless there is a grace period waiting on that particular
+       RCU read-side critical section.
+       <p>
+       Some extreme workloads might intentionally delay
+       RCU grace periods, and systems running those workloads can
+       be booted with <tt>rcupdate.rcu_cpu_stall_suppress</tt>
+       to suppress the splats.
+       This kernel parameter may also be set via <tt>sysfs</tt>.
+       Furthermore, RCU CPU stall warnings are counter-productive
+       during sysrq dumps and during panics.
+       RCU therefore supplies the <tt>rcu_sysrq_start()</tt> and
+       <tt>rcu_sysrq_end()</tt> API members to be called before
+       and after long sysrq dumps.
+       RCU also supplies the <tt>rcu_panic()</tt> notifier that is
+       automatically invoked at the beginning of a panic to suppress
+       further RCU CPU stall warnings.
+
+       <p>
+       This requirement made itself known in the early 1990s, pretty
+       much the first time that it was necessary to debug a CPU stall.
+       That said, the initial implementation in DYNIX/ptx was quite
+       generic in comparison with that of Linux.
+<li>   Although it would be very good to detect pointers leaking out
+       of RCU read-side critical sections, there is currently no
+       good way of doing this.
+       One complication is the need to distinguish between pointers
+       leaking and pointers that have been handed off from RCU to
+       some other synchronization mechanism, for example, reference
+       counting.
+<li>   In kernels built with <tt>CONFIG_RCU_TRACE=y</tt>, RCU-related
+       information is provided via both debugfs and event tracing.
+<li>   Open-coded use of <tt>rcu_assign_pointer()</tt> and
+       <tt>rcu_dereference()</tt> to create typical linked
+       data structures can be surprisingly error-prone.
+       Therefore, RCU-protected
+       <a href="https://lwn.net/Articles/609973/#RCU List APIs">linked lists</a>
+       and, more recently, RCU-protected
+       <a href="https://lwn.net/Articles/612100/">hash tables</a>
+       are available.
+       Many other special-purpose RCU-protected data structures are
+       available in the Linux kernel and the userspace RCU library.
+<li>   Some linked structures are created at compile time, but still
+       require <tt>__rcu</tt> checking.
+       The <tt>RCU_POINTER_INITIALIZER()</tt> macro serves this
+       purpose.
+<li>   It is not necessary to use <tt>rcu_assign_pointer()</tt>
+       when creating linked structures that are to be published via
+       a single external pointer.
+       The <tt>RCU_INIT_POINTER()</tt> macro is provided for
+       this task and also for assigning <tt>NULL</tt> pointers
+       at runtime.
+</ol>
+
+<p>
+This not a hard-and-fast list:  RCU's diagnostic capabilities will
+continue to be guided by the number and type of usage bugs found
+in real-world RCU usage.
+
+<h2><a name="Linux Kernel Complications">Linux Kernel Complications</a></h2>
+
+<p>
+The Linux kernel provides an interesting environment for all kinds of
+software, including RCU.
+Some of the relevant points of interest are as follows:
+
+<ol>
+<li>   <a href="#Configuration">Configuration</a>.
+<li>   <a href="#Firmware Interface">Firmware Interface</a>.
+<li>   <a href="#Early Boot">Early Boot</a>.
+<li>   <a href="#Interrupts and NMIs">
+       Interrupts and non-maskable interrupts (NMIs)</a>.
+<li>   <a href="#Loadable Modules">Loadable Modules</a>.
+<li>   <a href="#Hotplug CPU">Hotplug CPU</a>.
+<li>   <a href="#Scheduler and RCU">Scheduler and RCU</a>.
+<li>   <a href="#Tracing and RCU">Tracing and RCU</a>.
+<li>   <a href="#Energy Efficiency">Energy Efficiency</a>.
+<li>   <a href="#Memory Efficiency">Memory Efficiency</a>.
+<li>   <a href="#Performance, Scalability, Response Time, and Reliability">
+       Performance, Scalability, Response Time, and Reliability</a>.
+</ol>
+
+<p>
+This list is probably incomplete, but it does give a feel for the
+most notable Linux-kernel complications.
+Each of the following sections covers one of the above topics.
+
+<h3><a name="Configuration">Configuration</a></h3>
+
+<p>
+RCU's goal is automatic configuration, so that almost nobody
+needs to worry about RCU's <tt>Kconfig</tt> options.
+And for almost all users, RCU does in fact work well
+&ldquo;out of the box.&rdquo;
+
+<p>
+However, there are specialized use cases that are handled by
+kernel boot parameters and <tt>Kconfig</tt> options.
+Unfortunately, the <tt>Kconfig</tt> system will explicitly ask users
+about new <tt>Kconfig</tt> options, which requires almost all of them
+be hidden behind a <tt>CONFIG_RCU_EXPERT</tt> <tt>Kconfig</tt> option.
+
+<p>
+This all should be quite obvious, but the fact remains that
+Linus Torvalds recently had to
+<a href="https://lkml.kernel.org/g/CA+55aFy4wcCwaL4okTs8wXhGZ5h-ibecy_Meg9C4MNQrUnwMcg@mail.gmail.com">remind</a>
+me of this requirement.
+
+<h3><a name="Firmware Interface">Firmware Interface</a></h3>
+
+<p>
+In many cases, kernel obtains information about the system from the
+firmware, and sometimes things are lost in translation.
+Or the translation is accurate, but the original message is bogus.
+
+<p>
+For example, some systems' firmware overreports the number of CPUs,
+sometimes by a large factor.
+If RCU naively believed the firmware, as it used to do,
+it would create too many per-CPU kthreads.
+Although the resulting system will still run correctly, the extra
+kthreads needlessly consume memory and can cause confusion
+when they show up in <tt>ps</tt> listings.
+
+<p>
+RCU must therefore wait for a given CPU to actually come online before
+it can allow itself to believe that the CPU actually exists.
+The resulting &ldquo;ghost CPUs&rdquo; (which are never going to
+come online) cause a number of
+<a href="https://paulmck.livejournal.com/37494.html">interesting complications</a>.
+
+<h3><a name="Early Boot">Early Boot</a></h3>
+
+<p>
+The Linux kernel's boot sequence is an interesting process,
+and RCU is used early, even before <tt>rcu_init()</tt>
+is invoked.
+In fact, a number of RCU's primitives can be used as soon as the
+initial task's <tt>task_struct</tt> is available and the
+boot CPU's per-CPU variables are set up.
+The read-side primitives (<tt>rcu_read_lock()</tt>,
+<tt>rcu_read_unlock()</tt>, <tt>rcu_dereference()</tt>,
+and <tt>rcu_access_pointer()</tt>) will operate normally very early on,
+as will <tt>rcu_assign_pointer()</tt>.
+
+<p>
+Although <tt>call_rcu()</tt> may be invoked at any
+time during boot, callbacks are not guaranteed to be invoked until after
+the scheduler is fully up and running.
+This delay in callback invocation is due to the fact that RCU does not
+invoke callbacks until it is fully initialized, and this full initialization
+cannot occur until after the scheduler has initialized itself to the
+point where RCU can spawn and run its kthreads.
+In theory, it would be possible to invoke callbacks earlier,
+however, this is not a panacea because there would be severe restrictions
+on what operations those callbacks could invoke.
+
+<p>
+Perhaps surprisingly, <tt>synchronize_rcu()</tt>,
+<a href="#Bottom-Half Flavor"><tt>synchronize_rcu_bh()</tt></a>
+(<a href="#Bottom-Half Flavor">discussed below</a>),
+and
+<a href="#Sched Flavor"><tt>synchronize_sched()</tt></a>
+will all operate normally
+during very early boot, the reason being that there is only one CPU
+and preemption is disabled.
+This means that the call <tt>synchronize_rcu()</tt> (or friends)
+itself is a quiescent
+state and thus a grace period, so the early-boot implementation can
+be a no-op.
+
+<p>
+Both <tt>synchronize_rcu_bh()</tt> and <tt>synchronize_sched()</tt>
+continue to operate normally through the remainder of boot, courtesy
+of the fact that preemption is disabled across their RCU read-side
+critical sections and also courtesy of the fact that there is still
+only one CPU.
+However, once the scheduler starts initializing, preemption is enabled.
+There is still only a single CPU, but the fact that preemption is enabled
+means that the no-op implementation of <tt>synchronize_rcu()</tt> no
+longer works in <tt>CONFIG_PREEMPT=y</tt> kernels.
+Therefore, as soon as the scheduler starts initializing, the early-boot
+fastpath is disabled.
+This means that <tt>synchronize_rcu()</tt> switches to its runtime
+mode of operation where it posts callbacks, which in turn means that
+any call to <tt>synchronize_rcu()</tt> will block until the corresponding
+callback is invoked.
+Unfortunately, the callback cannot be invoked until RCU's runtime
+grace-period machinery is up and running, which cannot happen until
+the scheduler has initialized itself sufficiently to allow RCU's
+kthreads to be spawned.
+Therefore, invoking <tt>synchronize_rcu()</tt> during scheduler
+initialization can result in deadlock.
+
+<p>@@QQ@@
+So what happens with <tt>synchronize_rcu()</tt> during
+scheduler initialization for <tt>CONFIG_PREEMPT=n</tt>
+kernels?
+<p>@@QQA@@
+In <tt>CONFIG_PREEMPT=n</tt> kernel, <tt>synchronize_rcu()</tt>
+maps directly to <tt>synchronize_sched()</tt>.
+Therefore, <tt>synchronize_rcu()</tt> works normally throughout
+boot in <tt>CONFIG_PREEMPT=n</tt> kernels.
+However, your code must also work in <tt>CONFIG_PREEMPT=y</tt> kernels,
+so it is still necessary to avoid invoking <tt>synchronize_rcu()</tt>
+during scheduler initialization.
+<p>@@QQE@@
+
+<p>
+I learned of these boot-time requirements as a result of a series of
+system hangs.
+
+<h3><a name="Interrupts and NMIs">Interrupts and NMIs</a></h3>
+
+<p>
+The Linux kernel has interrupts, and RCU read-side critical sections are
+legal within interrupt handlers and within interrupt-disabled regions
+of code, as are invocations of <tt>call_rcu()</tt>.
+
+<p>
+Some Linux-kernel architectures can enter an interrupt handler from
+non-idle process context, and then just never leave it, instead stealthily
+transitioning back to process context.
+This trick is sometimes used to invoke system calls from inside the kernel.
+These &ldquo;half-interrupts&rdquo; mean that RCU has to be very careful
+about how it counts interrupt nesting levels.
+I learned of this requirement the hard way during a rewrite
+of RCU's dyntick-idle code.
+
+<p>
+The Linux kernel has non-maskable interrupts (NMIs), and
+RCU read-side critical sections are legal within NMI handlers.
+Thankfully, RCU update-side primitives, including
+<tt>call_rcu()</tt>, are prohibited within NMI handlers.
+
+<p>
+The name notwithstanding, some Linux-kernel architectures
+can have nested NMIs, which RCU must handle correctly.
+Andy Lutomirski
+<a href="https://lkml.kernel.org/g/CALCETrXLq1y7e_dKFPgou-FKHB6Pu-r8+t-6Ds+8=va7anBWDA@mail.gmail.com">surprised me</a>
+with this requirement;
+he also kindly surprised me with
+<a href="https://lkml.kernel.org/g/CALCETrXSY9JpW3uE6H8WYk81sg56qasA2aqmjMPsq5dOtzso=g@mail.gmail.com">an algorithm</a>
+that meets this requirement.
+
+<h3><a name="Loadable Modules">Loadable Modules</a></h3>
+
+<p>
+The Linux kernel has loadable modules, and these modules can
+also be unloaded.
+After a given module has been unloaded, any attempt to call
+one of its functions results in a segmentation fault.
+The module-unload functions must therefore cancel any
+delayed calls to loadable-module functions, for example,
+any outstanding <tt>mod_timer()</tt> must be dealt with
+via <tt>del_timer_sync()</tt> or similar.
+
+<p>
+Unfortunately, there is no way to cancel an RCU callback;
+once you invoke <tt>call_rcu()</tt>, the callback function is
+going to eventually be invoked, unless the system goes down first.
+Because it is normally considered socially irresponsible to crash the system
+in response to a module unload request, we need some other way
+to deal with in-flight RCU callbacks.
+
+<p>
+RCU therefore provides
+<tt><a href="https://lwn.net/Articles/217484/">rcu_barrier()</a></tt>,
+which waits until all in-flight RCU callbacks have been invoked.
+If a module uses <tt>call_rcu()</tt>, its exit function should therefore
+prevent any future invocation of <tt>call_rcu()</tt>, then invoke
+<tt>rcu_barrier()</tt>.
+In theory, the underlying module-unload code could invoke
+<tt>rcu_barrier()</tt> unconditionally, but in practice this would
+incur unacceptable latencies.
+
+<p>
+Nikita Danilov noted this requirement for an analogous filesystem-unmount
+situation, and Dipankar Sarma incorporated <tt>rcu_barrier()</tt> into RCU.
+The need for <tt>rcu_barrier()</tt> for module unloading became
+apparent later.
+
+<h3><a name="Hotplug CPU">Hotplug CPU</a></h3>
+
+<p>
+The Linux kernel supports CPU hotplug, which means that CPUs
+can come and go.
+It is of course illegal to use any RCU API member from an offline CPU.
+This requirement was present from day one in DYNIX/ptx, but
+on the other hand, the Linux kernel's CPU-hotplug implementation
+is &ldquo;interesting.&rdquo;
+
+<p>
+The Linux-kernel CPU-hotplug implementation has notifiers that
+are used to allow the various kernel subsystems (including RCU)
+to respond appropriately to a given CPU-hotplug operation.
+Most RCU operations may be invoked from CPU-hotplug notifiers,
+including even normal synchronous grace-period operations
+such as <tt>synchronize_rcu()</tt>.
+However, expedited grace-period operations such as
+<tt>synchronize_rcu_expedited()</tt> are not supported,
+due to the fact that current implementations block CPU-hotplug
+operations, which could result in deadlock.
+
+<p>
+In addition, all-callback-wait operations such as
+<tt>rcu_barrier()</tt> are also not supported, due to the
+fact that there are phases of CPU-hotplug operations where
+the outgoing CPU's callbacks will not be invoked until after
+the CPU-hotplug operation ends, which could also result in deadlock.
+
+<h3><a name="Scheduler and RCU">Scheduler and RCU</a></h3>
+
+<p>
+RCU depends on the scheduler, and the scheduler uses RCU to
+protect some of its data structures.
+This means the scheduler is forbidden from acquiring
+the runqueue locks and the priority-inheritance locks
+in the middle of an outermost RCU read-side critical section unless either
+(1)&nbsp;it releases them before exiting that same
+RCU read-side critical section, or
+(2)&nbsp;interrupts are disabled across
+that entire RCU read-side critical section.
+This same prohibition also applies (recursively!) to any lock that is acquired
+while holding any lock to which this prohibition applies.
+Adhering to this rule prevents preemptible RCU from invoking
+<tt>rcu_read_unlock_special()</tt> while either runqueue or
+priority-inheritance locks are held, thus avoiding deadlock.
+
+<p>
+Prior to v4.4, it was only necessary to disable preemption across
+RCU read-side critical sections that acquired scheduler locks.
+In v4.4, expedited grace periods started using IPIs, and these
+IPIs could force a <tt>rcu_read_unlock()</tt> to take the slowpath.
+Therefore, this expedited-grace-period change required disabling of
+interrupts, not just preemption.
+
+<p>
+For RCU's part, the preemptible-RCU <tt>rcu_read_unlock()</tt>
+implementation must be written carefully to avoid similar deadlocks.
+In particular, <tt>rcu_read_unlock()</tt> must tolerate an
+interrupt where the interrupt handler invokes both
+<tt>rcu_read_lock()</tt> and <tt>rcu_read_unlock()</tt>.
+This possibility requires <tt>rcu_read_unlock()</tt> to use
+negative nesting levels to avoid destructive recursion via
+interrupt handler's use of RCU.
+
+<p>
+This pair of mutual scheduler-RCU requirements came as a
+<a href="https://lwn.net/Articles/453002/">complete surprise</a>.
+
+<p>
+As noted above, RCU makes use of kthreads, and it is necessary to
+avoid excessive CPU-time accumulation by these kthreads.
+This requirement was no surprise, but RCU's violation of it
+when running context-switch-heavy workloads when built with
+<tt>CONFIG_NO_HZ_FULL=y</tt>
+<a href="http://www.rdrop.com/users/paulmck/scalability/paper/BareMetal.2015.01.15b.pdf">did come as a surprise [PDF]</a>.
+RCU has made good progress towards meeting this requirement, even
+for context-switch-have <tt>CONFIG_NO_HZ_FULL=y</tt> workloads,
+but there is room for further improvement.
+
+<h3><a name="Tracing and RCU">Tracing and RCU</a></h3>
+
+<p>
+It is possible to use tracing on RCU code, but tracing itself
+uses RCU.
+For this reason, <tt>rcu_dereference_raw_notrace()</tt>
+is provided for use by tracing, which avoids the destructive
+recursion that could otherwise ensue.
+This API is also used by virtualization in some architectures,
+where RCU readers execute in environments in which tracing
+cannot be used.
+The tracing folks both located the requirement and provided the
+needed fix, so this surprise requirement was relatively painless.
+
+<h3><a name="Energy Efficiency">Energy Efficiency</a></h3>
+
+<p>
+Interrupting idle CPUs is considered socially unacceptable,
+especially by people with battery-powered embedded systems.
+RCU therefore conserves energy by detecting which CPUs are
+idle, including tracking CPUs that have been interrupted from idle.
+This is a large part of the energy-efficiency requirement,
+so I learned of this via an irate phone call.
+
+<p>
+Because RCU avoids interrupting idle CPUs, it is illegal to
+execute an RCU read-side critical section on an idle CPU.
+(Kernels built with <tt>CONFIG_PROVE_RCU=y</tt> will splat
+if you try it.)
+The <tt>RCU_NONIDLE()</tt> macro and <tt>_rcuidle</tt>
+event tracing is provided to work around this restriction.
+In addition, <tt>rcu_is_watching()</tt> may be used to
+test whether or not it is currently legal to run RCU read-side
+critical sections on this CPU.
+I learned of the need for diagnostics on the one hand
+and <tt>RCU_NONIDLE()</tt> on the other while inspecting
+idle-loop code.
+Steven Rostedt supplied <tt>_rcuidle</tt> event tracing,
+which is used quite heavily in the idle loop.
+
+<p>
+It is similarly socially unacceptable to interrupt an
+<tt>nohz_full</tt> CPU running in userspace.
+RCU must therefore track <tt>nohz_full</tt> userspace
+execution.
+And in
+<a href="https://lwn.net/Articles/558284/"><tt>CONFIG_NO_HZ_FULL_SYSIDLE=y</tt></a>
+kernels, RCU must separately track idle CPUs on the one hand and
+CPUs that are either idle or executing in userspace on the other.
+In both cases, RCU must be able to sample state at two points in
+time, and be able to determine whether or not some other CPU spent
+any time idle and/or executing in userspace.
+
+<p>
+These energy-efficiency requirements have proven quite difficult to
+understand and to meet, for example, there have been more than five
+clean-sheet rewrites of RCU's energy-efficiency code, the last of
+which was finally able to demonstrate
+<a href="http://www.rdrop.com/users/paulmck/realtime/paper/AMPenergy.2013.04.19a.pdf">real energy savings running on real hardware [PDF]</a>.
+As noted earlier,
+I learned of many of these requirements via angry phone calls:
+Flaming me on the Linux-kernel mailing list was apparently not
+sufficient to fully vent their ire at RCU's energy-efficiency bugs!
+
+<h3><a name="Memory Efficiency">Memory Efficiency</a></h3>
+
+<p>
+Although small-memory non-realtime systems can simply use Tiny RCU,
+code size is only one aspect of memory efficiency.
+Another aspect is the size of the <tt>rcu_head</tt> structure
+used by <tt>call_rcu()</tt> and <tt>kfree_rcu()</tt>.
+Although this structure contains nothing more than a pair of pointers,
+it does appear in many RCU-protected data structures, including
+some that are size critical.
+The <tt>page</tt> structure is a case in point, as evidenced by
+the many occurrences of the <tt>union</tt> keyword within that structure.
+
+<p>
+This need for memory efficiency is one reason that RCU uses hand-crafted
+singly linked lists to track the <tt>rcu_head</tt> structures that
+are waiting for a grace period to elapse.
+It is also the reason why <tt>rcu_head</tt> structures do not contain
+debug information, such as fields tracking the file and line of the
+<tt>call_rcu()</tt> or <tt>kfree_rcu()</tt> that posted them.
+Although this information might appear in debug-only kernel builds at some
+point, in the meantime, the <tt>-&gt;func</tt> field will often provide
+the needed debug information.
+
+<p>
+However, in some cases, the need for memory efficiency leads to even
+more extreme measures.
+Returning to the <tt>page</tt> structure, the <tt>rcu_head</tt> field
+shares storage with a great many other structures that are used at
+various points in the corresponding page's lifetime.
+In order to correctly resolve certain
+<a href="https://lkml.kernel.org/g/1439976106-137226-1-git-send-email-kirill.shutemov@linux.intel.com">race conditions</a>,
+the Linux kernel's memory-management subsystem needs a particular bit
+to remain zero during all phases of grace-period processing,
+and that bit happens to map to the bottom bit of the
+<tt>rcu_head</tt> structure's <tt>-&gt;next</tt> field.
+RCU makes this guarantee as long as <tt>call_rcu()</tt>
+is used to post the callback, as opposed to <tt>kfree_rcu()</tt>
+or some future &ldquo;lazy&rdquo;
+variant of <tt>call_rcu()</tt> that might one day be created for
+energy-efficiency purposes.
+
+<h3><a name="Performance, Scalability, Response Time, and Reliability">
+Performance, Scalability, Response Time, and Reliability</a></h3>
+
+<p>
+Expanding on the
+<a href="#Performance and Scalability">earlier discussion</a>,
+RCU is used heavily by hot code paths in performance-critical
+portions of the Linux kernel's networking, security, virtualization,
+and scheduling code paths.
+RCU must therefore use efficient implementations, especially in its
+read-side primitives.
+To that end, it would be good if preemptible RCU's implementation
+of <tt>rcu_read_lock()</tt> could be inlined, however, doing
+this requires resolving <tt>#include</tt> issues with the
+<tt>task_struct</tt> structure.
+
+<p>
+The Linux kernel supports hardware configurations with up to
+4096 CPUs, which means that RCU must be extremely scalable.
+Algorithms that involve frequent acquisitions of global locks or
+frequent atomic operations on global variables simply cannot be
+tolerated within the RCU implementation.
+RCU therefore makes heavy use of a combining tree based on the
+<tt>rcu_node</tt> structure.
+RCU is required to tolerate all CPUs continuously invoking any
+combination of RCU's runtime primitives with minimal per-operation
+overhead.
+In fact, in many cases, increasing load must <i>decrease</i> the
+per-operation overhead, witness the batching optimizations for
+<tt>synchronize_rcu()</tt>, <tt>call_rcu()</tt>,
+<tt>synchronize_rcu_expedited()</tt>, and <tt>rcu_barrier()</tt>.
+As a general rule, RCU must cheerfully accept whatever the
+rest of the Linux kernel decides to throw at it.
+
+<p>
+The Linux kernel is used for real-time workloads, especially
+in conjunction with the
+<a href="https://rt.wiki.kernel.org/index.php/Main_Page">-rt patchset</a>.
+The real-time-latency response requirements are such that the
+traditional approach of disabling preemption across RCU
+read-side critical sections is inappropriate.
+Kernels built with <tt>CONFIG_PREEMPT=y</tt> therefore
+use an RCU implementation that allows RCU read-side critical
+sections to be preempted.
+This requirement made its presence known after users made it
+clear that an earlier
+<a href="https://lwn.net/Articles/107930/">real-time patch</a>
+did not meet their needs, in conjunction with some
+<a href="https://lkml.kernel.org/g/20050318002026.GA2693@us.ibm.com">RCU issues</a>
+encountered by a very early version of the -rt patchset.
+
+<p>
+In addition, RCU must make do with a sub-100-microsecond real-time latency
+budget.
+In fact, on smaller systems with the -rt patchset, the Linux kernel
+provides sub-20-microsecond real-time latencies for the whole kernel,
+including RCU.
+RCU's scalability and latency must therefore be sufficient for
+these sorts of configurations.
+To my surprise, the sub-100-microsecond real-time latency budget
+<a href="http://www.rdrop.com/users/paulmck/realtime/paper/bigrt.2013.01.31a.LCA.pdf">
+applies to even the largest systems [PDF]</a>,
+up to and including systems with 4096 CPUs.
+This real-time requirement motivated the grace-period kthread, which
+also simplified handling of a number of race conditions.
+
+<p>
+Finally, RCU's status as a synchronization primitive means that
+any RCU failure can result in arbitrary memory corruption that can be
+extremely difficult to debug.
+This means that RCU must be extremely reliable, which in
+practice also means that RCU must have an aggressive stress-test
+suite.
+This stress-test suite is called <tt>rcutorture</tt>.
+
+<p>
+Although the need for <tt>rcutorture</tt> was no surprise,
+the current immense popularity of the Linux kernel is posing
+interesting&mdash;and perhaps unprecedented&mdash;validation
+challenges.
+To see this, keep in mind that there are well over one billion
+instances of the Linux kernel running today, given Android
+smartphones, Linux-powered televisions, and servers.
+This number can be expected to increase sharply with the advent of
+the celebrated Internet of Things.
+
+<p>
+Suppose that RCU contains a race condition that manifests on average
+once per million years of runtime.
+This bug will be occurring about three times per <i>day</i> across
+the installed base.
+RCU could simply hide behind hardware error rates, given that no one
+should really expect their smartphone to last for a million years.
+However, anyone taking too much comfort from this thought should
+consider the fact that in most jurisdictions, a successful multi-year
+test of a given mechanism, which might include a Linux kernel,
+suffices for a number of types of safety-critical certifications.
+In fact, rumor has it that the Linux kernel is already being used
+in production for safety-critical applications.
+I don't know about you, but I would feel quite bad if a bug in RCU
+killed someone.
+Which might explain my recent focus on validation and verification.
+
+<h2><a name="Other RCU Flavors">Other RCU Flavors</a></h2>
+
+<p>
+One of the more surprising things about RCU is that there are now
+no fewer than five <i>flavors</i>, or API families.
+In addition, the primary flavor that has been the sole focus up to
+this point has two different implementations, non-preemptible and
+preemptible.
+The other four flavors are listed below, with requirements for each
+described in a separate section.
+
+<ol>
+<li>   <a href="#Bottom-Half Flavor">Bottom-Half Flavor</a>
+<li>   <a href="#Sched Flavor">Sched Flavor</a>
+<li>   <a href="#Sleepable RCU">Sleepable RCU</a>
+<li>   <a href="#Tasks RCU">Tasks RCU</a>
+</ol>
+
+<h3><a name="Bottom-Half Flavor">Bottom-Half Flavor</a></h3>
+
+<p>
+The softirq-disable (AKA &ldquo;bottom-half&rdquo;,
+hence the &ldquo;_bh&rdquo; abbreviations)
+flavor of RCU, or <i>RCU-bh</i>, was developed by
+Dipankar Sarma to provide a flavor of RCU that could withstand the
+network-based denial-of-service attacks researched by Robert
+Olsson.
+These attacks placed so much networking load on the system
+that some of the CPUs never exited softirq execution,
+which in turn prevented those CPUs from ever executing a context switch,
+which, in the RCU implementation of that time, prevented grace periods
+from ever ending.
+The result was an out-of-memory condition and a system hang.
+
+<p>
+The solution was the creation of RCU-bh, which does
+<tt>local_bh_disable()</tt>
+across its read-side critical sections, and which uses the transition
+from one type of softirq processing to another as a quiescent state
+in addition to context switch, idle, user mode, and offline.
+This means that RCU-bh grace periods can complete even when some of
+the CPUs execute in softirq indefinitely, thus allowing algorithms
+based on RCU-bh to withstand network-based denial-of-service attacks.
+
+<p>
+Because
+<tt>rcu_read_lock_bh()</tt> and <tt>rcu_read_unlock_bh()</tt>
+disable and re-enable softirq handlers, any attempt to start a softirq
+handlers during the
+RCU-bh read-side critical section will be deferred.
+In this case, <tt>rcu_read_unlock_bh()</tt>
+will invoke softirq processing, which can take considerable time.
+One can of course argue that this softirq overhead should be associated
+with the code following the RCU-bh read-side critical section rather
+than <tt>rcu_read_unlock_bh()</tt>, but the fact
+is that most profiling tools cannot be expected to make this sort
+of fine distinction.
+For example, suppose that a three-millisecond-long RCU-bh read-side
+critical section executes during a time of heavy networking load.
+There will very likely be an attempt to invoke at least one softirq
+handler during that three milliseconds, but any such invocation will
+be delayed until the time of the <tt>rcu_read_unlock_bh()</tt>.
+This can of course make it appear at first glance as if
+<tt>rcu_read_unlock_bh()</tt> was executing very slowly.
+
+<p>
+The
+<a href="https://lwn.net/Articles/609973/#RCU Per-Flavor API Table">RCU-bh API</a>
+includes
+<tt>rcu_read_lock_bh()</tt>,
+<tt>rcu_read_unlock_bh()</tt>,
+<tt>rcu_dereference_bh()</tt>,
+<tt>rcu_dereference_bh_check()</tt>,
+<tt>synchronize_rcu_bh()</tt>,
+<tt>synchronize_rcu_bh_expedited()</tt>,
+<tt>call_rcu_bh()</tt>,
+<tt>rcu_barrier_bh()</tt>, and
+<tt>rcu_read_lock_bh_held()</tt>.
+
+<h3><a name="Sched Flavor">Sched Flavor</a></h3>
+
+<p>
+Before preemptible RCU, waiting for an RCU grace period had the
+side effect of also waiting for all pre-existing interrupt
+and NMI handlers.
+However, there are legitimate preemptible-RCU implementations that
+do not have this property, given that any point in the code outside
+of an RCU read-side critical section can be a quiescent state.
+Therefore, <i>RCU-sched</i> was created, which follows &ldquo;classic&rdquo;
+RCU in that an RCU-sched grace period waits for for pre-existing
+interrupt and NMI handlers.
+In kernels built with <tt>CONFIG_PREEMPT=n</tt>, the RCU and RCU-sched
+APIs have identical implementations, while kernels built with
+<tt>CONFIG_PREEMPT=y</tt> provide a separate implementation for each.
+
+<p>
+Note well that in <tt>CONFIG_PREEMPT=y</tt> kernels,
+<tt>rcu_read_lock_sched()</tt> and <tt>rcu_read_unlock_sched()</tt>
+disable and re-enable preemption, respectively.
+This means that if there was a preemption attempt during the
+RCU-sched read-side critical section, <tt>rcu_read_unlock_sched()</tt>
+will enter the scheduler, with all the latency and overhead entailed.
+Just as with <tt>rcu_read_unlock_bh()</tt>, this can make it look
+as if <tt>rcu_read_unlock_sched()</tt> was executing very slowly.
+However, the highest-priority task won't be preempted, so that task
+will enjoy low-overhead <tt>rcu_read_unlock_sched()</tt> invocations.
+
+<p>
+The
+<a href="https://lwn.net/Articles/609973/#RCU Per-Flavor API Table">RCU-sched API</a>
+includes
+<tt>rcu_read_lock_sched()</tt>,
+<tt>rcu_read_unlock_sched()</tt>,
+<tt>rcu_read_lock_sched_notrace()</tt>,
+<tt>rcu_read_unlock_sched_notrace()</tt>,
+<tt>rcu_dereference_sched()</tt>,
+<tt>rcu_dereference_sched_check()</tt>,
+<tt>synchronize_sched()</tt>,
+<tt>synchronize_rcu_sched_expedited()</tt>,
+<tt>call_rcu_sched()</tt>,
+<tt>rcu_barrier_sched()</tt>, and
+<tt>rcu_read_lock_sched_held()</tt>.
+However, anything that disables preemption also marks an RCU-sched
+read-side critical section, including
+<tt>preempt_disable()</tt> and <tt>preempt_enable()</tt>,
+<tt>local_irq_save()</tt> and <tt>local_irq_restore()</tt>,
+and so on.
+
+<h3><a name="Sleepable RCU">Sleepable RCU</a></h3>
+
+<p>
+For well over a decade, someone saying &ldquo;I need to block within
+an RCU read-side critical section&rdquo; was a reliable indication
+that this someone did not understand RCU.
+After all, if you are always blocking in an RCU read-side critical
+section, you can probably afford to use a higher-overhead synchronization
+mechanism.
+However, that changed with the advent of the Linux kernel's notifiers,
+whose RCU read-side critical
+sections almost never sleep, but sometimes need to.
+This resulted in the introduction of
+<a href="https://lwn.net/Articles/202847/">sleepable RCU</a>,
+or <i>SRCU</i>.
+
+<p>
+SRCU allows different domains to be defined, with each such domain
+defined by an instance of an <tt>srcu_struct</tt> structure.
+A pointer to this structure must be passed in to each SRCU function,
+for example, <tt>synchronize_srcu(&amp;ss)</tt>, where
+<tt>ss</tt> is the <tt>srcu_struct</tt> structure.
+The key benefit of these domains is that a slow SRCU reader in one
+domain does not delay an SRCU grace period in some other domain.
+That said, one consequence of these domains is that read-side code
+must pass a &ldquo;cookie&rdquo; from <tt>srcu_read_lock()</tt>
+to <tt>srcu_read_unlock()</tt>, for example, as follows:
+
+<blockquote>
+<pre>
+ 1 int idx;
+ 2
+ 3 idx = srcu_read_lock(&amp;ss);
+ 4 do_something();
+ 5 srcu_read_unlock(&amp;ss, idx);
+</pre>
+</blockquote>
+
+<p>
+As noted above, it is legal to block within SRCU read-side critical sections,
+however, with great power comes great responsibility.
+If you block forever in one of a given domain's SRCU read-side critical
+sections, then that domain's grace periods will also be blocked forever.
+Of course, one good way to block forever is to deadlock, which can
+happen if any operation in a given domain's SRCU read-side critical
+section can block waiting, either directly or indirectly, for that domain's
+grace period to elapse.
+For example, this results in a self-deadlock:
+
+<blockquote>
+<pre>
+ 1 int idx;
+ 2
+ 3 idx = srcu_read_lock(&amp;ss);
+ 4 do_something();
+ 5 synchronize_srcu(&amp;ss);
+ 6 srcu_read_unlock(&amp;ss, idx);
+</pre>
+</blockquote>
+
+<p>
+However, if line&nbsp;5 acquired a mutex that was held across
+a <tt>synchronize_srcu()</tt> for domain <tt>ss</tt>,
+deadlock would still be possible.
+Furthermore, if line&nbsp;5 acquired a mutex that was held across
+a <tt>synchronize_srcu()</tt> for some other domain <tt>ss1</tt>,
+and if an <tt>ss1</tt>-domain SRCU read-side critical section
+acquired another mutex that was held across as <tt>ss</tt>-domain
+<tt>synchronize_srcu()</tt>,
+deadlock would again be possible.
+Such a deadlock cycle could extend across an arbitrarily large number
+of different SRCU domains.
+Again, with great power comes great responsibility.
+
+<p>
+Unlike the other RCU flavors, SRCU read-side critical sections can
+run on idle and even offline CPUs.
+This ability requires that <tt>srcu_read_lock()</tt> and
+<tt>srcu_read_unlock()</tt> contain memory barriers, which means
+that SRCU readers will run a bit slower than would RCU readers.
+It also motivates the <tt>smp_mb__after_srcu_read_unlock()</tt>
+API, which, in combination with <tt>srcu_read_unlock()</tt>,
+guarantees a full memory barrier.
+
+<p>
+The
+<a href="https://lwn.net/Articles/609973/#RCU Per-Flavor API Table">SRCU API</a>
+includes
+<tt>srcu_read_lock()</tt>,
+<tt>srcu_read_unlock()</tt>,
+<tt>srcu_dereference()</tt>,
+<tt>srcu_dereference_check()</tt>,
+<tt>synchronize_srcu()</tt>,
+<tt>synchronize_srcu_expedited()</tt>,
+<tt>call_srcu()</tt>,
+<tt>srcu_barrier()</tt>, and
+<tt>srcu_read_lock_held()</tt>.
+It also includes
+<tt>DEFINE_SRCU()</tt>,
+<tt>DEFINE_STATIC_SRCU()</tt>, and
+<tt>init_srcu_struct()</tt>
+APIs for defining and initializing <tt>srcu_struct</tt> structures.
+
+<h3><a name="Tasks RCU">Tasks RCU</a></h3>
+
+<p>
+Some forms of tracing use &ldquo;tramopolines&rdquo; to handle the
+binary rewriting required to install different types of probes.
+It would be good to be able to free old trampolines, which sounds
+like a job for some form of RCU.
+However, because it is necessary to be able to install a trace
+anywhere in the code, it is not possible to use read-side markers
+such as <tt>rcu_read_lock()</tt> and <tt>rcu_read_unlock()</tt>.
+In addition, it does not work to have these markers in the trampoline
+itself, because there would need to be instructions following
+<tt>rcu_read_unlock()</tt>.
+Although <tt>synchronize_rcu()</tt> would guarantee that execution
+reached the <tt>rcu_read_unlock()</tt>, it would not be able to
+guarantee that execution had completely left the trampoline.
+
+<p>
+The solution, in the form of
+<a href="https://lwn.net/Articles/607117/"><i>Tasks RCU</i></a>,
+is to have implicit
+read-side critical sections that are delimited by voluntary context
+switches, that is, calls to <tt>schedule()</tt>,
+<tt>cond_resched_rcu_qs()</tt>, and
+<tt>synchronize_rcu_tasks()</tt>.
+In addition, transitions to and from userspace execution also delimit
+tasks-RCU read-side critical sections.
+
+<p>
+The tasks-RCU API is quite compact, consisting only of
+<tt>call_rcu_tasks()</tt>,
+<tt>synchronize_rcu_tasks()</tt>, and
+<tt>rcu_barrier_tasks()</tt>.
+
+<h2><a name="Possible Future Changes">Possible Future Changes</a></h2>
+
+<p>
+One of the tricks that RCU uses to attain update-side scalability is
+to increase grace-period latency with increasing numbers of CPUs.
+If this becomes a serious problem, it will be necessary to rework the
+grace-period state machine so as to avoid the need for the additional
+latency.
+
+<p>
+Expedited grace periods scan the CPUs, so their latency and overhead
+increases with increasing numbers of CPUs.
+If this becomes a serious problem on large systems, it will be necessary
+to do some redesign to avoid this scalability problem.
+
+<p>
+RCU disables CPU hotplug in a few places, perhaps most notably in the
+expedited grace-period and <tt>rcu_barrier()</tt> operations.
+If there is a strong reason to use expedited grace periods in CPU-hotplug
+notifiers, it will be necessary to avoid disabling CPU hotplug.
+This would introduce some complexity, so there had better be a <i>very</i>
+good reason.
+
+<p>
+The tradeoff between grace-period latency on the one hand and interruptions
+of other CPUs on the other hand may need to be re-examined.
+The desire is of course for zero grace-period latency as well as zero
+interprocessor interrupts undertaken during an expedited grace period
+operation.
+While this ideal is unlikely to be achievable, it is quite possible that
+further improvements can be made.
+
+<p>
+The multiprocessor implementations of RCU use a combining tree that
+groups CPUs so as to reduce lock contention and increase cache locality.
+However, this combining tree does not spread its memory across NUMA
+nodes nor does it align the CPU groups with hardware features such
+as sockets or cores.
+Such spreading and alignment is currently believed to be unnecessary
+because the hotpath read-side primitives do not access the combining
+tree, nor does <tt>call_rcu()</tt> in the common case.
+If you believe that your architecture needs such spreading and alignment,
+then your architecture should also benefit from the
+<tt>rcutree.rcu_fanout_leaf</tt> boot parameter, which can be set
+to the number of CPUs in a socket, NUMA node, or whatever.
+If the number of CPUs is too large, use a fraction of the number of
+CPUs.
+If the number of CPUs is a large prime number, well, that certainly
+is an &ldquo;interesting&rdquo; architectural choice!
+More flexible arrangements might be considered, but only if
+<tt>rcutree.rcu_fanout_leaf</tt> has proven inadequate, and only
+if the inadequacy has been demonstrated by a carefully run and
+realistic system-level workload.
+
+<p>
+Please note that arrangements that require RCU to remap CPU numbers will
+require extremely good demonstration of need and full exploration of
+alternatives.
+
+<p>
+There is an embarrassingly large number of flavors of RCU, and this
+number has been increasing over time.
+Perhaps it will be possible to combine some at some future date.
+
+<p>
+RCU's various kthreads are reasonably recent additions.
+It is quite likely that adjustments will be required to more gracefully
+handle extreme loads.
+It might also be necessary to be able to relate CPU utilization by
+RCU's kthreads and softirq handlers to the code that instigated this
+CPU utilization.
+For example, RCU callback overhead might be charged back to the
+originating <tt>call_rcu()</tt> instance, though probably not
+in production kernels.
+
+<h2><a name="Summary">Summary</a></h2>
+
+<p>
+This document has presented more than two decade's worth of RCU
+requirements.
+Given that the requirements keep changing, this will not be the last
+word on this subject, but at least it serves to get an important
+subset of the requirements set forth.
+
+<h2><a name="Acknowledgments">Acknowledgments</a></h2>
+
+I am grateful to Steven Rostedt, Lai Jiangshan, Ingo Molnar,
+Oleg Nesterov, Borislav Petkov, Peter Zijlstra, Boqun Feng, and
+Andy Lutomirski for their help in rendering
+this article human readable, and to Michelle Rankin for her support
+of this effort.
+Other contributions are acknowledged in the Linux kernel's git archive.
+The cartoon is copyright (c) 2013 by Melissa Broussard,
+and is provided
+under the terms of the Creative Commons Attribution-Share Alike 3.0
+United States license.
+
+<p>@@QQAL@@
+
+</body></html>
diff --git a/Documentation/RCU/Design/htmlqqz.sh b/Documentation/RCU/Design/htmlqqz.sh
new file mode 100755 (executable)
index 0000000..d354f06
--- /dev/null
@@ -0,0 +1,108 @@
+#!/bin/sh
+#
+# Usage: sh htmlqqz.sh file
+#
+# Extracts and converts quick quizzes in a proto-HTML document file.htmlx.
+# Commands, all of which must be on a line by themselves:
+#
+#      "<p>@@QQ@@": Start of a quick quiz.
+#      "<p>@@QQA@@": Start of a quick-quiz answer.
+#      "<p>@@QQE@@": End of a quick-quiz answer, and thus of the quick quiz.
+#      "<p>@@QQAL@@": Place to put quick-quiz answer list.
+#
+# Places the result in file.html.
+#
+# This program is 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, you can access it online at
+# http://www.gnu.org/licenses/gpl-2.0.html.
+#
+# Copyright (c) 2013 Paul E. McKenney, IBM Corporation.
+
+fn=$1
+if test ! -r $fn.htmlx
+then
+       echo "Error: $fn.htmlx unreadable."
+       exit 1
+fi
+
+echo "<!-- DO NOT HAND EDIT. -->" > $fn.html
+echo "<!-- Instead, edit $fn.htmlx and run 'sh htmlqqz.sh $fn' -->" >> $fn.html
+awk < $fn.htmlx >> $fn.html '
+
+state == "" && $1 != "<p>@@QQ@@" && $1 != "<p>@@QQAL@@" {
+       print $0;
+       if ($0 ~ /^<p>@@QQ/)
+               print "Bad Quick Quiz command: " NR " (expected <p>@@QQ@@ or <p>@@QQAL@@)." > "/dev/stderr"
+       next;
+}
+
+state == "" && $1 == "<p>@@QQ@@" {
+       qqn++;
+       qqlineno = NR;
+       haveqq = 1;
+       state = "qq";
+       print "<p><a name=\"Quick Quiz " qqn "\"><b>Quick Quiz " qqn "</b>:</a>"
+       next;
+}
+
+state == "qq" && $1 != "<p>@@QQA@@" {
+       qq[qqn] = qq[qqn] $0 "\n";
+       print $0
+       if ($0 ~ /^<p>@@QQ/)
+               print "Bad Quick Quiz command: " NR ". (expected <p>@@QQA@@)" > "/dev/stderr"
+       next;
+}
+
+state == "qq" && $1 == "<p>@@QQA@@" {
+       state = "qqa";
+       print "<br><a href=\"#qq" qqn "answer\">Answer</a>"
+       next;
+}
+
+state == "qqa" && $1 != "<p>@@QQE@@" {
+       qqa[qqn] = qqa[qqn] $0 "\n";
+       if ($0 ~ /^<p>@@QQ/)
+               print "Bad Quick Quiz command: " NR " (expected <p>@@QQE@@)." > "/dev/stderr"
+       next;
+}
+
+state == "qqa" && $1 == "<p>@@QQE@@" {
+       state = "";
+       next;
+}
+
+state == "" && $1 == "<p>@@QQAL@@" {
+       haveqq = "";
+       print "<h3><a name=\"Answers to Quick Quizzes\">"
+       print "Answers to Quick Quizzes</a></h3>"
+       print "";
+       for (i = 1; i <= qqn; i++) {
+               print "<a name=\"qq" i "answer\"></a>"
+               print "<p><b>Quick Quiz " i "</b>:"
+               print qq[i];
+               print "";
+               print "</p><p><b>Answer</b>:"
+               print qqa[i];
+               print "";
+               print "</p><p><a href=\"#Quick%20Quiz%20" i "\"><b>Back to Quick Quiz " i "</b>.</a>"
+               print "";
+       }
+       next;
+}
+
+END {
+       if (state != "")
+               print "Unterminated Quick Quiz: " qqlineno "." > "/dev/stderr"
+       else if (haveqq)
+               print "Missing \"<p>@@QQAL@@\", no Quick Quiz." > "/dev/stderr"
+}'
diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
new file mode 100644 (file)
index 0000000..58b71dd
--- /dev/null
@@ -0,0 +1,58 @@
+                Silicon Errata and Software Workarounds
+                =======================================
+
+Author: Will Deacon <will.deacon@arm.com>
+Date  : 27 November 2015
+
+It is an unfortunate fact of life that hardware is often produced with
+so-called "errata", which can cause it to deviate from the architecture
+under specific circumstances.  For hardware produced by ARM, these
+errata are broadly classified into the following categories:
+
+  Category A: A critical error without a viable workaround.
+  Category B: A significant or critical error with an acceptable
+              workaround.
+  Category C: A minor error that is not expected to occur under normal
+              operation.
+
+For more information, consult one of the "Software Developers Errata
+Notice" documents available on infocenter.arm.com (registration
+required).
+
+As far as Linux is concerned, Category B errata may require some special
+treatment in the operating system. For example, avoiding a particular
+sequence of code, or configuring the processor in a particular way. A
+less common situation may require similar actions in order to declassify
+a Category A erratum into a Category C erratum. These are collectively
+known as "software workarounds" and are only required in the minority of
+cases (e.g. those cases that both require a non-secure workaround *and*
+can be triggered by Linux).
+
+For software workarounds that may adversely impact systems unaffected by
+the erratum in question, a Kconfig entry is added under "Kernel
+Features" -> "ARM errata workarounds via the alternatives framework".
+These are enabled by default and patched in at runtime when an affected
+CPU is detected. For less-intrusive workarounds, a Kconfig option is not
+available and the code is structured (preferably with a comment) in such
+a way that the erratum will not be hit.
+
+This approach can make it slightly onerous to determine exactly which
+errata are worked around in an arbitrary kernel source tree, so this
+file acts as a registry of software workarounds in the Linux Kernel and
+will be updated when new workarounds are committed and backported to
+stable kernels.
+
+| Implementor    | Component       | Erratum ID      | Kconfig                 |
++----------------+-----------------+-----------------+-------------------------+
+| ARM            | Cortex-A53      | #826319         | ARM64_ERRATUM_826319    |
+| ARM            | Cortex-A53      | #827319         | ARM64_ERRATUM_827319    |
+| ARM            | Cortex-A53      | #824069         | ARM64_ERRATUM_824069    |
+| ARM            | Cortex-A53      | #819472         | ARM64_ERRATUM_819472    |
+| ARM            | Cortex-A53      | #845719         | ARM64_ERRATUM_845719    |
+| ARM            | Cortex-A53      | #843419         | ARM64_ERRATUM_843419    |
+| ARM            | Cortex-A57      | #832075         | ARM64_ERRATUM_832075    |
+| ARM            | Cortex-A57      | #852523         | N/A                     |
+| ARM            | Cortex-A57      | #834220         | ARM64_ERRATUM_834220    |
+|                |                 |                 |                         |
+| Cavium         | ThunderX ITS    | #22375, #24313  | CAVIUM_ERRATUM_22375    |
+| Cavium         | ThunderX GICv3  | #23154          | CAVIUM_ERRATUM_23154    |
index e15bc1a0fb98ab23563681210cc6ed1865234816..89fd8f9a259f69b9c9423da9bb16771ed0596cad 100644 (file)
@@ -18,11 +18,11 @@ Construction Parameters
 
     0 is the original format used in the Chromium OS.
       The salt is appended when hashing, digests are stored continuously and
-      the rest of the block is padded with zeros.
+      the rest of the block is padded with zeroes.
 
     1 is the current format that should be used for new devices.
       The salt is prepended when hashing and each digest is
-      padded with zeros to the power of two.
+      padded with zeroes to the power of two.
 
 <dev>
     This is the device containing data, the integrity of which needs to be
@@ -79,6 +79,37 @@ restart_on_corruption
     not compatible with ignore_corruption and requires user space support to
     avoid restart loops.
 
+ignore_zero_blocks
+    Do not verify blocks that are expected to contain zeroes and always return
+    zeroes instead. This may be useful if the partition contains unused blocks
+    that are not guaranteed to contain zeroes.
+
+use_fec_from_device <fec_dev>
+    Use forward error correction (FEC) to recover from corruption if hash
+    verification fails. Use encoding data from the specified device. This
+    may be the same device where data and hash blocks reside, in which case
+    fec_start must be outside data and hash areas.
+
+    If the encoding data covers additional metadata, it must be accessible
+    on the hash device after the hash blocks.
+
+    Note: block sizes for data and hash devices must match. Also, if the
+    verity <dev> is encrypted the <fec_dev> should be too.
+
+fec_roots <num>
+    Number of generator roots. This equals to the number of parity bytes in
+    the encoding data. For example, in RS(M, N) encoding, the number of roots
+    is M-N.
+
+fec_blocks <num>
+    The number of encoding data blocks on the FEC device. The block size for
+    the FEC device is <data_block_size>.
+
+fec_start <offset>
+    This is the offset, in <data_block_size> blocks, from the start of the
+    FEC device to the beginning of the encoding data.
+
+
 Theory of operation
 ===================
 
@@ -98,6 +129,11 @@ per-block basis. This allows for a lightweight hash computation on first read
 into the page cache. Block hashes are stored linearly, aligned to the nearest
 block size.
 
+If forward error correction (FEC) support is enabled any recovery of
+corrupted data will be verified using the cryptographic hash of the
+corresponding data. This is why combining error correction with
+integrity checking is essential.
+
 Hash Tree
 ---------
 
diff --git a/Documentation/devicetree/bindings/arm/l2c2x0.txt b/Documentation/devicetree/bindings/arm/l2c2x0.txt
new file mode 100644 (file)
index 0000000..fe0398c
--- /dev/null
@@ -0,0 +1,105 @@
+* ARM L2 Cache Controller
+
+ARM cores often have a separate L2C210/L2C220/L2C310 (also known as PL210/PL220/
+PL310 and variants) based level 2 cache controller. All these various implementations
+of the L2 cache controller have compatible programming models (Note 1).
+Some of the properties that are just prefixed "cache-*" are taken from section
+3.7.3 of the ePAPR v1.1 specification which can be found at:
+https://www.power.org/wp-content/uploads/2012/06/Power_ePAPR_APPROVED_v1.1.pdf
+
+The ARM L2 cache representation in the device tree should be done as follows:
+
+Required properties:
+
+- compatible : should be one of:
+  "arm,pl310-cache"
+  "arm,l220-cache"
+  "arm,l210-cache"
+  "bcm,bcm11351-a2-pl310-cache": DEPRECATED by "brcm,bcm11351-a2-pl310-cache"
+  "brcm,bcm11351-a2-pl310-cache": For Broadcom bcm11351 chipset where an
+     offset needs to be added to the address before passing down to the L2
+     cache controller
+  "marvell,aurora-system-cache": Marvell Controller designed to be
+     compatible with the ARM one, with system cache mode (meaning
+     maintenance operations on L1 are broadcasted to the L2 and L2
+     performs the same operation).
+  "marvell,aurora-outer-cache": Marvell Controller designed to be
+     compatible with the ARM one with outer cache mode.
+  "marvell,tauros3-cache": Marvell Tauros3 cache controller, compatible
+     with arm,pl310-cache controller.
+- cache-unified : Specifies the cache is a unified cache.
+- cache-level : Should be set to 2 for a level 2 cache.
+- reg : Physical base address and size of cache controller's memory mapped
+  registers.
+
+Optional properties:
+
+- arm,data-latency : Cycles of latency for Data RAM accesses. Specifies 3 cells of
+  read, write and setup latencies. Minimum valid values are 1. Controllers
+  without setup latency control should use a value of 0.
+- arm,tag-latency : Cycles of latency for Tag RAM accesses. Specifies 3 cells of
+  read, write and setup latencies. Controllers without setup latency control
+  should use 0. Controllers without separate read and write Tag RAM latency
+  values should only use the first cell.
+- arm,dirty-latency : Cycles of latency for Dirty RAMs. This is a single cell.
+- arm,filter-ranges : <start length> Starting address and length of window to
+  filter. Addresses in the filter window are directed to the M1 port. Other
+  addresses will go to the M0 port.
+- arm,io-coherent : indicates that the system is operating in an hardware
+  I/O coherent mode. Valid only when the arm,pl310-cache compatible
+  string is used.
+- interrupts : 1 combined interrupt.
+- cache-size : specifies the size in bytes of the cache
+- cache-sets : specifies the number of associativity sets of the cache
+- cache-block-size : specifies the size in bytes of a cache block
+- cache-line-size : specifies the size in bytes of a line in the cache,
+  if this is not specified, the line size is assumed to be equal to the
+  cache block size
+- cache-id-part: cache id part number to be used if it is not present
+  on hardware
+- wt-override: If present then L2 is forced to Write through mode
+- arm,double-linefill : Override double linefill enable setting. Enable if
+  non-zero, disable if zero.
+- arm,double-linefill-incr : Override double linefill on INCR read. Enable
+  if non-zero, disable if zero.
+- arm,double-linefill-wrap : Override double linefill on WRAP read. Enable
+  if non-zero, disable if zero.
+- arm,prefetch-drop : Override prefetch drop enable setting. Enable if non-zero,
+  disable if zero.
+- arm,prefetch-offset : Override prefetch offset value. Valid values are
+  0-7, 15, 23, and 31.
+- arm,shared-override : The default behavior of the L220 or PL310 cache
+  controllers with respect to the shareable attribute is to transform "normal
+  memory non-cacheable transactions" into "cacheable no allocate" (for reads)
+  or "write through no write allocate" (for writes).
+  On systems where this may cause DMA buffer corruption, this property must be
+  specified to indicate that such transforms are precluded.
+- arm,parity-enable : enable parity checking on the L2 cache (L220 or PL310).
+- arm,parity-disable : disable parity checking on the L2 cache (L220 or PL310).
+- arm,outer-sync-disable : disable the outer sync operation on the L2 cache.
+  Some core tiles, especially ARM PB11MPCore have a faulty L220 cache that
+  will randomly hang unless outer sync operations are disabled.
+- prefetch-data : Data prefetch. Value: <0> (forcibly disable), <1>
+  (forcibly enable), property absent (retain settings set by firmware)
+- prefetch-instr : Instruction prefetch. Value: <0> (forcibly disable),
+  <1> (forcibly enable), property absent (retain settings set by
+  firmware)
+
+Example:
+
+L2: cache-controller {
+        compatible = "arm,pl310-cache";
+        reg = <0xfff12000 0x1000>;
+        arm,data-latency = <1 1 1>;
+        arm,tag-latency = <2 2 2>;
+        arm,filter-ranges = <0x80000000 0x8000000>;
+        cache-unified;
+        cache-level = <2>;
+       interrupts = <45>;
+};
+
+Note 1: The description in this document doesn't apply to integrated L2
+       cache controllers as found in e.g. Cortex-A15/A7/A57/A53. These
+       integrated L2 controllers are assumed to be all preconfigured by
+       early secure boot code. Thus no need to deal with their configuration
+       in the kernel at all.
diff --git a/Documentation/devicetree/bindings/arm/l2cc.txt b/Documentation/devicetree/bindings/arm/l2cc.txt
deleted file mode 100644 (file)
index 06c88a4..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-* ARM L2 Cache Controller
-
-ARM cores often have a separate level 2 cache controller. There are various
-implementations of the L2 cache controller with compatible programming models.
-Some of the properties that are just prefixed "cache-*" are taken from section
-3.7.3 of the ePAPR v1.1 specification which can be found at:
-https://www.power.org/wp-content/uploads/2012/06/Power_ePAPR_APPROVED_v1.1.pdf
-
-The ARM L2 cache representation in the device tree should be done as follows:
-
-Required properties:
-
-- compatible : should be one of:
-  "arm,pl310-cache"
-  "arm,l220-cache"
-  "arm,l210-cache"
-  "bcm,bcm11351-a2-pl310-cache": DEPRECATED by "brcm,bcm11351-a2-pl310-cache"
-  "brcm,bcm11351-a2-pl310-cache": For Broadcom bcm11351 chipset where an
-     offset needs to be added to the address before passing down to the L2
-     cache controller
-  "marvell,aurora-system-cache": Marvell Controller designed to be
-     compatible with the ARM one, with system cache mode (meaning
-     maintenance operations on L1 are broadcasted to the L2 and L2
-     performs the same operation).
-  "marvell,aurora-outer-cache": Marvell Controller designed to be
-     compatible with the ARM one with outer cache mode.
-  "marvell,tauros3-cache": Marvell Tauros3 cache controller, compatible
-     with arm,pl310-cache controller.
-- cache-unified : Specifies the cache is a unified cache.
-- cache-level : Should be set to 2 for a level 2 cache.
-- reg : Physical base address and size of cache controller's memory mapped
-  registers.
-
-Optional properties:
-
-- arm,data-latency : Cycles of latency for Data RAM accesses. Specifies 3 cells of
-  read, write and setup latencies. Minimum valid values are 1. Controllers
-  without setup latency control should use a value of 0.
-- arm,tag-latency : Cycles of latency for Tag RAM accesses. Specifies 3 cells of
-  read, write and setup latencies. Controllers without setup latency control
-  should use 0. Controllers without separate read and write Tag RAM latency
-  values should only use the first cell.
-- arm,dirty-latency : Cycles of latency for Dirty RAMs. This is a single cell.
-- arm,filter-ranges : <start length> Starting address and length of window to
-  filter. Addresses in the filter window are directed to the M1 port. Other
-  addresses will go to the M0 port.
-- arm,io-coherent : indicates that the system is operating in an hardware
-  I/O coherent mode. Valid only when the arm,pl310-cache compatible
-  string is used.
-- interrupts : 1 combined interrupt.
-- cache-size : specifies the size in bytes of the cache
-- cache-sets : specifies the number of associativity sets of the cache
-- cache-block-size : specifies the size in bytes of a cache block
-- cache-line-size : specifies the size in bytes of a line in the cache,
-  if this is not specified, the line size is assumed to be equal to the
-  cache block size
-- cache-id-part: cache id part number to be used if it is not present
-  on hardware
-- wt-override: If present then L2 is forced to Write through mode
-- arm,double-linefill : Override double linefill enable setting. Enable if
-  non-zero, disable if zero.
-- arm,double-linefill-incr : Override double linefill on INCR read. Enable
-  if non-zero, disable if zero.
-- arm,double-linefill-wrap : Override double linefill on WRAP read. Enable
-  if non-zero, disable if zero.
-- arm,prefetch-drop : Override prefetch drop enable setting. Enable if non-zero,
-  disable if zero.
-- arm,prefetch-offset : Override prefetch offset value. Valid values are
-  0-7, 15, 23, and 31.
-- arm,shared-override : The default behavior of the pl310 cache controller with
-  respect to the shareable attribute is to transform "normal memory
-  non-cacheable transactions" into "cacheable no allocate" (for reads) or
-  "write through no write allocate" (for writes).
-  On systems where this may cause DMA buffer corruption, this property must be
-  specified to indicate that such transforms are precluded.
-- prefetch-data : Data prefetch. Value: <0> (forcibly disable), <1>
-  (forcibly enable), property absent (retain settings set by firmware)
-- prefetch-instr : Instruction prefetch. Value: <0> (forcibly disable),
-  <1> (forcibly enable), property absent (retain settings set by
-  firmware)
-
-Example:
-
-L2: cache-controller {
-        compatible = "arm,pl310-cache";
-        reg = <0xfff12000 0x1000>;
-        arm,data-latency = <1 1 1>;
-        arm,tag-latency = <2 2 2>;
-        arm,filter-ranges = <0x80000000 0x8000000>;
-        cache-unified;
-        cache-level = <2>;
-       interrupts = <45>;
-};
index 97ba45af04fc693f831c00f15f9388df864434a6..56518839f52a7908922aa9a88d60575be57cdbe3 100644 (file)
@@ -9,8 +9,9 @@ Required properties:
 - compatible : should be one of
        "apm,potenza-pmu"
        "arm,armv8-pmuv3"
-       "arm.cortex-a57-pmu"
-       "arm.cortex-a53-pmu"
+       "arm,cortex-a72-pmu"
+       "arm,cortex-a57-pmu"
+       "arm,cortex-a53-pmu"
        "arm,cortex-a17-pmu"
        "arm,cortex-a15-pmu"
        "arm,cortex-a12-pmu"
index 20ac9bbfa1fda45e4d59e67ace1a202f98f1ee25..60872838f1adb772d04e0db6b50678d850be2a73 100644 (file)
@@ -4,7 +4,9 @@ SATA nodes are defined to describe on-chip Serial ATA controllers.
 Each SATA controller should have its own node.
 
 Required properties:
-- compatible         : compatible list, may contain "brcm,bcm7445-ahci" and/or
+- compatible         : should be one or more of
+                       "brcm,bcm7425-ahci"
+                       "brcm,bcm7445-ahci"
                        "brcm,sata3-ahci"
 - reg                : register mappings for AHCI and SATA_TOP_CTRL
 - reg-names          : "ahci" and "top-ctrl"
index 2493a5a316551de878c1be87d6e86f20f090e985..0764f9ab63dcde31f7efff01f74e56c5c6fa1c56 100644 (file)
@@ -8,6 +8,7 @@ Required properties:
                          - "renesas,sata-r8a7790" for R-Car H2 other than ES1
                          - "renesas,sata-r8a7791" for R-Car M2-W
                          - "renesas,sata-r8a7793" for R-Car M2-N
+                         - "renesas,sata-r8a7795" for R-Car H3
 - reg                  : address and length of the SATA registers;
 - interrupts           : must consist of one interrupt specifier.
 - clocks               : must contain a reference to the functional clock.
diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun67i-sc-nmi.txt b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun67i-sc-nmi.txt
deleted file mode 100644 (file)
index d1c5cda..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-Allwinner Sunxi NMI Controller
-==============================
-
-Required properties:
-
-- compatible : should be "allwinner,sun7i-a20-sc-nmi" or
-  "allwinner,sun6i-a31-sc-nmi"
-- reg : Specifies base physical address and size of the registers.
-- interrupt-controller : Identifies the node as an interrupt controller
-- #interrupt-cells : Specifies the number of cells needed to encode an
-  interrupt source. The value shall be 2. The first cell is the IRQ number, the
-  second cell the trigger type as defined in interrupt.txt in this directory.
-- interrupt-parent: Specifies the parent interrupt controller.
-- interrupts: Specifies the interrupt line (NMI) which is handled by
-  the interrupt controller in the parent controller's notation. This value
-  shall be the NMI.
-
-Example:
-
-sc-nmi-intc@01c00030 {
-       compatible = "allwinner,sun7i-a20-sc-nmi";
-       interrupt-controller;
-       #interrupt-cells = <2>;
-       reg = <0x01c00030 0x0c>;
-       interrupt-parent = <&gic>;
-       interrupts = <0 0 4>;
-};
diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sunxi-nmi.txt b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sunxi-nmi.txt
new file mode 100644 (file)
index 0000000..81cd369
--- /dev/null
@@ -0,0 +1,27 @@
+Allwinner Sunxi NMI Controller
+==============================
+
+Required properties:
+
+- compatible : should be "allwinner,sun7i-a20-sc-nmi" or
+  "allwinner,sun6i-a31-sc-nmi" or "allwinner,sun9i-a80-nmi"
+- reg : Specifies base physical address and size of the registers.
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The value shall be 2. The first cell is the IRQ number, the
+  second cell the trigger type as defined in interrupt.txt in this directory.
+- interrupt-parent: Specifies the parent interrupt controller.
+- interrupts: Specifies the interrupt line (NMI) which is handled by
+  the interrupt controller in the parent controller's notation. This value
+  shall be the NMI.
+
+Example:
+
+sc-nmi-intc@01c00030 {
+       compatible = "allwinner,sun7i-a20-sc-nmi";
+       interrupt-controller;
+       #interrupt-cells = <2>;
+       reg = <0x01c00030 0x0c>;
+       interrupt-parent = <&gic>;
+       interrupts = <0 0 4>;
+};
index cc56021eb60babea6c580bfbe594aca3c17dfce5..5a1cb4bc3dfe84c67664c65eeb2a64ac4a92c1ff 100644 (file)
@@ -18,6 +18,7 @@ Main node required properties:
        "arm,cortex-a9-gic"
        "arm,gic-400"
        "arm,pl390"
+       "arm,tc11mp-gic"
        "brcm,brahma-b15-gic"
        "qcom,msm-8660-qgic"
        "qcom,msm-qgic2"
diff --git a/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt b/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
new file mode 100644 (file)
index 0000000..720f7c9
--- /dev/null
@@ -0,0 +1,74 @@
+Hisilicon mbigen device tree bindings.
+=======================================
+
+Mbigen means: message based interrupt generator.
+
+MBI is kind of msi interrupt only used on Non-PCI devices.
+
+To reduce the wired interrupt number connected to GIC,
+Hisilicon designed mbigen to collect and generate interrupt.
+
+
+Non-pci devices can connect to mbigen and generate the
+interrupt by writing ITS register.
+
+The mbigen chip and devices connect to mbigen have the following properties:
+
+Mbigen main node required properties:
+-------------------------------------------
+- compatible: Should be "hisilicon,mbigen-v2"
+
+- reg: Specifies the base physical address and size of the Mbigen
+  registers.
+
+- interrupt controller: Identifies the node as an interrupt controller
+
+- msi-parent: Specifies the MSI controller this mbigen use.
+  For more detail information,please refer to the generic msi-parent binding in
+  Documentation/devicetree/bindings/interrupt-controller/msi.txt.
+
+- num-pins: the total number of pins implemented in this Mbigen
+  instance.
+
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The value must be 2.
+
+  The 1st cell is hardware pin number of the interrupt.This number is local to
+  each mbigen chip and in the range from 0 to the maximum interrupts number
+  of the mbigen.
+
+  The 2nd cell is the interrupt trigger type.
+       The value of this cell should be:
+       1: rising edge triggered
+       or
+       4: high level triggered
+
+Examples:
+
+       mbigen_device_gmac:intc {
+                       compatible = "hisilicon,mbigen-v2";
+                       reg = <0x0 0xc0080000 0x0 0x10000>;
+                       interrupt-controller;
+                       msi-parent = <&its_dsa 0x40b1c>;
+                       num-pins = <9>;
+                       #interrupt-cells = <2>;
+       };
+
+Devices connect to mbigen required properties:
+----------------------------------------------------
+-interrupt-parent: Specifies the mbigen device node which device connected.
+
+-interrupts:Specifies the interrupt source.
+ For the specific information of each cell in this property,please refer to
+ the "interrupt-cells" description mentioned above.
+
+Examples:
+       gmac0: ethernet@c2080000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0 0xc2080000 0 0x20000>,
+                     <0 0xc0000000 0 0x1000>;
+               interrupt-parent  = <&mbigen_device_gmac>;
+               interrupts =    <656 1>,
+                               <657 1>;
+       };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/technologic,ts4800.txt b/Documentation/devicetree/bindings/interrupt-controller/technologic,ts4800.txt
new file mode 100644 (file)
index 0000000..7f15f1b
--- /dev/null
@@ -0,0 +1,16 @@
+TS-4800 FPGA interrupt controller
+
+TS-4800 FPGA has an internal interrupt controller. When one of the
+interrupts is triggered, the SoC is notified, usually using a GPIO as
+parent interrupt source.
+
+Required properties:
+- compatible: should be "technologic,ts4800-irqc"
+- interrupt-controller: identifies the node as an interrupt controller
+- reg: physical base address of the controller and length of memory mapped
+  region
+- #interrupt-cells: specifies the number of cells needed to encode an interrupt
+  source, should be 1.
+- interrupt-parent: phandle to the parent interrupt controller this one is
+  cascaded from
+- interrupts: specifies the interrupt line in the interrupt-parent controller
index d4def767bdfea346df695d2d5a1a74577f0fbfea..cc51b1fd6e0cee6e7e6a17123be60f20b9c318f8 100644 (file)
@@ -35,7 +35,7 @@ Required properties (tsin (child) node):
 
 - tsin-num     : tsin id of the InputBlock (must be between 0 to 6)
 - i2c-bus      : phandle to the I2C bus DT node which the demodulators & tuners on this tsin channel are connected.
-- rst-gpio     : reset gpio for this tsin channel.
+- reset-gpios  : reset gpio for this tsin channel.
 
 Optional properties (tsin (child) node):
 
@@ -55,27 +55,27 @@ Example:
                status = "okay";
                reg = <0x08a20000 0x10000>, <0x08a00000 0x4000>;
                reg-names = "stfe", "stfe-ram";
-               interrupts = <0 34 0>, <0 35 0>;
+               interrupts = <GIC_SPI 34 IRQ_TYPE_NONE>, <GIC_SPI 35 IRQ_TYPE_NONE>;
                interrupt-names = "stfe-error-irq", "stfe-idle-irq";
-
-               pinctrl-names   = "tsin0-serial", "tsin0-parallel", "tsin3-serial",
-                               "tsin4-serial", "tsin5-serial";
-
                pinctrl-0       = <&pinctrl_tsin0_serial>;
                pinctrl-1       = <&pinctrl_tsin0_parallel>;
                pinctrl-2       = <&pinctrl_tsin3_serial>;
                pinctrl-3       = <&pinctrl_tsin4_serial_alt3>;
                pinctrl-4       = <&pinctrl_tsin5_serial_alt1>;
-
+               pinctrl-names   = "tsin0-serial",
+                                 "tsin0-parallel",
+                                 "tsin3-serial",
+                                 "tsin4-serial",
+                                 "tsin5-serial";
                clocks = <&clk_s_c0_flexgen CLK_PROC_STFE>;
-               clock-names = "stfe";
+               clock-names = "c8sectpfe";
 
                /* tsin0 is TSA on NIMA */
                tsin0: port@0 {
                        tsin-num                = <0>;
                        serial-not-parallel;
                        i2c-bus                 = <&ssc2>;
-                       rst-gpio                = <&pio15 4 0>;
+                       reset-gpios             = <&pio15 4 GPIO_ACTIVE_HIGH>;
                        dvb-card                = <STV0367_TDA18212_NIMA_1>;
                };
 
@@ -83,7 +83,7 @@ Example:
                        tsin-num                = <3>;
                        serial-not-parallel;
                        i2c-bus                 = <&ssc3>;
-                       rst-gpio                = <&pio15 7 0>;
+                       reset-gpios             = <&pio15 7 GPIO_ACTIVE_HIGH>;
                        dvb-card                = <STV0367_TDA18212_NIMB_1>;
                };
        };
index cae29eb5733d8a529d2ec2c3606e4c2255a01884..ff611fa66871dec93363ea875df4237df90423f0 100644 (file)
@@ -11,6 +11,7 @@ Required properties:
        - "renesas,mmcif-r8a7740" for the MMCIF found in r8a7740 SoCs
        - "renesas,mmcif-r8a7790" for the MMCIF found in r8a7790 SoCs
        - "renesas,mmcif-r8a7791" for the MMCIF found in r8a7791 SoCs
+       - "renesas,mmcif-r8a7793" for the MMCIF found in r8a7793 SoCs
        - "renesas,mmcif-r8a7794" for the MMCIF found in r8a7794 SoCs
 
 - clocks: reference to the functional clock
index 9853f8e7096613e990c28cc545b39ab7f26afddc..28a4781ab6d7b9d6a1ab553ed96857f0f509e250 100644 (file)
@@ -40,18 +40,18 @@ Optional properties:
 
 Slave Properties:
 Required properties:
-- phy_id               : Specifies slave phy id
 - phy-mode             : See ethernet.txt file in the same directory
 
 Optional properties:
 - dual_emac_res_vlan   : Specifies VID to be used to segregate the ports
 - mac-address          : See ethernet.txt file in the same directory
+- phy_id               : Specifies slave phy id
 - phy-handle           : See ethernet.txt file in the same directory
 
 Slave sub-nodes:
 - fixed-link           : See fixed-link.txt file in the same directory
-                         Either the properties phy_id and phy-mode,
-                         or the sub-node fixed-link can be specified
+                         Either the property phy_id, or the sub-node
+                         fixed-link can be specified
 
 Note: "ti,hwmods" field is used to fetch the base address and irq
 resources from TI, omap hwmod data base during device registration.
index b321b26780dc0697e54f0821289126c2a5c6e801..9213b27e1036666f98fa077fb05e066b793fca0e 100644 (file)
@@ -17,7 +17,10 @@ Required properties:
   "allwinner,sun8i-a23-pinctrl"
   "allwinner,sun8i-a23-r-pinctrl"
   "allwinner,sun8i-a33-pinctrl"
+  "allwinner,sun9i-a80-pinctrl"
+  "allwinner,sun9i-a80-r-pinctrl"
   "allwinner,sun8i-a83t-pinctrl"
+  "allwinner,sun8i-h3-pinctrl"
 
 - reg: Should contain the register physical address and length for the
   pin controller.
diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,cygnus-gpio.txt b/Documentation/devicetree/bindings/pinctrl/brcm,cygnus-gpio.txt
deleted file mode 100644 (file)
index 16589fb..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-Broadcom Cygnus GPIO/PINCONF Controller
-
-Required properties:
-
-- compatible:
-    Must be "brcm,cygnus-ccm-gpio", "brcm,cygnus-asiu-gpio",
-    "brcm,cygnus-crmu-gpio" or "brcm,iproc-gpio"
-
-- reg:
-    Define the base and range of the I/O address space that contains the Cygnus
-GPIO/PINCONF controller registers
-
-- #gpio-cells:
-    Must be two. The first cell is the GPIO pin number (within the
-controller's pin space) and the second cell is used for the following:
-    bit[0]: polarity (0 for active high and 1 for active low)
-
-- gpio-controller:
-    Specifies that the node is a GPIO controller
-
-Optional properties:
-
-- interrupts:
-    Interrupt ID
-
-- interrupt-controller:
-    Specifies that the node is an interrupt controller
-
-- gpio-ranges:
-    Specifies the mapping between gpio controller and pin-controllers pins.
-    This requires 4 fields in cells defined as -
-    1. Phandle of pin-controller.
-    2. GPIO base pin offset.
-    3  Pin-control base pin offset.
-    4. number of gpio pins which are linearly mapped from pin base.
-
-Supported generic PINCONF properties in child nodes:
-
-- pins:
-    The list of pins (within the controller's own pin space) that properties
-in the node apply to. Pin names are "gpio-<pin>"
-
-- bias-disable:
-    Disable pin bias
-
-- bias-pull-up:
-    Enable internal pull up resistor
-
-- bias-pull-down:
-    Enable internal pull down resistor
-
-- drive-strength:
-    Valid drive strength values include 2, 4, 6, 8, 10, 12, 14, 16 (mA)
-
-Example:
-       gpio_ccm: gpio@1800a000 {
-               compatible = "brcm,cygnus-ccm-gpio";
-               reg = <0x1800a000 0x50>,
-                     <0x0301d164 0x20>;
-               #gpio-cells = <2>;
-               gpio-controller;
-               interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
-               interrupt-controller;
-
-               touch_pins: touch_pins {
-                       pwr: pwr {
-                               pins = "gpio-0";
-                               drive-strength = <16>;
-                       };
-
-                       event: event {
-                               pins = "gpio-1";
-                               bias-pull-up;
-                       };
-               };
-       };
-
-       gpio_asiu: gpio@180a5000 {
-               compatible = "brcm,cygnus-asiu-gpio";
-               reg = <0x180a5000 0x668>;
-               #gpio-cells = <2>;
-               gpio-controller;
-               interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
-               interrupt-controller;
-               gpio-ranges = <&pinctrl 0 42 1>,
-                               <&pinctrl 1 44 3>;
-       };
-
-       /*
-        * Touchscreen that uses the CCM GPIO 0 and 1
-        */
-       tsc {
-               ...
-               ...
-               gpio-pwr = <&gpio_ccm 0 0>;
-               gpio-event = <&gpio_ccm 1 0>;
-       };
-
-       /* Bluetooth that uses the ASIU GPIO 5, with polarity inverted */
-       bluetooth {
-               ...
-               ...
-               bcm,rfkill-bank-sel = <&gpio_asiu 5 1>
-       }
diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,iproc-gpio.txt b/Documentation/devicetree/bindings/pinctrl/brcm,iproc-gpio.txt
new file mode 100644 (file)
index 0000000..e427792
--- /dev/null
@@ -0,0 +1,109 @@
+Broadcom iProc GPIO/PINCONF Controller
+
+Required properties:
+
+- compatible:
+    Must be "brcm,cygnus-ccm-gpio", "brcm,cygnus-asiu-gpio",
+    "brcm,cygnus-crmu-gpio" or "brcm,iproc-gpio"
+
+- reg:
+    Define the base and range of the I/O address space that contains SoC
+GPIO/PINCONF controller registers
+
+- ngpios:
+    Total number of in-use slots in GPIO controller
+
+- #gpio-cells:
+    Must be two. The first cell is the GPIO pin number (within the
+controller's pin space) and the second cell is used for the following:
+    bit[0]: polarity (0 for active high and 1 for active low)
+
+- gpio-controller:
+    Specifies that the node is a GPIO controller
+
+Optional properties:
+
+- interrupts:
+    Interrupt ID
+
+- interrupt-controller:
+    Specifies that the node is an interrupt controller
+
+- gpio-ranges:
+    Specifies the mapping between gpio controller and pin-controllers pins.
+    This requires 4 fields in cells defined as -
+    1. Phandle of pin-controller.
+    2. GPIO base pin offset.
+    3  Pin-control base pin offset.
+    4. number of gpio pins which are linearly mapped from pin base.
+
+Supported generic PINCONF properties in child nodes:
+
+- pins:
+    The list of pins (within the controller's own pin space) that properties
+in the node apply to. Pin names are "gpio-<pin>"
+
+- bias-disable:
+    Disable pin bias
+
+- bias-pull-up:
+    Enable internal pull up resistor
+
+- bias-pull-down:
+    Enable internal pull down resistor
+
+- drive-strength:
+    Valid drive strength values include 2, 4, 6, 8, 10, 12, 14, 16 (mA)
+
+Example:
+       gpio_ccm: gpio@1800a000 {
+               compatible = "brcm,cygnus-ccm-gpio";
+               reg = <0x1800a000 0x50>,
+                     <0x0301d164 0x20>;
+               ngpios = <24>;
+               #gpio-cells = <2>;
+               gpio-controller;
+               interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-controller;
+
+               touch_pins: touch_pins {
+                       pwr: pwr {
+                               pins = "gpio-0";
+                               drive-strength = <16>;
+                       };
+
+                       event: event {
+                               pins = "gpio-1";
+                               bias-pull-up;
+                       };
+               };
+       };
+
+       gpio_asiu: gpio@180a5000 {
+               compatible = "brcm,cygnus-asiu-gpio";
+               reg = <0x180a5000 0x668>;
+               ngpios = <146>;
+               #gpio-cells = <2>;
+               gpio-controller;
+               interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-controller;
+               gpio-ranges = <&pinctrl 0 42 1>,
+                               <&pinctrl 1 44 3>;
+       };
+
+       /*
+        * Touchscreen that uses the CCM GPIO 0 and 1
+        */
+       tsc {
+               ...
+               ...
+               gpio-pwr = <&gpio_ccm 0 0>;
+               gpio-event = <&gpio_ccm 1 0>;
+       };
+
+       /* Bluetooth that uses the ASIU GPIO 5, with polarity inverted */
+       bluetooth {
+               ...
+               ...
+               bcm,rfkill-bank-sel = <&gpio_asiu 5 1>
+       }
diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,nsp-gpio.txt b/Documentation/devicetree/bindings/pinctrl/brcm,nsp-gpio.txt
new file mode 100644 (file)
index 0000000..0844168
--- /dev/null
@@ -0,0 +1,80 @@
+Broadcom Northstar plus (NSP) GPIO/PINCONF Controller
+
+Required properties:
+- compatible:
+    Must be "brcm,nsp-gpio-a"
+
+- reg:
+    Should contain the register physical address and length for each of
+    GPIO base, IO control registers
+
+- #gpio-cells:
+    Must be two. The first cell is the GPIO pin number (within the
+    controller's pin space) and the second cell is used for the following:
+    bit[0]: polarity (0 for active high and 1 for active low)
+
+- gpio-controller:
+    Specifies that the node is a GPIO controller
+
+- ngpios:
+    Number of gpios supported (58x25 supports 32 and 58x23 supports 24)
+
+Optional properties:
+- interrupts:
+    Interrupt ID
+
+- interrupt-controller:
+    Specifies that the node is an interrupt controller
+
+- gpio-ranges:
+    Specifies the mapping between gpio controller and pin-controllers pins.
+    This requires 4 fields in cells defined as -
+    1. Phandle of pin-controller.
+    2. GPIO base pin offset.
+    3  Pin-control base pin offset.
+    4. number of gpio pins which are linearly mapped from pin base.
+
+Supported generic PINCONF properties in child nodes:
+- pins:
+    The list of pins (within the controller's own pin space) that properties
+    in the node apply to. Pin names are "gpio-<pin>"
+
+- bias-disable:
+    Disable pin bias
+
+- bias-pull-up:
+    Enable internal pull up resistor
+
+- bias-pull-down:
+    Enable internal pull down resistor
+
+- drive-strength:
+    Valid drive strength values include 2, 4, 6, 8, 10, 12, 14, 16 (mA)
+
+Example:
+
+       gpioa: gpio@18000020 {
+               compatible = "brcm,nsp-gpio-a";
+               reg = <0x18000020 0x100>,
+                     <0x1803f1c4 0x1c>;
+               #gpio-cells = <2>;
+               gpio-controller;
+               ngpios = <32>;
+               gpio-ranges = <&pinctrl 0 0 31>;
+               interrupt-controller;
+               interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
+
+               /* Hog a few default settings */
+               pinctrl-names = "default";
+               pinctrl-0 = <&led>;
+               led: led {
+                       pins = "gpio-1";
+                       bias-pull-up;
+               };
+
+               pwr: pwr {
+                       gpio-hog;
+                       gpios = <3 1>;
+                       output-high;
+               };
+       };
index e89b4677567d0fcd9a4550905ea806d905d951c0..8e5216bcd74852cb6f675002d31866a5e53de206 100644 (file)
@@ -1,7 +1,16 @@
 Lantiq XWAY pinmux controller
 
 Required properties:
-- compatible: "lantiq,pinctrl-xway" or "lantiq,pinctrl-xr9"
+- compatible: "lantiq,pinctrl-xway", (DEPRECATED: Use "lantiq,pinctrl-danube")
+             "lantiq,pinctrl-xr9", (DEPRECATED: Use "lantiq,xrx100-pinctrl" or
+                                       "lantiq,xrx200-pinctrl")
+             "lantiq,pinctrl-ase", (DEPRECATED: Use "lantiq,ase-pinctrl")
+             "lantiq,<chip>-pinctrl", where <chip> is:
+               "ase" (XWAY AMAZON Family)
+               "danube" (XWAY DANUBE Family)
+               "xrx100" (XWAY xRX100 Family)
+               "xrx200" (XWAY xRX200 Family)
+               "xrx300" (XWAY xRX300 Family)
 - reg: Should contain the physical address and length of the gpio/pinmux
   register range
 
@@ -36,19 +45,87 @@ Required subnode-properties:
 
 Valid values for group and function names:
 
+XWAY: (DEPRECATED: Use DANUBE)
   mux groups:
     exin0, exin1, exin2, jtag, ebu a23, ebu a24, ebu a25, ebu clk, ebu cs1,
     ebu wait, nand ale, nand cs1, nand cle, spi, spi_cs1, spi_cs2, spi_cs3,
-    spi_cs4, spi_cs5, spi_cs6, asc0, asc0 cts rts, stp, nmi , gpt1, gpt2,
+    spi_cs4, spi_cs5, spi_cs6, asc0, asc0 cts rts, stp, nmi, gpt1, gpt2,
     gpt3, clkout0, clkout1, clkout2, clkout3, gnt1, gnt2, gnt3, req1, req2,
     req3
 
-  additional mux groups (XR9 only):
-    mdio, nand rdy, nand rd, exin3, exin4, gnt4, req4
+  functions:
+    spi, asc, cgu, jtag, exin, stp, gpt, nmi, pci, ebu
+
+XR9: ( DEPRECATED: Use xRX100/xRX200)
+  mux groups:
+    exin0, exin1, exin2, exin3, exin4, jtag, ebu a23, ebu a24, ebu a25,
+    ebu clk, ebu cs1, ebu wait, nand ale, nand cs1, nand cle, nand rdy,
+    nand rd, spi, spi_cs1, spi_cs2, spi_cs3, spi_cs4, spi_cs5, spi_cs6,
+    asc0, asc0 cts rts, stp, nmi, gpt1, gpt2, gpt3, clkout0, clkout1,
+    clkout2, clkout3, gnt1, gnt2, gnt3, gnt4, req1, req2, req3, req4, mdio,
+    gphy0 led0, gphy0 led1, gphy0 led2, gphy1 led0, gphy1 led1, gphy1 led2
+
+  functions:
+    spi, asc, cgu, jtag, exin, stp, gpt, nmi, pci, ebu, mdio, gphy
+
+AMAZON:
+  mux groups:
+    exin0, exin1, exin2, jtag, spi_di, spi_do, spi_clk, spi_cs1, spi_cs2,
+    spi_cs3, spi_cs4, spi_cs5, spi_cs6, asc, stp, gpt1, gpt2, gpt3, clkout0,
+    clkout1, clkout2, mdio, dfe led0, dfe led1, ephy led0, ephy led1, ephy led2
+
+  functions:
+    spi, asc, cgu, jtag, exin, stp, gpt, mdio, ephy, dfe
+
+DANUBE:
+  mux groups:
+    exin0, exin1, exin2, jtag, ebu a23, ebu a24, ebu a25, ebu clk, ebu cs1,
+    ebu wait, nand ale, nand cs1, nand cle, spi_di, spi_do, spi_clk, spi_cs1,
+    spi_cs2, spi_cs3, spi_cs4, spi_cs5, spi_cs6, asc0, asc0 cts rts, stp, nmi,
+    gpt1, gpt2, gpt3, clkout0, clkout1, clkout2, clkout3, gnt1, gnt2, gnt3,
+    req1, req2, req3, dfe led0, dfe led1
 
   functions:
-    spi, asc, cgu, jtag, exin, stp, gpt, nmi, pci, ebu, mdio
+    spi, asc, cgu, jtag, exin, stp, gpt, nmi, pci, ebu, dfe
 
+xRX100:
+  mux groups:
+    exin0, exin1, exin2, exin3, exin4, ebu a23, ebu a24, ebu a25, ebu clk,
+    ebu cs1, ebu wait, nand ale, nand cs1, nand cle, nand rdy, nand rd,
+    spi_di, spi_do, spi_clk, spi_cs1, spi_cs2, spi_cs3, spi_cs4, spi_cs5,
+    spi_cs6, asc0, asc0 cts rts, stp, nmi, gpt1, gpt2, gpt3, clkout0, clkout1,
+    clkout2, clkout3, gnt1, gnt2, gnt3, gnt4, req1, req2, req3, req4, mdio,
+    dfe led0, dfe led1
+
+  functions:
+    spi, asc, cgu, exin, stp, gpt, nmi, pci, ebu, mdio, dfe
+
+xRX200:
+  mux groups:
+    exin0, exin1, exin2, exin3, exin4, ebu a23, ebu a24, ebu a25, ebu clk,
+    ebu cs1, ebu wait, nand ale, nand cs1, nand cle, nand rdy, nand rd,
+    spi_di, spi_do, spi_clk, spi_cs1, spi_cs2, spi_cs3, spi_cs4, spi_cs5,
+    spi_cs6, usif uart_rx, usif uart_tx, usif uart_rts, usif uart_cts,
+    usif uart_dtr, usif uart_dsr, usif uart_dcd, usif uart_ri, usif spi_di,
+    usif spi_do, usif spi_clk, usif spi_cs0, usif spi_cs1, usif spi_cs2,
+    stp, nmi, gpt1, gpt2, gpt3, clkout0, clkout1, clkout2, clkout3, gnt1,
+    gnt2, gnt3, gnt4, req1, req2, req3, req4, mdio, dfe led0, dfe led1,
+    gphy0 led0, gphy0 led1, gphy0 led2, gphy1 led0, gphy1 led1, gphy1 led2
+
+  functions:
+    spi, usif, cgu, exin, stp, gpt, nmi, pci, ebu, mdio, dfe, gphy
+
+xRX300:
+  mux groups:
+    exin0, exin1, exin2, exin4, nand ale, nand cs0, nand cs1, nand cle,
+    nand rdy, nand rd, nand_d0, nand_d1, nand_d2, nand_d3, nand_d4, nand_d5,
+    nand_d6, nand_d7, nand_d1, nand wr, nand wp, nand se, spi_di, spi_do,
+    spi_clk, spi_cs1, spi_cs4, spi_cs6, usif uart_rx, usif uart_tx,
+    usif spi_di, usif spi_do, usif spi_clk, usif spi_cs0, stp, clkout2,
+    mdio, dfe led0, dfe led1, ephy0 led0, ephy0 led1, ephy1 led0, ephy1 led1
+
+  functions:
+    spi, usif, cgu, exin, stp, ebu, mdio, dfe, ephy
 
 
 Definition of pin configurations:
@@ -62,15 +139,32 @@ Optional subnode-properties:
     0: none, 1: down, 2: up.
 - lantiq,open-drain: Boolean, enables open-drain on the defined pin.
 
-Valid values for XWAY pin names:
+Valid values for XWAY pin names: (DEPRECATED: Use DANUBE)
   Pinconf pins can be referenced via the names io0-io31.
 
-Valid values for XR9 pin names:
+Valid values for XR9 pin names: (DEPRECATED: Use xrX100/xRX200)
   Pinconf pins can be referenced via the names io0-io55.
 
+Valid values for AMAZON pin names:
+  Pinconf pins can be referenced via the names io0-io31.
+
+Valid values for DANUBE pin names:
+  Pinconf pins can be referenced via the names io0-io31.
+
+Valid values for xRX100 pin names:
+  Pinconf pins can be referenced via the names io0-io55.
+
+Valid values for xRX200 pin names:
+  Pinconf pins can be referenced via the names io0-io49.
+
+Valid values for xRX300 pin names:
+  Pinconf pins can be referenced via the names io0-io1,io3-io6,io8-io11,
+                                               io13-io19,io23-io27,io34-io36,
+                                               io42-io43,io48-io61.
+
 Example:
        gpio: pinmux@E100B10 {
-               compatible = "lantiq,pinctrl-xway";
+               compatible = "lantiq,danube-pinctrl";
                pinctrl-names = "default";
                pinctrl-0 = <&state_default>;
 
index 0480bc31bfd71c624ef33d3e94e571fbd09083e7..9ffb0b276bb4864eab7a41368d754f035d4ab56b 100644 (file)
@@ -4,10 +4,11 @@ The Mediatek's Pin controller is used to control SoC pins.
 
 Required properties:
 - compatible: value should be one of the following.
-    (a) "mediatek,mt8135-pinctrl", compatible with mt8135 pinctrl.
-    (b) "mediatek,mt8173-pinctrl", compatible with mt8173 pinctrl.
-    (c) "mediatek,mt6397-pinctrl", compatible with mt6397 pinctrl.
-    (d) "mediatek,mt8127-pinctrl", compatible with mt8127 pinctrl.
+       "mediatek,mt2701-pinctrl", compatible with mt2701 pinctrl.
+       "mediatek,mt6397-pinctrl", compatible with mt6397 pinctrl.
+       "mediatek,mt8127-pinctrl", compatible with mt8127 pinctrl.
+       "mediatek,mt8135-pinctrl", compatible with mt8135 pinctrl.
+       "mediatek,mt8173-pinctrl", compatible with mt8173 pinctrl.
 - pins-are-numbered: Specify the subnodes are using numbered pinmux to
   specify pins.
 - gpio-controller : Marks the device node as a gpio controller.
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.txt
new file mode 100644 (file)
index 0000000..e312a71
--- /dev/null
@@ -0,0 +1,199 @@
+Qualcomm MSM8996 TLMM block
+
+This binding describes the Top Level Mode Multiplexer block found in the
+MSM8996 platform.
+
+- compatible:
+       Usage: required
+       Value type: <string>
+       Definition: must be "qcom,msm8996-pinctrl"
+
+- reg:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: the base address and size of the TLMM register space.
+
+- interrupts:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: should specify the TLMM summary IRQ.
+
+- interrupt-controller:
+       Usage: required
+       Value type: <none>
+       Definition: identifies this node as an interrupt controller
+
+- #interrupt-cells:
+       Usage: required
+       Value type: <u32>
+       Definition: must be 2. Specifying the pin number and flags, as defined
+                   in <dt-bindings/interrupt-controller/irq.h>
+
+- gpio-controller:
+       Usage: required
+       Value type: <none>
+       Definition: identifies this node as a gpio controller
+
+- #gpio-cells:
+       Usage: required
+       Value type: <u32>
+       Definition: must be 2. Specifying the pin number and flags, as defined
+                   in <dt-bindings/gpio/gpio.h>
+
+Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for
+a general description of GPIO and interrupt bindings.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+The pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin, a group, or a list of pins or groups. This configuration can include the
+mux function to select on those pin(s)/group(s), and various pin configuration
+parameters, such as pull-up, drive strength, etc.
+
+
+PIN CONFIGURATION NODES:
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Each subnode only affects those parameters that are explicitly listed. In
+other words, a subnode that lists a mux function but no pin configuration
+parameters implies no information about any pin configuration parameters.
+Similarly, a pin subnode that describes a pullup parameter implies no
+information about e.g. the mux function.
+
+
+The following generic properties as defined in pinctrl-bindings.txt are valid
+to specify in a pin configuration subnode:
+
+- pins:
+       Usage: required
+       Value type: <string-array>
+       Definition: List of gpio pins affected by the properties specified in
+                   this subnode.
+
+                   Valid pins are:
+                     gpio0-gpio149
+                       Supports mux, bias and drive-strength
+
+                     sdc1_clk, sdc1_cmd, sdc1_data sdc2_clk, sdc2_cmd,
+                     sdc2_data sdc1_rclk
+                       Supports bias and drive-strength
+
+- function:
+       Usage: required
+       Value type: <string>
+       Definition: Specify the alternative function to be configured for the
+                   specified pins. Functions are only valid for gpio pins.
+                   Valid values are:
+
+                   blsp_uart1, blsp_spi1, blsp_i2c1, blsp_uim1, atest_tsens,
+                   bimc_dte1, dac_calib0, blsp_spi8, blsp_uart8, blsp_uim8,
+                   qdss_cti_trig_out_b, bimc_dte0, dac_calib1, qdss_cti_trig_in_b,
+                   dac_calib2, atest_tsens2, atest_usb1, blsp_spi10, blsp_uart10,
+                   blsp_uim10, atest_bbrx1, atest_usb13, atest_bbrx0, atest_usb12,
+                   mdp_vsync, edp_lcd, blsp_i2c10, atest_gpsadc1, atest_usb11,
+                   atest_gpsadc0, edp_hot, atest_usb10, m_voc, dac_gpio, atest_char,
+                   cam_mclk, pll_bypassnl, qdss_stm7, blsp_i2c8, qdss_tracedata_b,
+                   pll_reset, qdss_stm6, qdss_stm5, qdss_stm4, atest_usb2, cci_i2c,
+                   qdss_stm3, dac_calib3, atest_usb23, atest_char3, dac_calib4,
+                   qdss_stm2, atest_usb22, atest_char2, qdss_stm1, dac_calib5,
+                   atest_usb21, atest_char1, dbg_out, qdss_stm0, dac_calib6,
+                   atest_usb20, atest_char0, dac_calib10, qdss_stm10,
+                   qdss_cti_trig_in_a, cci_timer4, blsp_spi6, blsp_uart6, blsp_uim6,
+                   blsp2_spi, qdss_stm9, qdss_cti_trig_out_a, dac_calib11,
+                   qdss_stm8, cci_timer0, qdss_stm13, dac_calib7, cci_timer1,
+                   qdss_stm12, dac_calib8, cci_timer2, blsp1_spi, qdss_stm11,
+                   dac_calib9, cci_timer3, cci_async, dac_calib12, blsp_i2c6,
+                   qdss_tracectl_a, dac_calib13, qdss_traceclk_a, dac_calib14,
+                   dac_calib15, hdmi_rcv, dac_calib16, hdmi_cec, pwr_modem,
+                   dac_calib17, hdmi_ddc, pwr_nav, dac_calib18, pwr_crypto,
+                   dac_calib19, hdmi_hot, dac_calib20, dac_calib21, pci_e0,
+                   dac_calib22, dac_calib23, dac_calib24, tsif1_sync, dac_calib25,
+                   sd_write, tsif1_error, blsp_spi2, blsp_uart2, blsp_uim2,
+                   qdss_cti, blsp_i2c2, blsp_spi3, blsp_uart3, blsp_uim3, blsp_i2c3,
+                   uim3, blsp_spi9, blsp_uart9, blsp_uim9, blsp10_spi, blsp_i2c9,
+                   blsp_spi7, blsp_uart7, blsp_uim7, qdss_tracedata_a, blsp_i2c7,
+                   qua_mi2s, gcc_gp1_clk_a, ssc_irq, uim4, blsp_spi11, blsp_uart11,
+                   blsp_uim11, gcc_gp2_clk_a, gcc_gp3_clk_a, blsp_i2c11, cri_trng0,
+                   cri_trng1, cri_trng, qdss_stm18, pri_mi2s, qdss_stm17, blsp_spi4,
+                   blsp_uart4, blsp_uim4, qdss_stm16, qdss_stm15, blsp_i2c4,
+                   qdss_stm14, dac_calib26, spkr_i2s, audio_ref, lpass_slimbus,
+                   isense_dbg, tsense_pwm1, tsense_pwm2, btfm_slimbus, ter_mi2s,
+                   qdss_stm22, qdss_stm21, qdss_stm20, qdss_stm19, gcc_gp1_clk_b,
+                   sec_mi2s, blsp_spi5, blsp_uart5, blsp_uim5, gcc_gp2_clk_b,
+                   gcc_gp3_clk_b, blsp_i2c5, blsp_spi12, blsp_uart12, blsp_uim12,
+                   qdss_stm25, qdss_stm31, blsp_i2c12, qdss_stm30, qdss_stm29,
+                   tsif1_clk, qdss_stm28, tsif1_en, tsif1_data, sdc4_cmd, qdss_stm27,
+                   qdss_traceclk_b, tsif2_error, sdc43, vfr_1, qdss_stm26, tsif2_clk,
+                   sdc4_clk, qdss_stm24, tsif2_en, sdc42, qdss_stm23, qdss_tracectl_b,
+                   sd_card, tsif2_data, sdc41, tsif2_sync, sdc40, mdp_vsync_p_b,
+                   ldo_en, mdp_vsync_s_b, ldo_update, blsp11_uart_tx_b, blsp11_uart_rx_b,
+                   blsp11_i2c_sda_b, prng_rosc, blsp11_i2c_scl_b, uim2, uim1, uim_batt,
+                   pci_e2, pa_indicator, adsp_ext, ddr_bist, qdss_tracedata_11,
+                   qdss_tracedata_12, modem_tsync, nav_dr, nav_pps, pci_e1, gsm_tx,
+                   qspi_cs, ssbi2, ssbi1, mss_lte, qspi_clk, qspi0, qspi1, qspi2, qspi3,
+                   gpio
+
+- bias-disable:
+       Usage: optional
+       Value type: <none>
+       Definition: The specified pins should be configued as no pull.
+
+- bias-pull-down:
+       Usage: optional
+       Value type: <none>
+       Definition: The specified pins should be configued as pull down.
+
+- bias-pull-up:
+       Usage: optional
+       Value type: <none>
+       Definition: The specified pins should be configued as pull up.
+
+- output-high:
+       Usage: optional
+       Value type: <none>
+       Definition: The specified pins are configured in output mode, driven
+                   high.
+                   Not valid for sdc pins.
+
+- output-low:
+       Usage: optional
+       Value type: <none>
+       Definition: The specified pins are configured in output mode, driven
+                   low.
+                   Not valid for sdc pins.
+
+- drive-strength:
+       Usage: optional
+       Value type: <u32>
+       Definition: Selects the drive strength for the specified pins, in mA.
+                   Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16
+
+Example:
+
+       tlmm: pinctrl@01010000 {
+               compatible = "qcom,msm8996-pinctrl";
+               reg = <0x01010000 0x300000>;
+               interrupts = <0 208 0>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
+
+               uart_console_active: uart_console_active {
+                       mux {
+                               pins = "gpio4", "gpio5";
+                               function = "blsp_uart8";
+                       };
+
+                       config {
+                               pins = "gpio4", "gpio5";
+                               drive-strength = <2>;
+                               bias-disable;
+                       };
+               };
+       };
index 1ae63c0acd40b2609e173380d6785d7174248525..a90c812ad6429abe0ef5282982e6fea66560b599 100644 (file)
@@ -14,6 +14,7 @@ PMIC's from Qualcomm.
                    "qcom,pm8917-gpio"
                    "qcom,pm8921-gpio"
                    "qcom,pm8941-gpio"
+                   "qcom,pm8994-gpio"
                    "qcom,pma8084-gpio"
 
 - reg:
@@ -79,6 +80,7 @@ to specify in a pin configuration subnode:
                    gpio1-gpio38 for pm8917
                    gpio1-gpio44 for pm8921
                    gpio1-gpio36 for pm8941
+                   gpio1-gpio22 for pm8994
                    gpio1-gpio22 for pma8084
 
 - function:
index d7803a2a94e9be4c089a3ed69f8eaa23e935ee80..d74e631e10da1eb35252c97660d7044e1c502941 100644 (file)
@@ -15,6 +15,7 @@ of PMIC's from Qualcomm.
                    "qcom,pm8917-mpp",
                    "qcom,pm8921-mpp",
                    "qcom,pm8941-mpp",
+                   "qcom,pm8994-mpp",
                    "qcom,pma8084-mpp",
 
 - reg:
index 391ef4be8d509006446120fb83e73712e7384628..0cd701b1947fdc35bc8ec036cac82b053f237712 100644 (file)
@@ -21,7 +21,8 @@ defined as gpio sub-nodes of the pinmux controller.
 Required properties for iomux controller:
   - compatible: one of "rockchip,rk2928-pinctrl", "rockchip,rk3066a-pinctrl"
                       "rockchip,rk3066b-pinctrl", "rockchip,rk3188-pinctrl"
-                      "rockchip,rk3288-pinctrl", "rockchip,rk3368-pinctrl"
+                      "rockchip,rk3228-pinctrl", "rockchip,rk3288-pinctrl"
+                      "rockchip,rk3368-pinctrl"
   - rockchip,grf: phandle referencing a syscon providing the
         "general register files"
 
index 9d2a995293e650064923f0cc5f791ed57a34836a..6db16b90873a4d4fbcd820d4626e2ea80ee7c8ea 100644 (file)
@@ -17,6 +17,7 @@ Required Properties:
   - "samsung,exynos4x12-pinctrl": for Exynos4x12 compatible pin-controller.
   - "samsung,exynos5250-pinctrl": for Exynos5250 compatible pin-controller.
   - "samsung,exynos5260-pinctrl": for Exynos5260 compatible pin-controller.
+  - "samsung,exynos5410-pinctrl": for Exynos5410 compatible pin-controller.
   - "samsung,exynos5420-pinctrl": for Exynos5420 compatible pin-controller.
   - "samsung,exynos7-pinctrl": for Exynos7 compatible pin-controller.
 
index 8eb92264ee047163caa25738a30c09ad04d20fcc..669dc6ce43305e17f29ea95066bec2a80b59b70d 100644 (file)
@@ -45,7 +45,7 @@ Supported devices
 See the LinuxTV DVB Wiki at www.linuxtv.org for a complete list of
 cards/drivers/firmwares:
 
-http://www.linuxtv.org/wiki/index.php/DVB_USB
+https://linuxtv.org/wiki/index.php/DVB_USB
 
 0. History & News:
   2005-06-30 - added support for WideView WT-220U (Thanks to Steve Chang)
@@ -121,7 +121,7 @@ working.
 Have a look at the Wikipage for the DVB-USB-drivers to find out, which firmware
 you need for your device:
 
-http://www.linuxtv.org/wiki/index.php/DVB_USB
+https://linuxtv.org/wiki/index.php/DVB_USB
 
 1.2. Compiling
 
index 97b1373f2428e11bc38ed7e2a5adf71a570a4de2..a0be92012877d7c55246112c6dd61a104304d253 100644 (file)
@@ -76,7 +76,7 @@ Some very frequently asked questions about linuxtv-dvb
                the TuxBox CVS many interesting DVB applications and the dBox2
                DVB source
 
-       http://www.linuxtv.org/downloads/       
+       https://linuxtv.org/downloads
                DVB Swiss Army Knife library and utilities
 
        http://www.nenie.org/misc/mpsys/
index 91b43d2738c7935d8a919a6655b52fc95add8541..1a0a04125f713cb586549e1f5315501447eb65de 100755 (executable)
@@ -152,7 +152,7 @@ sub tda10046lifeview {
 
 sub av7110 {
     my $sourcefile = "dvb-ttpci-01.fw-261d";
-    my $url = "http://www.linuxtv.org/downloads/firmware/$sourcefile";
+    my $url = "https://linuxtv.org/downloads/firmware/$sourcefile";
     my $hash = "603431b6259715a8e88f376a53b64e2f";
     my $outfile = "dvb-ttpci-01.fw";
 
@@ -303,7 +303,7 @@ sub vp7049 {
 }
 
 sub dibusb {
-       my $url = "http://www.linuxtv.org/downloads/firmware/dvb-usb-dibusb-5.0.0.11.fw";
+       my $url = "https://linuxtv.org/downloads/firmware/dvb-usb-dibusb-5.0.0.11.fw";
        my $outfile = "dvb-dibusb-5.0.0.11.fw";
        my $hash = "fa490295a527360ca16dcdf3224ca243";
 
@@ -351,7 +351,7 @@ sub nxt2004 {
 
 sub or51211 {
     my $fwfile = "dvb-fe-or51211.fw";
-    my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
+    my $url = "https://linuxtv.org/downloads/firmware/$fwfile";
     my $hash = "d830949c771a289505bf9eafc225d491";
 
     checkstandard();
@@ -364,7 +364,7 @@ sub or51211 {
 
 sub cx231xx {
     my $fwfile = "v4l-cx231xx-avcore-01.fw";
-    my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
+    my $url = "https://linuxtv.org/downloads/firmware/$fwfile";
     my $hash = "7d3bb956dc9df0eafded2b56ba57cc42";
 
     checkstandard();
@@ -376,7 +376,7 @@ sub cx231xx {
 }
 
 sub cx18 {
-    my $url = "http://linuxtv.org/downloads/firmware/";
+    my $url = "https://linuxtv.org/downloads/firmware/";
 
     my %files = (
        'v4l-cx23418-apu.fw' => '588f081b562f5c653a3db1ad8f65939a',
@@ -450,7 +450,7 @@ sub mpc718 {
 }
 
 sub cx23885 {
-    my $url = "http://linuxtv.org/downloads/firmware/";
+    my $url = "https://linuxtv.org/downloads/firmware/";
 
     my %files = (
        'v4l-cx23885-avcore-01.fw' => 'a9f8f5d901a7fb42f552e1ee6384f3bb',
@@ -472,7 +472,7 @@ sub cx23885 {
 }
 
 sub pvrusb2 {
-    my $url = "http://linuxtv.org/downloads/firmware/";
+    my $url = "https://linuxtv.org/downloads/firmware/";
 
     my %files = (
        'v4l-cx25840.fw'           => 'dadb79e9904fc8af96e8111d9cb59320',
@@ -494,7 +494,7 @@ sub pvrusb2 {
 
 sub or51132_qam {
     my $fwfile = "dvb-fe-or51132-qam.fw";
-    my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
+    my $url = "https://linuxtv.org/downloads/firmware/$fwfile";
     my $hash = "7702e8938612de46ccadfe9b413cb3b5";
 
     checkstandard();
@@ -507,7 +507,7 @@ sub or51132_qam {
 
 sub or51132_vsb {
     my $fwfile = "dvb-fe-or51132-vsb.fw";
-    my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
+    my $url = "https://linuxtv.org/downloads/firmware/$fwfile";
     my $hash = "c16208e02f36fc439a557ad4c613364a";
 
     checkstandard();
@@ -519,7 +519,7 @@ sub or51132_vsb {
 }
 
 sub bluebird {
-       my $url = "http://www.linuxtv.org/download/dvb/firmware/dvb-usb-bluebird-01.fw";
+       my $url = "https://linuxtv.org/download/dvb/firmware/dvb-usb-bluebird-01.fw";
        my $outfile = "dvb-usb-bluebird-01.fw";
        my $hash = "658397cb9eba9101af9031302671f49d";
 
@@ -677,7 +677,7 @@ sub drxk_hauppauge_hvr930c {
 }
 
 sub drxk_terratec_h5 {
-    my $url = "http://www.linuxtv.org/downloads/firmware/";
+    my $url = "https://linuxtv.org/downloads/firmware/";
     my $hash = "19000dada8e2741162ccc50cc91fa7f1";
     my $fwfile = "dvb-usb-terratec-h5-drxk.fw";
 
index 0b0380c919902c012d1450f7202280fb8a5aefd6..89965041a2667d3b4b2f29aa23b28b6c2f73f57d 100644 (file)
@@ -2,12 +2,12 @@ Linux Digital Video Broadcast (DVB) subsystem
 =============================================
 
 The main development site and CVS repository for these
-drivers is http://linuxtv.org/.
+drivers is https://linuxtv.org.
 
 The developer mailing list linux-dvb is also hosted there,
-see http://linuxtv.org/lists.php. Please check
-the archive http://linuxtv.org/pipermail/linux-dvb/
-and the Wiki http://linuxtv.org/wiki/
+see https://linuxtv.org/lists.php. Please check
+the archive https://linuxtv.org/pipermail/linux-dvb/
+and the Wiki https://linuxtv.org/wiki/
 before asking newbie questions on the list.
 
 API documentation, utilities and test/example programs
@@ -16,7 +16,7 @@ are available as part of the old driver package for Linux 2.4
 We plan to split this into separate packages, but it's not
 been done yet.
 
-http://linuxtv.org/downloads/
+https://linuxtv.org/downloads/
 
 What's inside this directory:
 
index 80841a2d640cf5aeca8e16db4ebba5d224c5a008..f89cfd85ae134b1530ef76a46970d4fc044f66a6 100644 (file)
@@ -1,9 +1,13 @@
 EDAC - Error Detection And Correction
 =====================================
 
-"bluesmoke" was the name for this device driver when it was "out-of-tree"
-and maintained at sourceforge.net.  When it was pushed into 2.6.16 for the
-first time, it was renamed to 'EDAC'.
+"bluesmoke" was the name for this device driver when it
+was "out-of-tree" and maintained at sourceforge.net -
+bluesmoke.sourceforge.net. That site is mostly archaic now and can be
+used only for historical purposes.
+
+When the subsystem was pushed into 2.6.16 for the first time, it was
+renamed to 'EDAC'.
 
 PURPOSE
 -------
index e63316239938164be150d0a9d73dac94fa9b4b92..4199ffecc0ff06bde4b26fa5f09d1fd0a9a08601 100644 (file)
@@ -9,7 +9,7 @@
     |       alpha: |  ..  |
     |         arc: | TODO |
     |         arm: |  ok  |
-    |       arm64: |  ..  |
+    |       arm64: |  ok  |
     |       avr32: | TODO |
     |    blackfin: | TODO |
     |         c6x: | TODO |
index 06d443450f2138fc8595ef43be0e64ebc33f66f7..619af9bfdcb3eb4baceac7824c655fd9ba495950 100644 (file)
@@ -50,8 +50,7 @@ prototypes:
        int (*rename2) (struct inode *, struct dentry *,
                        struct inode *, struct dentry *, unsigned int);
        int (*readlink) (struct dentry *, char __user *,int);
-       const char *(*follow_link) (struct dentry *, void **);
-       void (*put_link) (struct inode *, void *);
+       const char *(*get_link) (struct dentry *, struct inode *, void **);
        void (*truncate) (struct inode *);
        int (*permission) (struct inode *, int, unsigned int);
        int (*get_acl)(struct inode *, int);
@@ -83,8 +82,7 @@ rmdir:                yes (both)      (see below)
 rename:                yes (all)       (see below)
 rename2:       yes (all)       (see below)
 readlink:      no
-follow_link:   no
-put_link:      no
+get_link:      no
 setattr:       yes
 permission:    no (may not block if called in rcu-walk mode)
 get_acl:       no
index f24d1b8339576e96c46045f5da8f275ee9250056..0f88e6020487ff9d08836e28b7e9ae780b4ebc5a 100644 (file)
@@ -504,3 +504,20 @@ in your dentry operations instead.
 [mandatory]
        __fd_install() & fd_install() can now sleep. Callers should not
        hold a spinlock or other resources that do not allow a schedule.
+--
+[mandatory]
+       any symlink that might use page_follow_link_light/page_put_link() must
+       have inode_nohighmem(inode) called before anything might start playing with
+       its pagecache.
+--
+[mandatory]
+       ->follow_link() is replaced with ->get_link(); same API, except that
+               * ->get_link() gets inode as a separate argument
+               * ->get_link() may be called in RCU mode - in that case NULL
+                 dentry is passed
+--
+[mandatory]
+       ->get_link() gets struct delayed_call *done now, and should do
+       set_delayed_call() where it used to set *cookie.
+       ->put_link() is gone - just give the destructor to set_delayed_call()
+       in ->get_link().
index 8c6f07ad373aa6b8402e457e0705cdebd0f3271d..b02a7d598258542e890eae7ab3b4b4503db251e2 100644 (file)
@@ -350,8 +350,8 @@ struct inode_operations {
        int (*rename2) (struct inode *, struct dentry *,
                        struct inode *, struct dentry *, unsigned int);
        int (*readlink) (struct dentry *, char __user *,int);
-       const char *(*follow_link) (struct dentry *, void **);
-       void (*put_link) (struct inode *, void *);
+       const char *(*get_link) (struct dentry *, struct inode *,
+                                struct delayed_call *);
        int (*permission) (struct inode *, int);
        int (*get_acl)(struct inode *, int);
        int (*setattr) (struct dentry *, struct iattr *);
@@ -434,20 +434,19 @@ otherwise noted.
   readlink: called by the readlink(2) system call. Only required if
        you want to support reading symbolic links
 
-  follow_link: called by the VFS to follow a symbolic link to the
+  get_link: called by the VFS to follow a symbolic link to the
        inode it points to.  Only required if you want to support
        symbolic links.  This method returns the symlink body
        to traverse (and possibly resets the current position with
        nd_jump_link()).  If the body won't go away until the inode
        is gone, nothing else is needed; if it needs to be otherwise
-       pinned, the data needed to release whatever we'd grabbed
-       is to be stored in void * variable passed by address to
-       follow_link() instance.
-
-  put_link: called by the VFS to release resources allocated by
-       follow_link().  The cookie stored by follow_link() is passed
-       to this method as the last parameter; only called when
-       cookie isn't NULL.
+       pinned, arrange for its release by having get_link(..., ..., done)
+       do set_delayed_call(done, destructor, argument).
+       In that case destructor(argument) will be called once VFS is
+       done with the body you've returned.
+       May be called in RCU mode; that is indicated by NULL dentry
+       argument.  If request can't be handled without leaving RCU mode,
+       have it return ERR_PTR(-ECHILD).
 
   permission: called by the VFS to check for access rights on a POSIX-like
        filesystem.
diff --git a/Documentation/hwmon/htu21 b/Documentation/hwmon/htu21
deleted file mode 100644 (file)
index f39a215..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-Kernel driver htu21
-===================
-
-Supported chips:
-  * Measurement Specialties HTU21D
-    Prefix: 'htu21'
-    Addresses scanned: none
-    Datasheet: Publicly available at the Measurement Specialties website
-    http://www.meas-spec.com/downloads/HTU21D.pdf
-
-
-Author:
-  William Markezana <william.markezana@meas-spec.com>
-
-Description
------------
-
-The HTU21D is a humidity and temperature sensor in a DFN package of
-only 3 x 3 mm footprint and 0.9 mm height.
-
-The devices communicate with the I2C protocol. All sensors are set to the
-same I2C address 0x40, so an entry with I2C_BOARD_INFO("htu21", 0x40) can
-be used in the board setup code.
-
-This driver does not auto-detect devices. You will have to instantiate the
-devices explicitly. Please see Documentation/i2c/instantiating-devices
-for details.
-
-sysfs-Interface
----------------
-
-temp1_input - temperature input
-humidity1_input - humidity input
-
-Notes
------
-
-The driver uses the default resolution settings of 12 bit for humidity and 14
-bit for temperature, which results in typical measurement times of 11 ms for
-humidity and 44 ms for temperature. To keep self heating below 0.1 degree
-Celsius, the device should not be active for more than 10% of the time. For
-this reason, the driver performs no more than two measurements per second and
-reports cached information if polled more frequently.
-
-Different resolutions, the on-chip heater, using the CRC checksum and reading
-the serial number are not supported yet.
diff --git a/Documentation/hwmon/ltc3815 b/Documentation/hwmon/ltc3815
new file mode 100644 (file)
index 0000000..eb7db2d
--- /dev/null
@@ -0,0 +1,61 @@
+Kernel driver ltc3815
+=====================
+
+Supported chips:
+  * Linear Technology LTC3815
+    Prefix: 'ltc3815'
+    Addresses scanned: -
+    Datasheet: http://www.linear.com/product/ltc3815
+
+Author: Guenter Roeck <linux@roeck-us.net>
+
+
+Description
+-----------
+
+LTC3815 is a Monolithic Synchronous DC/DC Step-Down Converter.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for PMBus devices. You will have to instantiate
+devices explicitly.
+
+Example: the following commands will load the driver for an LTC3815
+at address 0x20 on I2C bus #1:
+
+# modprobe ltc3815
+# echo ltc3815 0x20 > /sys/bus/i2c/devices/i2c-1/new_device
+
+
+Sysfs attributes
+----------------
+
+in1_label              "vin"
+in1_input              Measured input voltage.
+in1_alarm              Input voltage alarm.
+in1_highest            Highest input voltage.
+in1_reset_history      Reset input voltage history.
+
+in2_label              "vout1".
+in2_input              Measured output voltage.
+in2_alarm              Output voltage alarm.
+in2_highest            Highest output voltage.
+in2_reset_history      Reset output voltage history.
+
+temp1_input            Measured chip temperature.
+temp1_alarm            Temperature alarm.
+temp1_highest          Highest measured temperature.
+temp1_reset_history    Reset temperature history.
+
+curr1_label            "iin".
+curr1_input            Measured input current.
+curr1_highest          Highest input current.
+curr1_reset_history    Reset input current history.
+
+curr2_label            "iout1".
+curr2_input            Measured output current.
+curr2_alarm            Output current alarm.
+curr2_highest          Highest output current.
+curr2_reset_history    Reset output current history.
index 742f69d18fc8989ae28d9c0662d6bf334109dddd..1a8169ba29e6e0516c6837cf0ea04317b9253afb 100644 (file)
@@ -472,6 +472,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        Change the amount of debugging information output
                        when initialising the APIC and IO-APIC components.
 
+       apic_extnmi=    [APIC,X86] External NMI delivery setting
+                       Format: { bsp (default) | all | none }
+                       bsp:  External NMI is delivered only to CPU 0
+                       all:  External NMIs are broadcast to all CPUs as a
+                             backup of CPU 0
+                       none: External NMI is masked for all CPUs. This is
+                             useful so that a dump capture kernel won't be
+                             shot down by NMI
+
        autoconf=       [IPV6]
                        See Documentation/networking/ipv6.txt.
 
@@ -3296,18 +3305,35 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        rcutorture.verbose= [KNL]
                        Enable additional printk() statements.
 
+       rcupdate.rcu_cpu_stall_suppress= [KNL]
+                       Suppress RCU CPU stall warning messages.
+
+       rcupdate.rcu_cpu_stall_timeout= [KNL]
+                       Set timeout for RCU CPU stall warning messages.
+
        rcupdate.rcu_expedited= [KNL]
                        Use expedited grace-period primitives, for
                        example, synchronize_rcu_expedited() instead
                        of synchronize_rcu().  This reduces latency,
                        but can increase CPU utilization, degrade
                        real-time latency, and degrade energy efficiency.
-
-       rcupdate.rcu_cpu_stall_suppress= [KNL]
-                       Suppress RCU CPU stall warning messages.
-
-       rcupdate.rcu_cpu_stall_timeout= [KNL]
-                       Set timeout for RCU CPU stall warning messages.
+                       No effect on CONFIG_TINY_RCU kernels.
+
+       rcupdate.rcu_normal= [KNL]
+                       Use only normal grace-period primitives,
+                       for example, synchronize_rcu() instead of
+                       synchronize_rcu_expedited().  This improves
+                       real-time latency, CPU utilization, and
+                       energy efficiency, but can expose users to
+                       increased grace-period latency.  This parameter
+                       overrides rcupdate.rcu_expedited.  No effect on
+                       CONFIG_TINY_RCU kernels.
+
+       rcupdate.rcu_normal_after_boot= [KNL]
+                       Once boot has completed (that is, after
+                       rcu_end_inkernel_boot() has been invoked), use
+                       only normal grace-period primitives.  No effect
+                       on CONFIG_TINY_RCU kernels.
 
        rcupdate.rcu_task_stall_timeout= [KNL]
                        Set timeout in jiffies for RCU task stall warning
@@ -4114,6 +4140,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        or other driver-specific files in the
                        Documentation/watchdog/ directory.
 
+       workqueue.watchdog_thresh=
+                       If CONFIG_WQ_WATCHDOG is configured, workqueue can
+                       warn stall conditions and dump internal state to
+                       help debugging.  0 disables workqueue stall
+                       detection; otherwise, it's the stall threshold
+                       duration in seconds.  The default value is 30 and
+                       it can be updated at runtime by writing to the
+                       corresponding sysfs file.
+
        workqueue.disable_numa
                        By default, all work items queued to unbound
                        workqueues are affine to the NUMA nodes they're
index 62261c04060a73bef82a3a6784cef794d39e5d50..d406d98339b25abbe3d1f5f05c4ac7f9856d3e9c 100644 (file)
@@ -52,6 +52,19 @@ above leaves scope for further attributes should they be needed. If sections
 of the name don't apply, just leave that section blank.
 
 
+Brightness setting API
+======================
+
+LED subsystem core exposes following API for setting brightness:
+
+    - led_set_brightness : it is guaranteed not to sleep, passing LED_OFF stops
+               blinking,
+    - led_set_brightness_sync : for use cases when immediate effect is desired -
+               it can block the caller for the time required for accessing
+               device registers and can sleep, passing LED_OFF stops hardware
+               blinking, returns -EBUSY if software blink fallback is enabled.
+
+
 Hardware accelerated blink of LEDs
 ==================================
 
index aef9487303d023cd00d27dceadb441c78f12413f..a61be39c7b516a1e3b081afd1fea02a3f1068187 100644 (file)
@@ -194,7 +194,7 @@ There are some minimal guarantees that may be expected of a CPU:
  (*) On any given CPU, dependent memory accesses will be issued in order, with
      respect to itself.  This means that for:
 
-       WRITE_ONCE(Q, P); smp_read_barrier_depends(); D = READ_ONCE(*Q);
+       Q = READ_ONCE(P); smp_read_barrier_depends(); D = READ_ONCE(*Q);
 
      the CPU will issue the following memory operations:
 
@@ -202,9 +202,9 @@ There are some minimal guarantees that may be expected of a CPU:
 
      and always in that order.  On most systems, smp_read_barrier_depends()
      does nothing, but it is required for DEC Alpha.  The READ_ONCE()
-     and WRITE_ONCE() are required to prevent compiler mischief.  Please
-     note that you should normally use something like rcu_dereference()
-     instead of open-coding smp_read_barrier_depends().
+     is required to prevent compiler mischief.  Please note that you
+     should normally use something like rcu_dereference() instead of
+     open-coding smp_read_barrier_depends().
 
  (*) Overlapping loads and stores within a particular CPU will appear to be
      ordered within that CPU.  This means that for:
@@ -1673,8 +1673,8 @@ There are some more advanced barrier functions:
  (*) smp_store_mb(var, value)
 
      This assigns the value to the variable and then inserts a full memory
-     barrier after it, depending on the function.  It isn't guaranteed to
-     insert anything more than a compiler barrier in a UP compilation.
+     barrier after it.  It isn't guaranteed to insert anything more than a
+     compiler barrier in a UP compilation.
 
 
  (*) smp_mb__before_atomic();
index af70d1541d3af5b18834bce320ddd3e37009d29b..73c6b1ef0e8456a5de653305c1f9c783f0d958c1 100644 (file)
@@ -551,6 +551,21 @@ the recommended setting is 60.
 
 ==============================================================
 
+panic_on_io_nmi:
+
+Controls the kernel's behavior when a CPU receives an NMI caused by
+an IO error.
+
+0: try to continue operation (default)
+
+1: panic immediately. The IO error triggered an NMI. This indicates a
+   serious system condition which could result in IO data corruption.
+   Rather than continuing, panicking might be a better choice. Some
+   servers issue this sort of NMI when the dump button is pushed,
+   and you can use this option to take a crash dump.
+
+==============================================================
+
 panic_on_oops:
 
 Controls the kernel's behaviour when an oops or BUG is encountered.
diff --git a/Documentation/trace/events-msr.txt b/Documentation/trace/events-msr.txt
new file mode 100644 (file)
index 0000000..78c383b
--- /dev/null
@@ -0,0 +1,37 @@
+
+The x86 kernel supports tracing most MSR (Model Specific Register) accesses.
+To see the definition of the MSRs on Intel systems please see the SDM
+at http://www.intel.com/sdm (Volume 3)
+
+Available trace points:
+
+/sys/kernel/debug/tracing/events/msr/
+
+Trace MSR reads
+
+read_msr
+
+msr: MSR number
+val: Value written
+failed: 1 if the access failed, otherwise 0
+
+
+Trace MSR writes
+
+write_msr
+
+msr: MSR number
+val: Value written
+failed: 1 if the access failed, otherwise 0
+
+
+Trace RDPMC in kernel
+
+rdpmc
+
+The trace data can be post processed with the postprocess/decode_msr.py script
+
+cat /sys/kernel/debug/tracing/trace | decode_msr.py /usr/src/linux/include/asm/msr-index.h
+
+to add symbolic MSR names.
+
diff --git a/Documentation/trace/postprocess/decode_msr.py b/Documentation/trace/postprocess/decode_msr.py
new file mode 100644 (file)
index 0000000..0ab40e0
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/python
+# add symbolic names to read_msr / write_msr in trace
+# decode_msr msr-index.h < trace
+import sys
+import re
+
+msrs = dict()
+
+with open(sys.argv[1] if len(sys.argv) > 1 else "msr-index.h", "r") as f:
+       for j in f:
+               m = re.match(r'#define (MSR_\w+)\s+(0x[0-9a-fA-F]+)', j)
+               if m:
+                       msrs[int(m.group(2), 16)] = m.group(1)
+
+extra_ranges = (
+       ( "MSR_LASTBRANCH_%d_FROM_IP", 0x680, 0x69F ),
+       ( "MSR_LASTBRANCH_%d_TO_IP", 0x6C0, 0x6DF ),
+       ( "LBR_INFO_%d", 0xdc0, 0xddf ),
+)
+
+for j in sys.stdin:
+       m = re.search(r'(read|write)_msr:\s+([0-9a-f]+)', j)
+       if m:
+               r = None
+               num = int(m.group(2), 16)
+               if num in msrs:
+                       r = msrs[num]
+               else:
+                       for er in extra_ranges:
+                               if er[1] <= num <= er[2]:
+                                       r = er[0] % (num - er[1],)
+                                       break
+               if r:
+                       j = j.replace(" " + m.group(2), " " + r + "(" + m.group(2) + ")")
+       print j,
+
+
index 256f8efa992c27a30c34bcbeca0c9bc3053f9e2e..eaf948cf1ae7176293bf3312392fbee5875f6b92 100644 (file)
@@ -9,7 +9,7 @@
   <table border="0">
    <tr>
     <td>
-     <a href="http://linuxtv.org/downloads/legacy/video4linux/API/V4L1_API.html">V4L original API</a>
+     <a href="https://linuxtv.org/downloads/legacy/video4linux/API/V4L1_API.html">V4L original API</a>
     </td>
     <td>
      Obsoleted by V4L2 API
index 9e57ce43c4f499fbe3bf8c27775bcd3f5a50bc69..67209998a439ee55c9169194c368e7c6a192c40d 100644 (file)
@@ -41,8 +41,8 @@
  40 -> Plextor ConvertX PX-TV100U               (em2861)        [093b:a005]
  41 -> Kworld 350 U DVB-T                       (em2870)        [eb1a:e350]
  42 -> Kworld 355 U DVB-T                       (em2870)        [eb1a:e355,eb1a:e357,eb1a:e359]
- 43 -> Terratec Cinergy T XS                    (em2870)        [0ccd:0043]
- 44 -> Terratec Cinergy T XS (MT2060)           (em2870)
+ 43 -> Terratec Cinergy T XS                    (em2870)
+ 44 -> Terratec Cinergy T XS (MT2060)           (em2870)        [0ccd:0043]
  45 -> Pinnacle PCTV DVB-T                      (em2870)
  46 -> Compro, VideoMate U3                     (em2870)        [185b:2870]
  47 -> KWorld DVB-T 305U                        (em2880)        [eb1a:e305]
index e0c6b8bc4743736c2f98dce83238d24bf86aa8af..4fab231be52eb188bc59ac34595c57949d908ee5 100644 (file)
@@ -58,7 +58,7 @@ Not currently supported:
 4.1. Media device interface
 
 The driver supports Media Controller API as defined at
-http://linuxtv.org/downloads/v4l-dvb-apis/media_common.html
+https://linuxtv.org/downloads/v4l-dvb-apis/media_common.html
 The media device driver name is "SAMSUNG S5P FIMC".
 
 The purpose of this interface is to allow changing assignment of FIMC instances
@@ -83,11 +83,11 @@ undefined behaviour.
 4.3. Capture video node
 
 The driver supports V4L2 Video Capture Interface as defined at:
-http://linuxtv.org/downloads/v4l-dvb-apis/devices.html
+https://linuxtv.org/downloads/v4l-dvb-apis/devices.html
 
 At the capture and mem-to-mem video nodes only the multi-planar API is
 supported. For more details see:
-http://linuxtv.org/downloads/v4l-dvb-apis/planar-apis.html
+https://linuxtv.org/downloads/v4l-dvb-apis/planar-apis.html
 
 4.4. Camera capture subdevs
 
index 25d9b40a4651f0d2694819960384a48ffd98c5dc..a6734aa77242625d0bb9de6b4a946aea9b38f26c 100644 (file)
@@ -47,7 +47,7 @@ Tested platforms
 File list
 ---------
 drivers/staging/media/omap4iss/
-include/media/omap4iss.h
+include/linux/platform_data/media/omap4iss.h
 
 References
 ----------
index 2e7392a4fee1a736dcd6135f6f08341b38505e3b..2ddc6b095a760e80ed2202f96e045823f8b7f849 100644 (file)
@@ -157,7 +157,7 @@ int main (int argc, char *argv[])
 }
 
 The struct si4713_rnl and SI4713_IOC_MEASURE_RNL are defined under
-include/media/si4713.h.
+include/linux/platform_data/media/si4713.h.
 
 Stereo/Mono and RDS subchannels
 ===============================
index 95ae8286009280a568e18a98cd6ecd0d59f1fc36..79af0c0410565f0eaae17b4be4e5185aff3f9ea8 100644 (file)
@@ -163,11 +163,10 @@ static irqreturn_t skeleton_irq(int irq, void *dev_id)
  * minimum number: many DMA engines need a minimum of 2 buffers in the
  * queue and you need to have another available for userspace processing.
  */
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
                       unsigned int *nbuffers, unsigned int *nplanes,
                       unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct skeleton *skel = vb2_get_drv_priv(vq);
 
        skel->field = skel->format.field;
@@ -183,12 +182,12 @@ static int queue_setup(struct vb2_queue *vq, const void *parg,
 
        if (vq->num_buffers + *nbuffers < 3)
                *nbuffers = 3 - vq->num_buffers;
+       alloc_ctxs[0] = skel->alloc_ctx;
 
-       if (fmt && fmt->fmt.pix.sizeimage < skel->format.sizeimage)
-               return -EINVAL;
+       if (*nplanes)
+               return sizes[0] < skel->format.sizeimage ? -EINVAL : 0;
        *nplanes = 1;
-       sizes[0] = fmt ? fmt->fmt.pix.sizeimage : skel->format.sizeimage;
-       alloc_ctxs[0] = skel->alloc_ctx;
+       sizes[0] = skel->format.sizeimage;
        return 0;
 }
 
@@ -509,7 +508,7 @@ static int skeleton_s_dv_timings(struct file *file, void *_fh,
                return -EINVAL;
 
        /* Return 0 if the new timings are the same as the current timings. */
-       if (v4l2_match_dv_timings(timings, &skel->timings, 0))
+       if (v4l2_match_dv_timings(timings, &skel->timings, 0, false))
                return 0;
 
        /*
index 092ee9fbaf2bdc15868475267e5875727a62841f..053f613fc9a913af132da7f794742c45d6727dfc 100644 (file)
@@ -1451,6 +1451,7 @@ struct kvm_irq_routing_entry {
                struct kvm_irq_routing_irqchip irqchip;
                struct kvm_irq_routing_msi msi;
                struct kvm_irq_routing_s390_adapter adapter;
+               struct kvm_irq_routing_hv_sint hv_sint;
                __u32 pad[8];
        } u;
 };
@@ -1459,6 +1460,7 @@ struct kvm_irq_routing_entry {
 #define KVM_IRQ_ROUTING_IRQCHIP 1
 #define KVM_IRQ_ROUTING_MSI 2
 #define KVM_IRQ_ROUTING_S390_ADAPTER 3
+#define KVM_IRQ_ROUTING_HV_SINT 4
 
 No flags are specified so far, the corresponding field must be set to zero.
 
@@ -1482,6 +1484,10 @@ struct kvm_irq_routing_s390_adapter {
        __u32 adapter_id;
 };
 
+struct kvm_irq_routing_hv_sint {
+       __u32 vcpu;
+       __u32 sint;
+};
 
 4.53 KVM_ASSIGN_SET_MSIX_NR (deprecated)
 
@@ -3331,6 +3337,28 @@ the userspace IOAPIC should process the EOI and retrigger the interrupt if
 it is still asserted.  Vector is the LAPIC interrupt vector for which the
 EOI was received.
 
+               struct kvm_hyperv_exit {
+#define KVM_EXIT_HYPERV_SYNIC          1
+                       __u32 type;
+                       union {
+                               struct {
+                                       __u32 msr;
+                                       __u64 control;
+                                       __u64 evt_page;
+                                       __u64 msg_page;
+                               } synic;
+                       } u;
+               };
+               /* KVM_EXIT_HYPERV */
+                struct kvm_hyperv_exit hyperv;
+Indicates that the VCPU exits into userspace to process some tasks
+related to Hyper-V emulation.
+Valid values for 'type' are:
+       KVM_EXIT_HYPERV_SYNIC -- synchronously notify user-space about
+Hyper-V SynIC state change. Notification is used to remap SynIC
+event/message pages and to enable/disable SynIC messages/events processing
+in userspace.
+
                /* Fix the size of the union. */
                char padding[256];
        };
@@ -3685,3 +3713,16 @@ available, means that that the kernel has an implementation of the
 H_RANDOM hypercall backed by a hardware random-number generator.
 If present, the kernel H_RANDOM handler can be enabled for guest use
 with the KVM_CAP_PPC_ENABLE_HCALL capability.
+
+8.2 KVM_CAP_HYPERV_SYNIC
+
+Architectures: x86
+This capability, if KVM_CHECK_EXTENSION indicates that it is
+available, means that that the kernel has an implementation of the
+Hyper-V Synthetic interrupt controller(SynIC). Hyper-V SynIC is
+used to support Windows Hyper-V based guest paravirt drivers(VMBus).
+
+In order to use SynIC, it has to be activated by setting this
+capability via KVM_ENABLE_CAP ioctl on the vcpu fd. Note that this
+will disable the use of APIC hardware virtualization even if supported
+by the CPU, as it's incompatible with SynIC auto-EOI behavior.
index 2d09d1ed86d02d99046d62b1a772589e3de70c4d..f083a168eb350b80895f25a23621b87a131be84b 100644 (file)
@@ -37,7 +37,8 @@ Returns: -EFAULT if the given address is not accessible
 Allows userspace to query the actual limit and set a new limit for
 the maximum guest memory size. The limit will be rounded up to
 2048 MB, 4096 GB, 8192 TB respectively, as this limit is governed by
-the number of page table levels.
+the number of page table levels. In the case that there is no limit we will set
+the limit to KVM_S390_NO_MEM_LIMIT (U64_MAX).
 
 2. GROUP: KVM_S390_VM_CPU_MODEL
 Architectures: s390
index 3a4d681c3e981863ce2b30e8919cb16b9004d962..daf9c0f742d22e882637391539e90ea31eb788f3 100644 (file)
@@ -203,10 +203,10 @@ Shadow pages contain the following information:
     page cannot be destroyed.  See role.invalid.
   parent_ptes:
     The reverse mapping for the pte/ptes pointing at this page's spt. If
-    parent_ptes bit 0 is zero, only one spte points at this pages and
+    parent_ptes bit 0 is zero, only one spte points at this page and
     parent_ptes points at this single spte, otherwise, there exists multiple
     sptes pointing at this page and (parent_ptes & ~0x1) points at a data
-    structure with a list of parent_ptes.
+    structure with a list of parent sptes.
   unsync:
     If true, then the translations in this page may not match the guest's
     translation.  This is equivalent to the state of the tlb when a pte is
index 233f83464814f138c4c68f0815d2dbeace552ef6..e99a7b328c7f3e898f1b51c2d59224ef597633ad 100644 (file)
@@ -206,7 +206,7 @@ F:  include/trace/events/9p.h
 A8293 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -395,7 +395,7 @@ M:  Sakari Ailus <sakari.ailus@iki.fi>
 L:     linux-media@vger.kernel.org
 S:     Maintained
 F:     drivers/media/i2c/adp1653.c
-F:     include/media/adp1653.h
+F:     include/media/i2c/adp1653.h
 
 ADP5520 BACKLIGHT DRIVER WITH IO EXPANDER (ADP5520/ADP5501)
 M:     Michael Hennerich <michael.hennerich@analog.com>
@@ -466,7 +466,7 @@ F:  sound/oss/aedsp16.c
 AF9013 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -476,7 +476,7 @@ F:  drivers/media/dvb-frontends/af9013*
 AF9033 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -522,7 +522,7 @@ AIMSLAB FM RADIO RECEIVER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Maintained
 F:     drivers/media/radio/radio-aimslab*
 
@@ -536,7 +536,7 @@ F:  include/linux/*aio*.h
 AIRSPY MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -614,9 +614,9 @@ F:  drivers/crypto/ccp/
 F:     include/linux/ccp.h
 
 AMD FAM15H PROCESSOR POWER MONITORING DRIVER
-M:     Andreas Herrmann <herrmann.der.user@googlemail.com>
+M:     Huang Rui <ray.huang@amd.com>
 L:     lm-sensors@lm-sensors.org
-S:     Maintained
+S:     Supported
 F:     Documentation/hwmon/fam15h_power
 F:     drivers/hwmon/fam15h_power.c
 
@@ -1773,7 +1773,7 @@ L:        linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
 F:     drivers/media/i2c/as3645a.c
-F:     include/media/as3645a.h
+F:     include/media/i2c/as3645a.h
 
 ASC7621 HARDWARE MONITOR DRIVER
 M:     George Joseph <george.joseph@fairview5.com>
@@ -1896,7 +1896,6 @@ ATMEL AT91 / AT32 MCI DRIVER
 M:     Ludovic Desroches <ludovic.desroches@atmel.com>
 S:     Maintained
 F:     drivers/mmc/host/atmel-mci.c
-F:     drivers/mmc/host/atmel-mci-regs.h
 
 ATMEL AT91 / AT32 SERIAL DRIVER
 M:     Nicolas Ferre <nicolas.ferre@atmel.com>
@@ -2064,7 +2063,7 @@ F:        net/ax25/
 AZ6007 DVB DRIVER
 M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
 F:     drivers/media/usb/dvb-usb-v2/az6007.c
@@ -2073,7 +2072,7 @@ AZTECH FM RADIO RECEIVER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Maintained
 F:     drivers/media/radio/radio-aztech*
 
@@ -2126,7 +2125,7 @@ BDISP ST MEDIA DRIVER
 M:     Fabien Dessenne <fabien.dessenne@st.com>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Supported
 F:     drivers/media/platform/sti/bdisp
 
@@ -2519,7 +2518,7 @@ F:        fs/btrfs/
 BTTV VIDEO4LINUX DRIVER
 M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Odd fixes
 F:     Documentation/video4linux/bttv/
@@ -2558,7 +2557,7 @@ CADET FM/AM RADIO RECEIVER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Maintained
 F:     drivers/media/radio/radio-cadet*
 
@@ -2851,7 +2850,7 @@ COBALT MEDIA DRIVER
 M:     Hans Verkuil <hans.verkuil@cisco.com>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Supported
 F:     drivers/media/pci/cobalt/
 
@@ -3096,6 +3095,15 @@ S:       Maintained
 F:     crypto/ansi_cprng.c
 F:     crypto/rng.c
 
+CS3308 MEDIA DRIVER
+M:     Hans Verkuil <hverkuil@xs4all.nl>
+L:     linux-media@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+W:     http://linuxtv.org
+S:     Odd Fixes
+F:     drivers/media/i2c/cs3308.c
+F:     drivers/media/i2c/cs3308.h
+
 CS5535 Audio ALSA driver
 M:     Jaya Kumar <jayakumar.alsa@gmail.com>
 S:     Maintained
@@ -3111,7 +3119,7 @@ M:        Andy Walls <awalls@md.metrocast.net>
 L:     ivtv-devel@ivtvdriver.org (subscribers-only)
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 W:     http://www.ivtvdriver.org/index.php/Cx18
 S:     Maintained
 F:     Documentation/video4linux/cx18.txt
@@ -3122,7 +3130,7 @@ CX2341X MPEG ENCODER HELPER MODULE
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Maintained
 F:     drivers/media/common/cx2341x*
 F:     include/media/cx2341x*
@@ -3131,7 +3139,7 @@ CX24120 MEDIA DRIVER
 M:     Jemma Denson <jdenson@gmail.com>
 M:     Patrick Boettcher <patrick.boettcher@posteo.de>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 S:     Maintained
 F:     drivers/media/dvb-frontends/cx24120*
@@ -3139,7 +3147,7 @@ F:        drivers/media/dvb-frontends/cx24120*
 CX88 VIDEO4LINUX DRIVER
 M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Odd fixes
 F:     Documentation/video4linux/cx88/
@@ -3148,7 +3156,7 @@ F:        drivers/media/pci/cx88/
 CXD2820R MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -3254,7 +3262,7 @@ F:        drivers/net/wan/pc300*
 CYPRESS_FIRMWARE MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -3761,14 +3769,14 @@ DT3155 MEDIA DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Odd Fixes
 F:     drivers/media/pci/dt3155/
 
 DVB_USB_AF9015 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -3778,7 +3786,7 @@ F:        drivers/media/usb/dvb-usb-v2/af9015*
 DVB_USB_AF9035 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -3788,7 +3796,7 @@ F:        drivers/media/usb/dvb-usb-v2/af9035*
 DVB_USB_ANYSEE MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -3798,7 +3806,7 @@ F:        drivers/media/usb/dvb-usb-v2/anysee*
 DVB_USB_AU6610 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -3808,7 +3816,7 @@ F:        drivers/media/usb/dvb-usb-v2/au6610*
 DVB_USB_CE6230 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -3818,7 +3826,7 @@ F:        drivers/media/usb/dvb-usb-v2/ce6230*
 DVB_USB_CXUSB MEDIA DRIVER
 M:     Michael Krufky <mkrufky@linuxtv.org>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 W:     http://github.com/mkrufky
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/media_tree.git
@@ -3828,7 +3836,7 @@ F:        drivers/media/usb/dvb-usb/cxusb*
 DVB_USB_EC168 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -3838,7 +3846,7 @@ F:        drivers/media/usb/dvb-usb-v2/ec168*
 DVB_USB_GL861 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
 S:     Maintained
@@ -3847,7 +3855,7 @@ F:        drivers/media/usb/dvb-usb-v2/gl861*
 DVB_USB_MXL111SF MEDIA DRIVER
 M:     Michael Krufky <mkrufky@linuxtv.org>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 W:     http://github.com/mkrufky
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/mkrufky/mxl111sf.git
@@ -3857,7 +3865,7 @@ F:        drivers/media/usb/dvb-usb-v2/mxl111sf*
 DVB_USB_RTL28XXU MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -3867,7 +3875,7 @@ F:        drivers/media/usb/dvb-usb-v2/rtl28xxu*
 DVB_USB_V2 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -3897,7 +3905,7 @@ F:        Documentation/devicetree/bindings/input/e3x0-button.txt
 E4000 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -3913,7 +3921,7 @@ F:        drivers/scsi/eata.c
 EC100 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -3934,9 +3942,8 @@ M:        Doug Thompson <dougthompson@xmission.com>
 M:     Borislav Petkov <bp@alien8.de>
 M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-edac@vger.kernel.org
-W:     bluesmoke.sourceforge.net
-T:     git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git#for-next
-T:     git://git.kernel.org/pub/linux/kernel/git/mchehab/linux-edac.git#linux_next
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git for-next
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac.git linux_next
 S:     Supported
 F:     Documentation/edac.txt
 F:     drivers/edac/
@@ -3946,7 +3953,6 @@ EDAC-AMD64
 M:     Doug Thompson <dougthompson@xmission.com>
 M:     Borislav Petkov <bp@alien8.de>
 L:     linux-edac@vger.kernel.org
-W:     bluesmoke.sourceforge.net
 S:     Maintained
 F:     drivers/edac/amd64_edac*
 
@@ -3954,7 +3960,6 @@ EDAC-CALXEDA
 M:     Doug Thompson <dougthompson@xmission.com>
 M:     Robert Richter <rric@kernel.org>
 L:     linux-edac@vger.kernel.org
-W:     bluesmoke.sourceforge.net
 S:     Maintained
 F:     drivers/edac/highbank*
 
@@ -3963,7 +3968,6 @@ M:        Ralf Baechle <ralf@linux-mips.org>
 M:     David Daney <david.daney@cavium.com>
 L:     linux-edac@vger.kernel.org
 L:     linux-mips@linux-mips.org
-W:     bluesmoke.sourceforge.net
 S:     Supported
 F:     drivers/edac/octeon_edac*
 
@@ -3971,63 +3975,54 @@ EDAC-E752X
 M:     Mark Gross <mark.gross@intel.com>
 M:     Doug Thompson <dougthompson@xmission.com>
 L:     linux-edac@vger.kernel.org
-W:     bluesmoke.sourceforge.net
 S:     Maintained
 F:     drivers/edac/e752x_edac.c
 
 EDAC-E7XXX
 M:     Doug Thompson <dougthompson@xmission.com>
 L:     linux-edac@vger.kernel.org
-W:     bluesmoke.sourceforge.net
 S:     Maintained
 F:     drivers/edac/e7xxx_edac.c
 
 EDAC-GHES
 M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-edac@vger.kernel.org
-W:     bluesmoke.sourceforge.net
 S:     Maintained
 F:     drivers/edac/ghes_edac.c
 
 EDAC-I82443BXGX
 M:     Tim Small <tim@buttersideup.com>
 L:     linux-edac@vger.kernel.org
-W:     bluesmoke.sourceforge.net
 S:     Maintained
 F:     drivers/edac/i82443bxgx_edac.c
 
 EDAC-I3000
 M:     Jason Uhlenkott <juhlenko@akamai.com>
 L:     linux-edac@vger.kernel.org
-W:     bluesmoke.sourceforge.net
 S:     Maintained
 F:     drivers/edac/i3000_edac.c
 
 EDAC-I5000
 M:     Doug Thompson <dougthompson@xmission.com>
 L:     linux-edac@vger.kernel.org
-W:     bluesmoke.sourceforge.net
 S:     Maintained
 F:     drivers/edac/i5000_edac.c
 
 EDAC-I5400
 M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-edac@vger.kernel.org
-W:     bluesmoke.sourceforge.net
 S:     Maintained
 F:     drivers/edac/i5400_edac.c
 
 EDAC-I7300
 M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-edac@vger.kernel.org
-W:     bluesmoke.sourceforge.net
 S:     Maintained
 F:     drivers/edac/i7300_edac.c
 
 EDAC-I7CORE
 M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-edac@vger.kernel.org
-W:     bluesmoke.sourceforge.net
 S:     Maintained
 F:     drivers/edac/i7core_edac.c
 
@@ -4035,42 +4030,36 @@ EDAC-I82975X
 M:     Ranganathan Desikan <ravi@jetztechnologies.com>
 M:     "Arvind R." <arvino55@gmail.com>
 L:     linux-edac@vger.kernel.org
-W:     bluesmoke.sourceforge.net
 S:     Maintained
 F:     drivers/edac/i82975x_edac.c
 
 EDAC-IE31200
 M:     Jason Baron <jbaron@akamai.com>
 L:     linux-edac@vger.kernel.org
-W:     bluesmoke.sourceforge.net
 S:     Maintained
 F:     drivers/edac/ie31200_edac.c
 
 EDAC-MPC85XX
 M:     Johannes Thumshirn <morbidrsa@gmail.com>
 L:     linux-edac@vger.kernel.org
-W:     bluesmoke.sourceforge.net
 S:     Maintained
 F:     drivers/edac/mpc85xx_edac.[ch]
 
 EDAC-PASEMI
 M:     Egor Martovetsky <egor@pasemi.com>
 L:     linux-edac@vger.kernel.org
-W:     bluesmoke.sourceforge.net
 S:     Maintained
 F:     drivers/edac/pasemi_edac.c
 
 EDAC-R82600
 M:     Tim Small <tim@buttersideup.com>
 L:     linux-edac@vger.kernel.org
-W:     bluesmoke.sourceforge.net
 S:     Maintained
 F:     drivers/edac/r82600_edac.c
 
 EDAC-SBRIDGE
 M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-edac@vger.kernel.org
-W:     bluesmoke.sourceforge.net
 S:     Maintained
 F:     drivers/edac/sb_edac.c
 
@@ -4137,7 +4126,7 @@ F:        drivers/net/ethernet/ibm/ehea/
 EM28XX VIDEO4LINUX DRIVER
 M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
 F:     drivers/media/usb/em28xx/
@@ -4277,7 +4266,7 @@ F:        drivers/media/tuners/fc0011.c
 FC2580 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -4600,7 +4589,7 @@ M:        Heungjun Kim <riverful.kim@samsung.com>
 L:     linux-media@vger.kernel.org
 S:     Maintained
 F:     drivers/media/i2c/m5mols/
-F:     include/media/m5mols.h
+F:     include/media/i2c/m5mols.h
 
 FUJITSU TABLET EXTRAS
 M:     Robert Gerlach <khnz@gmx.de>
@@ -4646,7 +4635,7 @@ GEMTEK FM RADIO RECEIVER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Maintained
 F:     drivers/media/radio/radio-gemtek*
 
@@ -4854,7 +4843,7 @@ HDPVR USB VIDEO ENCODER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Odd Fixes
 F:     drivers/media/usb/hdpvr/
 
@@ -4873,7 +4862,7 @@ F:        drivers/tty/hvc/
 HACKRF MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -4916,7 +4905,7 @@ F:        sound/parisc/harmony.*
 HD29L2 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -5622,9 +5611,7 @@ F:        Documentation/trace/intel_th.txt
 F:     drivers/hwtracing/intel_th/
 
 INTEL(R) TRUSTED EXECUTION TECHNOLOGY (TXT)
-M:     Richard L Maliszewski <richard.l.maliszewski@intel.com>
-M:     Gang Wei <gang.wei@intel.com>
-M:     Shane Wang <shane.wang@intel.com>
+M:     Ning Sun <ning.sun@intel.com>
 L:     tboot-devel@lists.sourceforge.net
 W:     http://tboot.sourceforge.net
 T:     hg http://tboot.hg.sourceforge.net:8000/hgroot/tboot/tboot
@@ -5822,7 +5809,7 @@ ISA RADIO MODULE
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Maintained
 F:     drivers/media/radio/radio-isa*
 
@@ -5892,7 +5879,7 @@ F:        drivers/hwmon/it87.c
 IT913X MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -5913,7 +5900,7 @@ F:        include/uapi/linux/ivtv*
 IX2505V MEDIA DRIVER
 M:     Malcolm Priestley <tvboxspy@gmail.com>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 S:     Maintained
 F:     drivers/media/dvb-frontends/ix2505v*
@@ -6002,7 +5989,7 @@ KEENE FM RADIO TRANSMITTER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Maintained
 F:     drivers/media/radio/radio-keene*
 
@@ -6102,6 +6089,7 @@ M:        Marc Zyngier <marc.zyngier@arm.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     kvmarm@lists.cs.columbia.edu
 W:     http://systems.cs.columbia.edu/projects/kvm-arm
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git
 S:     Supported
 F:     arch/arm/include/uapi/asm/kvm*
 F:     arch/arm/include/asm/kvm*
@@ -6254,7 +6242,7 @@ F:        drivers/usb/misc/legousbtower.c
 LG2160 MEDIA DRIVER
 M:     Michael Krufky <mkrufky@linuxtv.org>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 W:     http://github.com/mkrufky
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/mkrufky/tuners.git
@@ -6264,7 +6252,7 @@ F:        drivers/media/dvb-frontends/lg2160.*
 LGDT3305 MEDIA DRIVER
 M:     Michael Krufky <mkrufky@linuxtv.org>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 W:     http://github.com/mkrufky
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/mkrufky/tuners.git
@@ -6521,7 +6509,7 @@ F:        drivers/hwmon/lm95234.c
 LME2510 MEDIA DRIVER
 M:     Malcolm Priestley <tvboxspy@gmail.com>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 S:     Maintained
 F:     drivers/media/usb/dvb-usb-v2/lmedm04*
@@ -6627,7 +6615,7 @@ F:        arch/m68k/hp300/
 M88DS3103 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -6637,7 +6625,7 @@ F:        drivers/media/dvb-frontends/m88ds3103*
 M88RS2000 MEDIA DRIVER
 M:     Malcolm Priestley <tvboxspy@gmail.com>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 S:     Maintained
 F:     drivers/media/dvb-frontends/m88rs2000*
@@ -6816,7 +6804,7 @@ MAXIRADIO FM RADIO RECEIVER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Maintained
 F:     drivers/media/radio/radio-maxiradio*
 
@@ -6838,7 +6826,7 @@ F:        drivers/media/platform/vsp1/
 MEDIA DRIVERS FOR ASCOT2E
 M:     Sergey Kozlov <serjk@netup.ru>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 W:     http://netup.tv/
 T:     git git://linuxtv.org/media_tree.git
 S:     Supported
@@ -6847,7 +6835,7 @@ F:        drivers/media/dvb-frontends/ascot2e*
 MEDIA DRIVERS FOR CXD2841ER
 M:     Sergey Kozlov <serjk@netup.ru>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 W:     http://netup.tv/
 T:     git git://linuxtv.org/media_tree.git
 S:     Supported
@@ -6856,7 +6844,7 @@ F:        drivers/media/dvb-frontends/cxd2841er*
 MEDIA DRIVERS FOR HORUS3A
 M:     Sergey Kozlov <serjk@netup.ru>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 W:     http://netup.tv/
 T:     git git://linuxtv.org/media_tree.git
 S:     Supported
@@ -6865,7 +6853,7 @@ F:        drivers/media/dvb-frontends/horus3a*
 MEDIA DRIVERS FOR LNBH25
 M:     Sergey Kozlov <serjk@netup.ru>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 W:     http://netup.tv/
 T:     git git://linuxtv.org/media_tree.git
 S:     Supported
@@ -6874,7 +6862,7 @@ F:        drivers/media/dvb-frontends/lnbh25*
 MEDIA DRIVERS FOR NETUP PCI UNIVERSAL DVB devices
 M:     Sergey Kozlov <serjk@netup.ru>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 W:     http://netup.tv/
 T:     git git://linuxtv.org/media_tree.git
 S:     Supported
@@ -6884,7 +6872,7 @@ MEDIA INPUT INFRASTRUCTURE (V4L/DVB)
 M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 P:     LinuxTV.org Project
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 Q:     http://patchwork.kernel.org/project/linux-media/list/
 T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
@@ -6893,6 +6881,7 @@ F:        Documentation/video4linux/
 F:     Documentation/DocBook/media/
 F:     drivers/media/
 F:     drivers/staging/media/
+F:     include/linux/platform_data/media/
 F:     include/media/
 F:     include/uapi/linux/dvb/
 F:     include/uapi/linux/videodev2.h
@@ -7044,7 +7033,7 @@ MIROSOUND PCM20 FM RADIO RECEIVER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Odd Fixes
 F:     drivers/media/radio/radio-miropcm20*
 
@@ -7080,7 +7069,7 @@ F:        drivers/iio/temperature/mlx90614.c
 MN88472 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -7091,7 +7080,7 @@ F:        drivers/media/dvb-frontends/mn88472.h
 MN88473 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -7146,7 +7135,7 @@ F:        drivers/platform/x86/msi-wmi.c
 MSI001 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -7156,7 +7145,7 @@ F:        drivers/media/tuners/msi001*
 MSI2500 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -7175,7 +7164,7 @@ L:        linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
 F:     drivers/media/i2c/mt9m032.c
-F:     include/media/mt9m032.h
+F:     include/media/i2c/mt9m032.h
 
 MT9P031 APTINA CAMERA SENSOR
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
@@ -7183,7 +7172,7 @@ L:        linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
 F:     drivers/media/i2c/mt9p031.c
-F:     include/media/mt9p031.h
+F:     include/media/i2c/mt9p031.h
 
 MT9T001 APTINA CAMERA SENSOR
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
@@ -7191,7 +7180,7 @@ L:        linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
 F:     drivers/media/i2c/mt9t001.c
-F:     include/media/mt9t001.h
+F:     include/media/i2c/mt9t001.h
 
 MT9V032 APTINA CAMERA SENSOR
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
@@ -7200,7 +7189,7 @@ T:        git git://linuxtv.org/media_tree.git
 S:     Maintained
 F:     Documentation/devicetree/bindings/media/i2c/mt9v032.txt
 F:     drivers/media/i2c/mt9v032.c
-F:     include/media/mt9v032.h
+F:     include/media/i2c/mt9v032.h
 
 MULTIFUNCTION DEVICES (MFD)
 M:     Lee Jones <lee.jones@linaro.org>
@@ -7244,7 +7233,7 @@ F:        drivers/usb/musb/
 MXL5007T MEDIA DRIVER
 M:     Michael Krufky <mkrufky@linuxtv.org>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 W:     http://github.com/mkrufky
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/mkrufky/tuners.git
@@ -8369,6 +8358,7 @@ F:        drivers/pinctrl/intel/
 
 PIN CONTROLLER - RENESAS
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+M:     Geert Uytterhoeven <geert+renesas@glider.be>
 L:     linux-sh@vger.kernel.org
 S:     Maintained
 F:     drivers/pinctrl/sh-pfc/
@@ -8639,6 +8629,7 @@ S:        Maintained
 F:     arch/arm/mach-pxa/
 F:     drivers/dma/pxa*
 F:     drivers/pcmcia/pxa2xx*
+F:     drivers/pinctrl/pxa/
 F:     drivers/spi/spi-pxa2xx*
 F:     drivers/usb/gadget/udc/pxa2*
 F:     include/sound/pxa2xx-lib.h
@@ -8745,7 +8736,7 @@ F:        include/uapi/linux/qnxtypes.h
 QT1010 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -9038,7 +9029,7 @@ F:        net/rose/
 RTL2830 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -9048,7 +9039,7 @@ F:        drivers/media/dvb-frontends/rtl2830*
 RTL2832 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -9058,7 +9049,7 @@ F:        drivers/media/dvb-frontends/rtl2832*
 RTL2832_SDR MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -9189,14 +9180,14 @@ SAA6588 RDS RECEIVER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Odd Fixes
 F:     drivers/media/i2c/saa6588*
 
 SAA7134 VIDEO4LINUX DRIVER
 M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Odd fixes
 F:     Documentation/video4linux/*.saa7134
@@ -9258,7 +9249,7 @@ L:        linux-media@vger.kernel.org
 L:     linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
 S:     Maintained
 F:     drivers/media/platform/s3c-camif/
-F:     include/media/s3c_camif.h
+F:     include/media/drv-intf/s3c_camif.h
 
 SAMSUNG S5C73M3 CAMERA DRIVER
 M:     Kyungmin Park <kyungmin.park@samsung.com>
@@ -9366,7 +9357,7 @@ M:        Andreas Noever <andreas.noever@gmail.com>
 S:     Maintained
 F:     drivers/thunderbolt/
 
-TIMEKEEPING, CLOCKSOURCE CORE, NTP
+TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER
 M:     John Stultz <john.stultz@linaro.org>
 M:     Thomas Gleixner <tglx@linutronix.de>
 L:     linux-kernel@vger.kernel.org
@@ -9379,6 +9370,7 @@ F:        include/uapi/linux/time.h
 F:     include/uapi/linux/timex.h
 F:     kernel/time/clocksource.c
 F:     kernel/time/time*.c
+F:     kernel/time/alarmtimer.c
 F:     kernel/time/ntp.c
 F:     tools/testing/selftests/timers/
 
@@ -9633,7 +9625,7 @@ F:        drivers/misc/sgi-xp/
 SI2157 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -9643,7 +9635,7 @@ F:        drivers/media/tuners/si2157*
 SI2168 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -9654,7 +9646,7 @@ SI470X FM RADIO RECEIVER I2C DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Odd Fixes
 F:     drivers/media/radio/si470x/radio-si470x-i2c.c
 
@@ -9662,7 +9654,7 @@ SI470X FM RADIO RECEIVER USB DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Maintained
 F:     drivers/media/radio/si470x/radio-si470x-common.c
 F:     drivers/media/radio/si470x/radio-si470x.h
@@ -9672,7 +9664,7 @@ SI4713 FM RADIO TRANSMITTER I2C DRIVER
 M:     Eduardo Valentin <edubezval@gmail.com>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Odd Fixes
 F:     drivers/media/radio/si4713/si4713.?
 
@@ -9680,7 +9672,7 @@ SI4713 FM RADIO TRANSMITTER PLATFORM DRIVER
 M:     Eduardo Valentin <edubezval@gmail.com>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Odd Fixes
 F:     drivers/media/radio/si4713/radio-platform-si4713.c
 
@@ -9688,14 +9680,14 @@ SI4713 FM RADIO TRANSMITTER USB DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Maintained
 F:     drivers/media/radio/si4713/radio-usb-si4713.c
 
 SIANO DVB DRIVER
 M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Odd fixes
 F:     drivers/media/common/siano/
@@ -9720,7 +9712,7 @@ SH_VOU V4L2 OUTPUT DRIVER
 L:     linux-media@vger.kernel.org
 S:     Orphan
 F:     drivers/media/platform/sh_vou.c
-F:     include/media/sh_vou.h
+F:     include/media/drv-intf/sh_vou.h
 
 SIMPLE FIRMWARE INTERFACE (SFI)
 M:     Len Brown <lenb@kernel.org>
@@ -9761,7 +9753,7 @@ F:        drivers/i2c/busses/i2c-davinci.c
 TI DAVINCI SERIES MEDIA DRIVER
 M:     "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
 S:     Maintained
@@ -9771,7 +9763,7 @@ F:        include/media/davinci/
 TI AM437X VPFE DRIVER
 M:     "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
 S:     Maintained
@@ -9780,12 +9772,12 @@ F:      drivers/media/platform/am437x/
 OV2659 OMNIVISION SENSOR DRIVER
 M:     "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
 S:     Maintained
 F:     drivers/media/i2c/ov2659.c
-F:     include/media/ov2659.h
+F:     include/media/i2c/ov2659.h
 
 SILICON MOTION SM712 FRAME BUFFER DRIVER
 M:     Sudip Mukherjee <sudipm.mukherjee@gmail.com>
@@ -9874,7 +9866,7 @@ M:        Sakari Ailus <sakari.ailus@iki.fi>
 L:     linux-media@vger.kernel.org
 S:     Maintained
 F:     drivers/media/i2c/smiapp/
-F:     include/media/smiapp.h
+F:     include/media/i2c/smiapp.h
 F:     drivers/media/i2c/smiapp-pll.c
 F:     drivers/media/i2c/smiapp-pll.h
 F:     include/uapi/linux/smiapp.h
@@ -10038,7 +10030,7 @@ F:      sound/soc/soc-generic-dmaengine-pcm.c
 SP2 MEDIA DRIVER
 M:     Olli Salonen <olli.salonen@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 S:     Maintained
 F:     drivers/media/dvb-frontends/sp2*
@@ -10400,7 +10392,7 @@ F:      net/ipv4/tcp_lp.c
 TDA10071 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -10410,7 +10402,7 @@ F:      drivers/media/dvb-frontends/tda10071*
 TDA18212 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -10420,7 +10412,7 @@ F:      drivers/media/tuners/tda18212*
 TDA18218 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -10430,7 +10422,7 @@ F:      drivers/media/tuners/tda18218*
 TDA18271 MEDIA DRIVER
 M:     Michael Krufky <mkrufky@linuxtv.org>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 W:     http://github.com/mkrufky
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/mkrufky/tuners.git
@@ -10440,7 +10432,7 @@ F:      drivers/media/tuners/tda18271*
 TDA827x MEDIA DRIVER
 M:     Michael Krufky <mkrufky@linuxtv.org>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 W:     http://github.com/mkrufky
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/mkrufky/tuners.git
@@ -10450,7 +10442,7 @@ F:      drivers/media/tuners/tda8290.*
 TDA8290 MEDIA DRIVER
 M:     Michael Krufky <mkrufky@linuxtv.org>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
+W:     https://linuxtv.org
 W:     http://github.com/mkrufky
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/mkrufky/tuners.git
@@ -10461,14 +10453,14 @@ TDA9840 MEDIA DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Maintained
 F:     drivers/media/i2c/tda9840*
 
 TEA5761 TUNER DRIVER
 M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Odd fixes
 F:     drivers/media/tuners/tea5761.*
@@ -10476,7 +10468,7 @@ F:      drivers/media/tuners/tea5761.*
 TEA5767 TUNER DRIVER
 M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
 F:     drivers/media/tuners/tea5767.*
@@ -10485,7 +10477,7 @@ TEA6415C MEDIA DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Maintained
 F:     drivers/media/i2c/tea6415c*
 
@@ -10493,7 +10485,7 @@ TEA6420 MEDIA DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Maintained
 F:     drivers/media/i2c/tea6420*
 
@@ -10591,7 +10583,7 @@ THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Maintained
 F:     drivers/media/radio/radio-raremono.c
 
@@ -10815,7 +10807,7 @@ M:      Mats Randgaard <matrandg@cisco.com>
 L:     linux-media@vger.kernel.org
 S:     Maintained
 F:     drivers/media/i2c/tc358743*
-F:     include/media/tc358743.h
+F:     include/media/i2c/tc358743.h
 
 TMIO MMC DRIVER
 M:     Ian Molton <ian@mnementh.co.uk>
@@ -10843,7 +10835,7 @@ F:      mm/shmem.c
 TM6000 VIDEO4LINUX DRIVER
 M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Odd fixes
 F:     drivers/media/usb/tm6000/
@@ -10852,7 +10844,7 @@ TW68 VIDEO4LINUX DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Odd Fixes
 F:     drivers/media/pci/tw68/
 
@@ -10913,7 +10905,7 @@ F:      include/uapi/linux/tty.h
 TUA9001 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.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
@@ -11260,7 +11252,7 @@ USB VISION DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Odd Fixes
 F:     drivers/media/usb/usbvision/
 
@@ -11474,7 +11466,7 @@ VIVID VIRTUAL VIDEO DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 S:     Maintained
 F:     drivers/media/platform/vivid/*
 
@@ -11763,7 +11755,7 @@ F:      arch/x86/entry/vdso/
 XC2028/3028 TUNER DRIVER
 M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org
+W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
 F:     drivers/media/tuners/tuner-xc2028.*
@@ -11932,7 +11924,7 @@ ZR36067 VIDEO FOR LINUX DRIVER
 L:     mjpeg-users@lists.sourceforge.net
 L:     linux-media@vger.kernel.org
 W:     http://mjpeg.sourceforge.net/driver-zoran/
-T:     hg http://linuxtv.org/hg/v4l-dvb
+T:     hg https://linuxtv.org/hg/v4l-dvb
 S:     Odd Fixes
 F:     drivers/media/pci/zoran/
 
index 1122433a5cd54566578e3d71d3ad357fe52064f3..70dea02f1346d4fa8253fb4d22aac60c7718e0c7 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 4
 PATCHLEVEL = 4
 SUBLEVEL = 0
-EXTRAVERSION = -rc7
+EXTRAVERSION =
 NAME = Blurry Fish Butt
 
 # *DOCUMENTATION*
index 34e1569a11ee322a0a020bdfe0c9b801b6b58c12..426115f7cb6327348b85bb6667bff99dbf0249f6 100644 (file)
@@ -20,6 +20,7 @@ config ARM
        select GENERIC_ALLOCATOR
        select GENERIC_ATOMIC64 if (CPU_V7M || CPU_V6 || !CPU_32v6K || !AEABI)
        select GENERIC_CLOCKEVENTS_BROADCAST if SMP
+       select GENERIC_EARLY_IOREMAP
        select GENERIC_IDLE_POLL_SETUP
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
@@ -33,10 +34,11 @@ config ARM
        select HARDIRQS_SW_RESEND
        select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT)
        select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6
-       select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32
-       select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32
+       select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU
+       select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32 && MMU
        select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT)
        select HAVE_ARCH_TRACEHOOK
+       select HAVE_ARM_SMCCC if CPU_V7
        select HAVE_BPF_JIT
        select HAVE_CC_STACKPROTECTOR
        select HAVE_CONTEXT_TRACKING
@@ -45,7 +47,7 @@ config ARM
        select HAVE_DMA_API_DEBUG
        select HAVE_DMA_ATTRS
        select HAVE_DMA_CONTIGUOUS if MMU
-       select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL) && !CPU_ENDIAN_BE32
+       select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL) && !CPU_ENDIAN_BE32 && MMU
        select HAVE_EFFICIENT_UNALIGNED_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && MMU
        select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL)
        select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL)
@@ -611,6 +613,7 @@ config ARCH_PXA
        select AUTO_ZRELADDR
        select COMMON_CLK
        select CLKDEV_LOOKUP
+       select CLKSRC_PXA
        select CLKSRC_MMIO
        select CLKSRC_OF
        select GENERIC_CLOCKEVENTS
@@ -650,6 +653,8 @@ config ARCH_SA1100
        select ARCH_SPARSEMEM_ENABLE
        select CLKDEV_LOOKUP
        select CLKSRC_MMIO
+       select CLKSRC_PXA
+       select CLKSRC_OF if OF
        select CPU_FREQ
        select CPU_SA1100
        select GENERIC_CLOCKEVENTS
@@ -799,6 +804,7 @@ config ARCH_VIRT
        bool "Dummy Virtual Machine" if ARCH_MULTI_V7
        select ARM_AMBA
        select ARM_GIC
+       select ARM_GIC_V2M if PCI_MSI
        select ARM_GIC_V3
        select ARM_PSCI
        select HAVE_ARM_ARCH_TIMER
@@ -1422,7 +1428,7 @@ config BIG_LITTLE
 
 config BL_SWITCHER
        bool "big.LITTLE switcher support"
-       depends on BIG_LITTLE && MCPM && HOTPLUG_CPU
+       depends on BIG_LITTLE && MCPM && HOTPLUG_CPU && ARM_GIC
        select ARM_CPU_SUSPEND
        select CPU_PM
        help
@@ -1481,7 +1487,7 @@ config HOTPLUG_CPU
 
 config ARM_PSCI
        bool "Support for the ARM Power State Coordination Interface (PSCI)"
-       depends on CPU_V7
+       depends on HAVE_ARM_SMCCC
        select ARM_PSCI_FW
        help
          Say Y here if you want Linux to communicate with system firmware
@@ -1604,6 +1610,24 @@ config THUMB2_AVOID_R_ARM_THM_JUMP11
 config ARM_ASM_UNIFIED
        bool
 
+config ARM_PATCH_IDIV
+       bool "Runtime patch udiv/sdiv instructions into __aeabi_{u}idiv()"
+       depends on CPU_32v7 && !XIP_KERNEL
+       default y
+       help
+         The ARM compiler inserts calls to __aeabi_idiv() and
+         __aeabi_uidiv() when it needs to perform division on signed
+         and unsigned integers. Some v7 CPUs have support for the sdiv
+         and udiv instructions that can be used to implement those
+         functions.
+
+         Enabling this option allows the kernel to modify itself to
+         replace the first two instructions of these library functions
+         with the sdiv or udiv plus "bx lr" instructions when the CPU
+         it is running on supports them. Typically this will be faster
+         and less power intensive than running the original library
+         code to do integer division.
+
 config AEABI
        bool "Use the ARM EABI to compile the kernel"
        help
@@ -1800,6 +1824,25 @@ config SWIOTLB
 config IOMMU_HELPER
        def_bool SWIOTLB
 
+config PARAVIRT
+       bool "Enable paravirtualization code"
+       help
+         This changes the kernel so it can modify itself when it is run
+         under a hypervisor, potentially improving performance significantly
+         over full virtualization.
+
+config PARAVIRT_TIME_ACCOUNTING
+       bool "Paravirtual steal time accounting"
+       select PARAVIRT
+       default n
+       help
+         Select this option to enable fine granularity task steal time
+         accounting. Time spent executing other tasks in parallel with
+         the current vCPU is discounted from the vCPU power. To account for
+         that, there can be a small performance impact.
+
+         If in doubt, say N here.
+
 config XEN_DOM0
        def_bool y
        depends on XEN
@@ -1813,6 +1856,7 @@ config XEN
        select ARCH_DMA_ADDR_T_64BIT
        select ARM_PSCI
        select SWIOTLB_XEN
+       select PARAVIRT
        help
          Say Y if you want to run Linux in a Virtual Machine on Xen on ARM.
 
@@ -2040,6 +2084,25 @@ config AUTO_ZRELADDR
          0xf8000000. This assumes the zImage being placed in the first 128MB
          from start of memory.
 
+config EFI_STUB
+       bool
+
+config EFI
+       bool "UEFI runtime support"
+       depends on OF && !CPU_BIG_ENDIAN && MMU && AUTO_ZRELADDR && !XIP_KERNEL
+       select UCS2_STRING
+       select EFI_PARAMS_FROM_FDT
+       select EFI_STUB
+       select EFI_ARMSTUB
+       select EFI_RUNTIME_WRAPPERS
+       ---help---
+         This option provides support for runtime services provided
+         by UEFI firmware (such as non-volatile variables, realtime
+         clock, and platform reset). A UEFI stub is also provided to
+         allow the kernel to be booted as an EFI application. This
+         is only useful for kernels that may run on systems that have
+         UEFI firmware.
+
 endmenu
 
 menu "CPU Power Management"
index 3f9a9ebc77c389bbf794ee5a6840ceb0294b63f3..4c23a68a0917049e4c7e9e864dcebca38d6b75b2 100644 (file)
@@ -167,9 +167,11 @@ if [ $(words $(ZRELADDR)) -gt 1 -a "$(CONFIG_AUTO_ZRELADDR)" = "" ]; then \
        false; \
 fi
 
+efi-obj-$(CONFIG_EFI_STUB) := $(objtree)/drivers/firmware/efi/libstub/lib.a
+
 $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
                $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) \
-               $(bswapsdi2) FORCE
+               $(bswapsdi2) $(efi-obj-y) FORCE
        @$(check_for_multiple_zreladdr)
        $(call if_changed,ld)
        @$(check_for_bad_syms)
diff --git a/arch/arm/boot/compressed/efi-header.S b/arch/arm/boot/compressed/efi-header.S
new file mode 100644 (file)
index 0000000..9d5dc4f
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2013-2015 Linaro Ltd
+ * Authors: Roy Franz <roy.franz@linaro.org>
+ *          Ard Biesheuvel <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+               .macro  __nop
+#ifdef CONFIG_EFI_STUB
+               @ This is almost but not quite a NOP, since it does clobber the
+               @ condition flags. But it is the best we can do for EFI, since
+               @ PE/COFF expects the magic string "MZ" at offset 0, while the
+               @ ARM/Linux boot protocol expects an executable instruction
+               @ there.
+               .inst   'M' | ('Z' << 8) | (0x1310 << 16)   @ tstne r0, #0x4d000
+#else
+               mov     r0, r0
+#endif
+               .endm
+
+               .macro  __EFI_HEADER
+#ifdef CONFIG_EFI_STUB
+               b       __efi_start
+
+               .set    start_offset, __efi_start - start
+               .org    start + 0x3c
+               @
+               @ The PE header can be anywhere in the file, but for
+               @ simplicity we keep it together with the MSDOS header
+               @ The offset to the PE/COFF header needs to be at offset
+               @ 0x3C in the MSDOS header.
+               @ The only 2 fields of the MSDOS header that are used are this
+               @ PE/COFF offset, and the "MZ" bytes at offset 0x0.
+               @
+               .long   pe_header - start       @ Offset to the PE header.
+
+pe_header:
+               .ascii  "PE\0\0"
+
+coff_header:
+               .short  0x01c2                  @ ARM or Thumb
+               .short  2                       @ nr_sections
+               .long   0                       @ TimeDateStamp
+               .long   0                       @ PointerToSymbolTable
+               .long   1                       @ NumberOfSymbols
+               .short  section_table - optional_header
+                                               @ SizeOfOptionalHeader
+               .short  0x306                   @ Characteristics.
+                                               @ IMAGE_FILE_32BIT_MACHINE |
+                                               @ IMAGE_FILE_DEBUG_STRIPPED |
+                                               @ IMAGE_FILE_EXECUTABLE_IMAGE |
+                                               @ IMAGE_FILE_LINE_NUMS_STRIPPED
+
+optional_header:
+               .short  0x10b                   @ PE32 format
+               .byte   0x02                    @ MajorLinkerVersion
+               .byte   0x14                    @ MinorLinkerVersion
+               .long   _end - __efi_start      @ SizeOfCode
+               .long   0                       @ SizeOfInitializedData
+               .long   0                       @ SizeOfUninitializedData
+               .long   efi_stub_entry - start  @ AddressOfEntryPoint
+               .long   start_offset            @ BaseOfCode
+               .long   0                       @ data
+
+extra_header_fields:
+               .long   0                       @ ImageBase
+               .long   0x200                   @ SectionAlignment
+               .long   0x200                   @ FileAlignment
+               .short  0                       @ MajorOperatingSystemVersion
+               .short  0                       @ MinorOperatingSystemVersion
+               .short  0                       @ MajorImageVersion
+               .short  0                       @ MinorImageVersion
+               .short  0                       @ MajorSubsystemVersion
+               .short  0                       @ MinorSubsystemVersion
+               .long   0                       @ Win32VersionValue
+
+               .long   _end - start            @ SizeOfImage
+               .long   start_offset            @ SizeOfHeaders
+               .long   0                       @ CheckSum
+               .short  0xa                     @ Subsystem (EFI application)
+               .short  0                       @ DllCharacteristics
+               .long   0                       @ SizeOfStackReserve
+               .long   0                       @ SizeOfStackCommit
+               .long   0                       @ SizeOfHeapReserve
+               .long   0                       @ SizeOfHeapCommit
+               .long   0                       @ LoaderFlags
+               .long   0x6                     @ NumberOfRvaAndSizes
+
+               .quad   0                       @ ExportTable
+               .quad   0                       @ ImportTable
+               .quad   0                       @ ResourceTable
+               .quad   0                       @ ExceptionTable
+               .quad   0                       @ CertificationTable
+               .quad   0                       @ BaseRelocationTable
+
+section_table:
+               @
+               @ The EFI application loader requires a relocation section
+               @ because EFI applications must be relocatable. This is a
+               @ dummy section as far as we are concerned.
+               @
+               .ascii  ".reloc\0\0"
+               .long   0                       @ VirtualSize
+               .long   0                       @ VirtualAddress
+               .long   0                       @ SizeOfRawData
+               .long   0                       @ PointerToRawData
+               .long   0                       @ PointerToRelocations
+               .long   0                       @ PointerToLineNumbers
+               .short  0                       @ NumberOfRelocations
+               .short  0                       @ NumberOfLineNumbers
+               .long   0x42100040              @ Characteristics
+
+               .ascii  ".text\0\0\0"
+               .long   _end - __efi_start      @ VirtualSize
+               .long   __efi_start             @ VirtualAddress
+               .long   _edata - __efi_start    @ SizeOfRawData
+               .long   __efi_start             @ PointerToRawData
+               .long   0                       @ PointerToRelocations
+               .long   0                       @ PointerToLineNumbers
+               .short  0                       @ NumberOfRelocations
+               .short  0                       @ NumberOfLineNumbers
+               .long   0xe0500020              @ Characteristics
+
+               .align  9
+__efi_start:
+#endif
+               .endm
index 06e983f59980ffc4c0955891d894bbbbaa5cb5e2..af11c2f8f3b7a63c350db162511c779617d70f61 100644 (file)
@@ -12,6 +12,8 @@
 #include <asm/assembler.h>
 #include <asm/v7m.h>
 
+#include "efi-header.S"
+
  AR_CLASS(     .arch   armv7-a )
  M_CLASS(      .arch   armv7-m )
 
 start:
                .type   start,#function
                .rept   7
-               mov     r0, r0
+               __nop
                .endr
    ARM(                mov     r0, r0          )
    ARM(                b       1f              )
@@ -139,7 +141,8 @@ start:
                .word   0x04030201      @ endianness flag
 
  THUMB(                .thumb                  )
-1:
+1:             __EFI_HEADER
+
  ARM_BE8(      setend  be              )       @ go BE8 if compiled for BE8
  AR_CLASS(     mrs     r9, cpsr        )
 #ifdef CONFIG_ARM_VIRT_EXT
@@ -1353,6 +1356,53 @@ __enter_kernel:
 
 reloc_code_end:
 
+#ifdef CONFIG_EFI_STUB
+               .align  2
+_start:                .long   start - .
+
+ENTRY(efi_stub_entry)
+               @ allocate space on stack for passing current zImage address
+               @ and for the EFI stub to return of new entry point of
+               @ zImage, as EFI stub may copy the kernel. Pointer address
+               @ is passed in r2. r0 and r1 are passed through from the
+               @ EFI firmware to efi_entry
+               adr     ip, _start
+               ldr     r3, [ip]
+               add     r3, r3, ip
+               stmfd   sp!, {r3, lr}
+               mov     r2, sp                  @ pass zImage address in r2
+               bl      efi_entry
+
+               @ Check for error return from EFI stub. r0 has FDT address
+               @ or error code.
+               cmn     r0, #1
+               beq     efi_load_fail
+
+               @ Preserve return value of efi_entry() in r4
+               mov     r4, r0
+               bl      cache_clean_flush
+               bl      cache_off
+
+               @ Set parameters for booting zImage according to boot protocol
+               @ put FDT address in r2, it was returned by efi_entry()
+               @ r1 is the machine type, and r0 needs to be 0
+               mov     r0, #0
+               mov     r1, #0xFFFFFFFF
+               mov     r2, r4
+
+               @ Branch to (possibly) relocated zImage that is in [sp]
+               ldr     lr, [sp]
+               ldr     ip, =start_offset
+               add     lr, lr, ip
+               mov     pc, lr                          @ no mode switch
+
+efi_load_fail:
+               @ Return EFI_LOAD_ERROR to EFI firmware on error.
+               ldr     r0, =0x80000001
+               ldmfd   sp!, {ip, pc}
+ENDPROC(efi_stub_entry)
+#endif
+
                .align
                .section ".stack", "aw", %nobits
 .L_user_stack: .space  4096
index 2b60b843ac5e9517f06e3e20190afa983fa7d21f..81c493156ce87e12a4719268076c861da18e7a53 100644 (file)
@@ -48,6 +48,13 @@ SECTIONS
     *(.rodata)
     *(.rodata.*)
   }
+  .data : {
+    /*
+     * The EFI stub always executes from RAM, and runs strictly before the
+     * decompressor, so we can make an exception for its r/w data, and keep it
+     */
+    *(.data.efistub)
+  }
   .piggydata : {
     *(.piggydata)
   }
index 314f59c121620868fae063a8c9fc13d323b5400b..d0c74385331803383d5296d7157516aa63c63758 100644 (file)
@@ -25,9 +25,9 @@
                cache-sets = <512>;
                cache-line-size = <32>;
                /* At full speed latency must be >=2 */
-               arm,tag-latency = <2>;
-               arm,data-latency = <2 2>;
-               arm,dirty-latency = <2>;
+               arm,tag-latency = <8>;
+               arm,data-latency = <8 8>;
+               arm,dirty-latency = <8>;
        };
 
        mtu0: mtu@101e2000 {
index ad21a4293a339c28446056b189e6c3059266c15c..133375bc8aa503d57f85a2b0026ff432b496a2d3 100644 (file)
@@ -6,6 +6,9 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <dt-bindings/clock/stih407-clks.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/media/c8sectpfe.h>
 / {
        soc {
                sbc_serial0: serial@9530000 {
                        status = "okay";
                };
 
-               i2c@9842000 {
+               ssc2: i2c@9842000 {
                        status = "okay";
+                       clock-frequency = <100000>;
+                       st,i2c-min-scl-pulse-width-us = <0>;
+                       st,i2c-min-sda-pulse-width-us = <5>;
                };
 
-               i2c@9843000 {
+               ssc3: i2c@9843000 {
                        status = "okay";
+                       clock-frequency = <100000>;
+                       st,i2c-min-scl-pulse-width-us = <0>;
+                       st,i2c-min-sda-pulse-width-us = <5>;
                };
 
                i2c@9844000 {
                        phy-mode = "rgmii";
                        fixed-link = <0 1 1000 0 0>;
                };
+
+               demux@08a20000 {
+                       compatible      = "st,stih407-c8sectpfe";
+                       status          = "okay";
+                       reg             = <0x08a20000 0x10000>,
+                                         <0x08a00000 0x4000>;
+                       reg-names       = "c8sectpfe", "c8sectpfe-ram";
+                       interrupts      = <GIC_SPI 34 IRQ_TYPE_NONE>,
+                                         <GIC_SPI 35 IRQ_TYPE_NONE>;
+                       interrupt-names = "c8sectpfe-error-irq",
+                                         "c8sectpfe-idle-irq";
+                       pinctrl-0       = <&pinctrl_tsin0_serial>;
+                       pinctrl-1       = <&pinctrl_tsin0_parallel>;
+                       pinctrl-2       = <&pinctrl_tsin3_serial>;
+                       pinctrl-3       = <&pinctrl_tsin4_serial_alt3>;
+                       pinctrl-4       = <&pinctrl_tsin5_serial_alt1>;
+                       pinctrl-names   = "tsin0-serial",
+                                         "tsin0-parallel",
+                                         "tsin3-serial",
+                                         "tsin4-serial",
+                                         "tsin5-serial";
+                       clocks          = <&clk_s_c0_flexgen CLK_PROC_STFE>;
+                       clock-names     = "c8sectpfe";
+
+                       /* tsin0 is TSA on NIMA */
+                       tsin0: port@0 {
+                               tsin-num        = <0>;
+                               serial-not-parallel;
+                               i2c-bus         = <&ssc2>;
+                               reset-gpios     = <&pio15 4 GPIO_ACTIVE_HIGH>;
+                               dvb-card        = <STV0367_TDA18212_NIMA_1>;
+                       };
+               };
        };
 };
index 01f40197ea13c4cc03691ef65a18c7ee20eb1990..3279bf1a17a123ac26448eaf4b9055884793eca4 100644 (file)
                        interrupt-parent = <&vic>;
                        interrupts = <31>; /* Cascaded to vic */
                        clear-mask = <0xffffffff>;
-                       valid-mask = <0xffc203f8>;
+                       /*
+                        * Valid interrupt lines mask according to
+                        * table 4-36 page 4-50 of ARM DUI 0225D
+                        */
+                       valid-mask = <0x0760031b>;
                };
 
                dma@10130000 {
                        };
                        mmc@5000 {
                                compatible = "arm,pl180", "arm,primecell";
-                               reg = < 0x5000 0x1000>;
-                               interrupts-extended = <&vic 22 &sic 2>;
+                               reg = <0x5000 0x1000>;
+                               interrupts-extended = <&vic 22 &sic 1>;
                                clocks = <&xtal24mhz>, <&pclk>;
                                clock-names = "mclk", "apb_pclk";
                        };
index b83137f66034016d2580dfaeaf63b162cc0ab5c4..33a8eb28374eaa8d3b8aca95d8801227bedd87ca 100644 (file)
@@ -5,6 +5,16 @@
        compatible = "arm,versatile-pb";
 
        amba {
+               /* The Versatile PB is using more SIC IRQ lines than the AB */
+               sic: intc@10003000 {
+                       clear-mask = <0xffffffff>;
+                       /*
+                        * Valid interrupt lines mask according to
+                        * figure 3-30 page 3-74 of ARM DUI 0224B
+                        */
+                       valid-mask = <0x7fe003ff>;
+               };
+
                gpio2: gpio@101e6000 {
                        compatible = "arm,pl061", "arm,primecell";
                        reg = <0x101e6000 0x1000>;
                };
 
                fpga {
+                       mmc@5000 {
+                               /*
+                                * Overrides the interrupt assignment from
+                                * the Versatile AB board file.
+                                */
+                               interrupts-extended = <&sic 22 &sic 23>;
+                       };
                        uart@9000 {
                                compatible = "arm,pl011", "arm,primecell";
                                reg = <0x9000 0x1000>;
                        mmc@b000 {
                                compatible = "arm,pl180", "arm,primecell";
                                reg = <0xb000 0x1000>;
-                               interrupts-extended = <&vic 23 &sic 2>;
+                               interrupt-parent = <&sic>;
+                               interrupts = <1>, <2>;
                                clocks = <&xtal24mhz>, <&pclk>;
                                clock-names = "mclk", "apb_pclk";
                        };
index b1c59a766a13381a693d897eb3349db4ac9d3c16..e12213d16693b890d0440e2da264a25b591e789a 100644 (file)
                        interrupts = <43>;
                };
 
+               sdhc@d800a000 {
+                       compatible = "wm,wm8505-sdhc";
+                       reg = <0xd800a000 0x400>;
+                       interrupts = <20>, <21>;
+                       clocks = <&clksdhc>;
+                       bus-width = <4>;
+                       sdon-inverted;
+               };
+
                fb: fb@d8050800 {
                        compatible = "wm,wm8505-fb";
                        reg = <0xd8050800 0x200>;
index 69a22fdb52a5a49ecb26760ed4163989e2f735e4..cd7b198fc79e220a1a082ada1889f919751a123f 100644 (file)
@@ -366,6 +366,7 @@ CONFIG_BATTERY_MAX17042=m
 CONFIG_CHARGER_MAX14577=m
 CONFIG_CHARGER_MAX77693=m
 CONFIG_CHARGER_TPS65090=y
+CONFIG_AXP20X_POWER=m
 CONFIG_POWER_RESET_AS3722=y
 CONFIG_POWER_RESET_GPIO=y
 CONFIG_POWER_RESET_GPIO_RESTART=y
index 3c36e16fcacf7d44f7e8ce76f32a2cbc20f2b1d4..b503a89441bf25ce5cda365a17cb7a172c28b4e2 100644 (file)
@@ -84,6 +84,7 @@ CONFIG_SPI_SUN4I=y
 CONFIG_SPI_SUN6I=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_POWER_SUPPLY=y
+CONFIG_AXP20X_POWER=y
 CONFIG_THERMAL=y
 CONFIG_CPU_THERMAL=y
 CONFIG_WATCHDOG=y
index bd425302c97a3ec9966d4c04bdb61c3c40252056..16da6380eb8505a9f9b87db77ac4b56c1febd8d9 100644 (file)
@@ -3,6 +3,7 @@
 generic-y += bitsperlong.h
 generic-y += cputime.h
 generic-y += current.h
+generic-y += early_ioremap.h
 generic-y += emergency-restart.h
 generic-y += errno.h
 generic-y += exec.h
index e7335a92144ef1d20d296ebdf26798148b2fa711..4e6e88a6b2f4ba36bcc3a0167b684a24cc58b7e9 100644 (file)
@@ -5,8 +5,6 @@
 #include <linux/types.h>
 #include <asm/opcodes.h>
 
-#ifdef CONFIG_BUG
-
 /*
  * Use a suitable undefined instruction to use for ARM/Thumb2 bug handling.
  * We need to be careful not to conflict with those used by other modules and
@@ -47,7 +45,7 @@ do {                                                          \
        unreachable();                                          \
 } while (0)
 
-#else  /* not CONFIG_DEBUG_BUGVERBOSE */
+#else
 
 #define __BUG(__file, __line, __value)                         \
 do {                                                           \
@@ -57,7 +55,6 @@ do {                                                          \
 #endif  /* CONFIG_DEBUG_BUGVERBOSE */
 
 #define HAVE_ARCH_BUG
-#endif  /* CONFIG_BUG */
 
 #include <asm-generic/bug.h>
 
index 0f842492490280b9d0b50fd1b25935a51b5a4c9d..3848259bebf85786d39d4212d74f2e1646b98a44 100644 (file)
@@ -30,7 +30,7 @@ static inline int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
 struct device_node;
 
 struct cpuidle_ops {
-       int (*suspend)(int cpu, unsigned long arg);
+       int (*suspend)(unsigned long arg);
        int (*init)(struct device_node *, int cpu);
 };
 
diff --git a/arch/arm/include/asm/efi.h b/arch/arm/include/asm/efi.h
new file mode 100644 (file)
index 0000000..e0eea72
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 Linaro Ltd <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARM_EFI_H
+#define __ASM_ARM_EFI_H
+
+#include <asm/cacheflush.h>
+#include <asm/cachetype.h>
+#include <asm/early_ioremap.h>
+#include <asm/fixmap.h>
+#include <asm/highmem.h>
+#include <asm/mach/map.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+
+#ifdef CONFIG_EFI
+void efi_init(void);
+
+int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
+
+#define efi_call_virt(f, ...)                                          \
+({                                                                     \
+       efi_##f##_t *__f;                                               \
+       efi_status_t __s;                                               \
+                                                                       \
+       efi_virtmap_load();                                             \
+       __f = efi.systab->runtime->f;                                   \
+       __s = __f(__VA_ARGS__);                                         \
+       efi_virtmap_unload();                                           \
+       __s;                                                            \
+})
+
+#define __efi_call_virt(f, ...)                                                \
+({                                                                     \
+       efi_##f##_t *__f;                                               \
+                                                                       \
+       efi_virtmap_load();                                             \
+       __f = efi.systab->runtime->f;                                   \
+       __f(__VA_ARGS__);                                               \
+       efi_virtmap_unload();                                           \
+})
+
+static inline void efi_set_pgd(struct mm_struct *mm)
+{
+       check_and_switch_context(mm, NULL);
+}
+
+void efi_virtmap_load(void);
+void efi_virtmap_unload(void);
+
+#else
+#define efi_init()
+#endif /* CONFIG_EFI */
+
+/* arch specific definitions used by the stub code */
+
+#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
+
+/*
+ * A reasonable upper bound for the uncompressed kernel size is 32 MBytes,
+ * so we will reserve that amount of memory. We have no easy way to tell what
+ * the actuall size of code + data the uncompressed kernel will use.
+ * If this is insufficient, the decompressor will relocate itself out of the
+ * way before performing the decompression.
+ */
+#define MAX_UNCOMP_KERNEL_SIZE SZ_32M
+
+/*
+ * The kernel zImage should preferably be located between 32 MB and 128 MB
+ * from the base of DRAM. The min address leaves space for a maximal size
+ * uncompressed image, and the max address is due to how the zImage decompressor
+ * picks a destination address.
+ */
+#define ZIMAGE_OFFSET_LIMIT    SZ_128M
+#define MIN_ZIMAGE_OFFSET      MAX_UNCOMP_KERNEL_SIZE
+#define MAX_FDT_OFFSET         ZIMAGE_OFFSET_LIMIT
+
+#endif /* _ASM_ARM_EFI_H */
index 58cfe9f1a687e6e1c8794f5ff5f37c6b4fcd7cb9..5c17d2dec777f627eaf6b706f92053065d5fa06b 100644 (file)
@@ -19,20 +19,47 @@ enum fixed_addresses {
        FIX_TEXT_POKE0,
        FIX_TEXT_POKE1,
 
-       __end_of_fixed_addresses
+       __end_of_fixmap_region,
+
+       /*
+        * Share the kmap() region with early_ioremap(): this is guaranteed
+        * not to clash since early_ioremap() is only available before
+        * paging_init(), and kmap() only after.
+        */
+#define NR_FIX_BTMAPS          32
+#define FIX_BTMAPS_SLOTS       7
+#define TOTAL_FIX_BTMAPS       (NR_FIX_BTMAPS * FIX_BTMAPS_SLOTS)
+
+       FIX_BTMAP_END = __end_of_permanent_fixed_addresses,
+       FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1,
+       __end_of_early_ioremap_region
 };
 
+static const enum fixed_addresses __end_of_fixed_addresses =
+       __end_of_fixmap_region > __end_of_early_ioremap_region ?
+       __end_of_fixmap_region : __end_of_early_ioremap_region;
+
 #define FIXMAP_PAGE_COMMON     (L_PTE_YOUNG | L_PTE_PRESENT | L_PTE_XN | L_PTE_DIRTY)
 
 #define FIXMAP_PAGE_NORMAL     (FIXMAP_PAGE_COMMON | L_PTE_MT_WRITEBACK)
+#define FIXMAP_PAGE_RO         (FIXMAP_PAGE_NORMAL | L_PTE_RDONLY)
 
 /* Used by set_fixmap_(io|nocache), both meant for mapping a device */
 #define FIXMAP_PAGE_IO         (FIXMAP_PAGE_COMMON | L_PTE_MT_DEV_SHARED | L_PTE_SHARED)
 #define FIXMAP_PAGE_NOCACHE    FIXMAP_PAGE_IO
 
+#define __early_set_fixmap     __set_fixmap
+
+#ifdef CONFIG_MMU
+
 void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot);
 void __init early_fixmap_init(void);
 
 #include <asm-generic/fixmap.h>
 
+#else
+
+static inline void early_fixmap_init(void) { }
+
+#endif
 #endif
index fe3ea776dc34267724f377465134e52b39434fed..3d7351c844aac0ae2392d441796ce9904dcaf717 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/threads.h>
 #include <asm/irq.h>
 
-#define NR_IPI 8
+#define NR_IPI 7
 
 typedef struct {
        unsigned int __softirq_pending;
index dc641ddf0784304434635080b5732ee215ab588f..e22089fb44dc86b7ed2fdb175bc6ec7b47ee4001 100644 (file)
@@ -19,6 +19,7 @@
 #ifndef __ARM_KVM_ARM_H__
 #define __ARM_KVM_ARM_H__
 
+#include <linux/const.h>
 #include <linux/types.h>
 
 /* Hyp Configuration Register (HCR) bits */
  * space.
  */
 #define KVM_PHYS_SHIFT (40)
-#define KVM_PHYS_SIZE  (1ULL << KVM_PHYS_SHIFT)
-#define KVM_PHYS_MASK  (KVM_PHYS_SIZE - 1ULL)
-#define PTRS_PER_S2_PGD        (1ULL << (KVM_PHYS_SHIFT - 30))
-#define S2_PGD_ORDER   get_order(PTRS_PER_S2_PGD * sizeof(pgd_t))
+#define KVM_PHYS_SIZE  (_AC(1, ULL) << KVM_PHYS_SHIFT)
+#define KVM_PHYS_MASK  (KVM_PHYS_SIZE - _AC(1, ULL))
+#define PTRS_PER_S2_PGD        (_AC(1, ULL) << (KVM_PHYS_SHIFT - 30))
 
 /* Virtualization Translation Control Register (VTCR) bits */
 #define VTCR_SH0       (3 << 12)
 #define VTTBR_X                (5 - KVM_T0SZ)
 #endif
 #define VTTBR_BADDR_SHIFT (VTTBR_X - 1)
-#define VTTBR_BADDR_MASK  (((1LLU << (40 - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT)
-#define VTTBR_VMID_SHIFT  (48LLU)
-#define VTTBR_VMID_MASK          (0xffLLU << VTTBR_VMID_SHIFT)
+#define VTTBR_BADDR_MASK  (((_AC(1, ULL) << (40 - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT)
+#define VTTBR_VMID_SHIFT  _AC(48, ULL)
+#define VTTBR_VMID_MASK(size)  (_AT(u64, (1 << size) - 1) << VTTBR_VMID_SHIFT)
 
 /* Hyp Syndrome Register (HSR) bits */
 #define HSR_EC_SHIFT   (26)
-#define HSR_EC         (0x3fU << HSR_EC_SHIFT)
-#define HSR_IL         (1U << 25)
+#define HSR_EC         (_AC(0x3f, UL) << HSR_EC_SHIFT)
+#define HSR_IL         (_AC(1, UL) << 25)
 #define HSR_ISS                (HSR_IL - 1)
 #define HSR_ISV_SHIFT  (24)
-#define HSR_ISV                (1U << HSR_ISV_SHIFT)
+#define HSR_ISV                (_AC(1, UL) << HSR_ISV_SHIFT)
 #define HSR_SRT_SHIFT  (16)
 #define HSR_SRT_MASK   (0xf << HSR_SRT_SHIFT)
 #define HSR_FSC                (0x3f)
 #define HSR_SSE                (1 << 21)
 #define HSR_WNR                (1 << 6)
 #define HSR_CV_SHIFT   (24)
-#define HSR_CV         (1U << HSR_CV_SHIFT)
+#define HSR_CV         (_AC(1, UL) << HSR_CV_SHIFT)
 #define HSR_COND_SHIFT (20)
-#define HSR_COND       (0xfU << HSR_COND_SHIFT)
+#define HSR_COND       (_AC(0xf, UL) << HSR_COND_SHIFT)
 
 #define FSC_FAULT      (0x04)
 #define FSC_ACCESS     (0x08)
 #define HSR_EC_DABT    (0x24)
 #define HSR_EC_DABT_HYP        (0x25)
 
-#define HSR_WFI_IS_WFE         (1U << 0)
+#define HSR_WFI_IS_WFE         (_AC(1, UL) << 0)
 
-#define HSR_HVC_IMM_MASK       ((1UL << 16) - 1)
+#define HSR_HVC_IMM_MASK       ((_AC(1, UL) << 16) - 1)
 
-#define HSR_DABT_S1PTW         (1U << 7)
-#define HSR_DABT_CM            (1U << 8)
-#define HSR_DABT_EA            (1U << 9)
+#define HSR_DABT_S1PTW         (_AC(1, UL) << 7)
+#define HSR_DABT_CM            (_AC(1, UL) << 8)
+#define HSR_DABT_EA            (_AC(1, UL) << 9)
 
 #define kvm_arm_exception_type \
        {0, "RESET" },          \
index 6692982c9b575db476bc12a37e2d69b27c00d9fb..f9f27792d8edc3d7a5f77b03ba72b0c051376f55 100644 (file)
@@ -150,6 +150,12 @@ struct kvm_vcpu_stat {
        u32 halt_successful_poll;
        u32 halt_attempted_poll;
        u32 halt_wakeup;
+       u32 hvc_exit_stat;
+       u64 wfe_exit_stat;
+       u64 wfi_exit_stat;
+       u64 mmio_exit_user;
+       u64 mmio_exit_kernel;
+       u64 exits;
 };
 
 int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init);
index 405aa18833073b88b52103363b54d534d9c69263..9203c21b4673fd8a73b5f5797ed5190305b363ae 100644 (file)
@@ -279,6 +279,11 @@ static inline void __kvm_extend_hypmap(pgd_t *boot_hyp_pgd,
                                       pgd_t *merged_hyp_pgd,
                                       unsigned long hyp_idmap_start) { }
 
+static inline unsigned int kvm_get_vmid_bits(void)
+{
+       return 8;
+}
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* __ARM_KVM_MMU_H__ */
index f98c7f32c9c8aefb256c7c7a287c6c2d69602011..9b7c328fb20778f9826ffbd953c10cda4cb37b6d 100644 (file)
@@ -42,6 +42,8 @@ enum {
 extern void iotable_init(struct map_desc *, int);
 extern void vm_reserve_area_early(unsigned long addr, unsigned long size,
                                  void *caller);
+extern void create_mapping_late(struct mm_struct *mm, struct map_desc *md,
+                               bool ng);
 
 #ifdef CONFIG_DEBUG_LL
 extern void debug_ll_addr(unsigned long *paddr, unsigned long *vaddr);
index 9b32f76bb0ddaa6d6e485d79cc9f2bdfeb24d776..432ce8176498e0a014b26689716454150278056c 100644 (file)
@@ -26,7 +26,7 @@ void __check_vmalloc_seq(struct mm_struct *mm);
 #ifdef CONFIG_CPU_HAS_ASID
 
 void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk);
-#define init_new_context(tsk,mm)       ({ atomic64_set(&mm->context.id, 0); 0; })
+#define init_new_context(tsk,mm)       ({ atomic64_set(&(mm)->context.id, 0); 0; })
 
 #ifdef CONFIG_ARM_ERRATA_798181
 void a15_erratum_get_cpumask(int this_cpu, struct mm_struct *mm,
diff --git a/arch/arm/include/asm/paravirt.h b/arch/arm/include/asm/paravirt.h
new file mode 100644 (file)
index 0000000..8435ff5
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _ASM_ARM_PARAVIRT_H
+#define _ASM_ARM_PARAVIRT_H
+
+#ifdef CONFIG_PARAVIRT
+struct static_key;
+extern struct static_key paravirt_steal_enabled;
+extern struct static_key paravirt_steal_rq_enabled;
+
+struct pv_time_ops {
+       unsigned long long (*steal_clock)(int cpu);
+};
+extern struct pv_time_ops pv_time_ops;
+
+static inline u64 paravirt_steal_clock(int cpu)
+{
+       return pv_time_ops.steal_clock(cpu);
+}
+#endif
+
+#endif
index 68ee3ce17b820e9c3cc6b77d0645cb68f6276988..b4c6d99364f179abe56849fa3ecc7bd82bb1ffcc 100644 (file)
@@ -16,7 +16,7 @@
 
 extern struct smp_operations psci_smp_ops;
 
-#ifdef CONFIG_ARM_PSCI
+#if defined(CONFIG_SMP) && defined(CONFIG_ARM_PSCI)
 bool psci_smp_available(void);
 #else
 static inline bool psci_smp_available(void) { return false; }
index e0adb9f1bf94a7f58d98835e8efd332604fd657f..3613d7e9fc40097afa2ab4cb44ae251a8438ccaa 100644 (file)
@@ -25,4 +25,10 @@ extern int arm_add_memory(u64 start, u64 size);
 extern void early_print(const char *str, ...);
 extern void dump_machine_table(void);
 
+#ifdef CONFIG_ATAGS_PROC
+extern void save_atags(const struct tag *tags);
+#else
+static inline void save_atags(const struct tag *tags) { }
+#endif
+
 #endif
index 712b50e0a6dc6901a5507ac89eeeeabdfefe4f19..d769972db8cbe49b232c3ac81ff10c8a958a5eee 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <xen/interface/xen.h>
 #include <xen/interface/sched.h>
+#include <xen/interface/platform.h>
 
 long privcmd_call(unsigned call, unsigned long a1,
                unsigned long a2, unsigned long a3,
@@ -49,6 +50,12 @@ int HYPERVISOR_memory_op(unsigned int cmd, void *arg);
 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_platform_op_raw(void *arg);
+static inline int HYPERVISOR_platform_op(struct xen_platform_op *op)
+{
+       op->interface_version = XENPF_INTERFACE_VERSION;
+       return HYPERVISOR_platform_op_raw(op);
+}
 int HYPERVISOR_multicall(struct multicall_entry *calls, uint32_t nr);
 
 static inline int
index 50066006e6bd3a961a580720911ab9c224f2fa36..75d5968628929b552b88107d279f988b3eda448e 100644 (file)
@@ -27,6 +27,8 @@
                (hnd).p = val;                          \
        } while (0)
 
+#define __HYPERVISOR_platform_op_raw __HYPERVISOR_platform_op
+
 #ifndef __ASSEMBLY__
 /* Explicitly size integers that represent pfns in the interface with
  * Xen so that we can have one ABI that works for 32 and 64 bit guests.
@@ -76,6 +78,7 @@ struct pvclock_wall_clock {
        u32   version;
        u32   sec;
        u32   nsec;
+       u32   sec_hi;
 } __attribute__((__packed__));
 #endif
 
index af9e59bf3831b9fd648d095c2070209b1e97677d..2c5f160be65e44cbabc2c5d01b023d56df0a1985 100644 (file)
@@ -73,14 +73,15 @@ obj-$(CONFIG_IWMMXT)                += iwmmxt.o
 obj-$(CONFIG_PERF_EVENTS)      += perf_regs.o perf_callchain.o
 obj-$(CONFIG_HW_PERF_EVENTS)   += perf_event_xscale.o perf_event_v6.o \
                                   perf_event_v7.o
-CFLAGS_pj4-cp0.o               := -marm
 AFLAGS_iwmmxt.o                        := -Wa,-mcpu=iwmmxt
 obj-$(CONFIG_ARM_CPU_TOPOLOGY)  += topology.o
 obj-$(CONFIG_VDSO)             += vdso.o
+obj-$(CONFIG_EFI)              += efi.o
 
 ifneq ($(CONFIG_ARCH_EBSA110),y)
   obj-y                += io.o
 endif
+obj-$(CONFIG_PARAVIRT) += paravirt.o
 
 head-y                 := head$(MMUEXT).o
 obj-$(CONFIG_DEBUG_LL) += debug.o
@@ -88,8 +89,9 @@ obj-$(CONFIG_EARLY_PRINTK)    += early_printk.o
 
 obj-$(CONFIG_ARM_VIRT_EXT)     += hyp-stub.o
 ifeq ($(CONFIG_ARM_PSCI),y)
-obj-y                          += psci-call.o
 obj-$(CONFIG_SMP)              += psci_smp.o
 endif
 
+obj-$(CONFIG_HAVE_ARM_SMCCC)   += smccc-call.o
+
 extra-y := $(head-y) vmlinux.lds
index f89811fb9a55f3a490c3633ef99ef52745c58129..7e45f69a0ddc9d0ef3b04c145195cf1b4ad7d84b 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/syscalls.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
+#include <linux/arm-smccc.h>
 
 #include <asm/checksum.h>
 #include <asm/ftrace.h>
@@ -175,3 +176,8 @@ EXPORT_SYMBOL(__gnu_mcount_nc);
 EXPORT_SYMBOL(__pv_phys_pfn_offset);
 EXPORT_SYMBOL(__pv_offset);
 #endif
+
+#ifdef CONFIG_HAVE_ARM_SMCCC
+EXPORT_SYMBOL(arm_smccc_smc);
+EXPORT_SYMBOL(arm_smccc_hvc);
+#endif
index ec4164da6e3018737c42022bef16b3ed6bcea350..edfa2268c12779dc86ae2513e6ff36a37ad7e0ff 100644 (file)
@@ -1,9 +1,3 @@
-#ifdef CONFIG_ATAGS_PROC
-extern void save_atags(struct tag *tags);
-#else
-static inline void save_atags(struct tag *tags) { }
-#endif
-
 void convert_to_tag_list(struct tag *tags);
 
 #ifdef CONFIG_ATAGS
index 318da33465f413f8c207eb2dd9b3766e53ab5ad3..703926e7007b4e0000b689006722780a02588e04 100644 (file)
@@ -56,7 +56,7 @@ int arm_cpuidle_suspend(int index)
        int cpu = smp_processor_id();
 
        if (cpuidle_ops[cpu].suspend)
-               ret = cpuidle_ops[cpu].suspend(cpu, index);
+               ret = cpuidle_ops[cpu].suspend(index);
 
        return ret;
 }
diff --git a/arch/arm/kernel/efi.c b/arch/arm/kernel/efi.c
new file mode 100644 (file)
index 0000000..ff8a9d8
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 Linaro Ltd <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/efi.h>
+#include <asm/efi.h>
+#include <asm/mach/map.h>
+#include <asm/mmu_context.h>
+
+int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
+{
+       struct map_desc desc = {
+               .virtual        = md->virt_addr,
+               .pfn            = __phys_to_pfn(md->phys_addr),
+               .length         = md->num_pages * EFI_PAGE_SIZE,
+       };
+
+       /*
+        * Order is important here: memory regions may have all of the
+        * bits below set (and usually do), so we check them in order of
+        * preference.
+        */
+       if (md->attribute & EFI_MEMORY_WB)
+               desc.type = MT_MEMORY_RWX;
+       else if (md->attribute & EFI_MEMORY_WT)
+               desc.type = MT_MEMORY_RWX_NONCACHED;
+       else if (md->attribute & EFI_MEMORY_WC)
+               desc.type = MT_DEVICE_WC;
+       else
+               desc.type = MT_DEVICE;
+
+       create_mapping_late(mm, &desc, true);
+       return 0;
+}
index b6c8bb9315e7bb6c15b9eb015ad9627fe545fdcb..907534f97053abbc32b667ff43df88dc93c08fb7 100644 (file)
@@ -88,7 +88,7 @@ __pendsv_entry:
        @ execute the pending work, including reschedule
        get_thread_info tsk
        mov     why, #0
-       b       ret_to_user
+       b       ret_to_user_from_irq
 ENDPROC(__pendsv_entry)
 
 /*
diff --git a/arch/arm/kernel/paravirt.c b/arch/arm/kernel/paravirt.c
new file mode 100644 (file)
index 0000000..53f371e
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2013 Citrix Systems
+ *
+ * Author: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+ */
+
+#include <linux/export.h>
+#include <linux/jump_label.h>
+#include <linux/types.h>
+#include <asm/paravirt.h>
+
+struct static_key paravirt_steal_enabled;
+struct static_key paravirt_steal_rq_enabled;
+
+struct pv_time_ops pv_time_ops;
+EXPORT_SYMBOL_GPL(pv_time_ops);
index 126dc679b2308a2b846252bbde1e513389d71cdd..4152158f6e6a527eca033e0235ee5a54f0ab2d69 100644 (file)
  * but the encodings are considered to be `reserved' in the case that
  * they are not available.
  */
-enum armv7_perf_types {
-       ARMV7_PERFCTR_PMNC_SW_INCR                      = 0x00,
-       ARMV7_PERFCTR_L1_ICACHE_REFILL                  = 0x01,
-       ARMV7_PERFCTR_ITLB_REFILL                       = 0x02,
-       ARMV7_PERFCTR_L1_DCACHE_REFILL                  = 0x03,
-       ARMV7_PERFCTR_L1_DCACHE_ACCESS                  = 0x04,
-       ARMV7_PERFCTR_DTLB_REFILL                       = 0x05,
-       ARMV7_PERFCTR_MEM_READ                          = 0x06,
-       ARMV7_PERFCTR_MEM_WRITE                         = 0x07,
-       ARMV7_PERFCTR_INSTR_EXECUTED                    = 0x08,
-       ARMV7_PERFCTR_EXC_TAKEN                         = 0x09,
-       ARMV7_PERFCTR_EXC_EXECUTED                      = 0x0A,
-       ARMV7_PERFCTR_CID_WRITE                         = 0x0B,
+#define ARMV7_PERFCTR_PMNC_SW_INCR                     0x00
+#define ARMV7_PERFCTR_L1_ICACHE_REFILL                 0x01
+#define ARMV7_PERFCTR_ITLB_REFILL                      0x02
+#define ARMV7_PERFCTR_L1_DCACHE_REFILL                 0x03
+#define ARMV7_PERFCTR_L1_DCACHE_ACCESS                 0x04
+#define ARMV7_PERFCTR_DTLB_REFILL                      0x05
+#define ARMV7_PERFCTR_MEM_READ                         0x06
+#define ARMV7_PERFCTR_MEM_WRITE                                0x07
+#define ARMV7_PERFCTR_INSTR_EXECUTED                   0x08
+#define ARMV7_PERFCTR_EXC_TAKEN                                0x09
+#define ARMV7_PERFCTR_EXC_EXECUTED                     0x0A
+#define ARMV7_PERFCTR_CID_WRITE                                0x0B
 
-       /*
-        * ARMV7_PERFCTR_PC_WRITE is equivalent to HW_BRANCH_INSTRUCTIONS.
-        * It counts:
-        *  - all (taken) branch instructions,
-        *  - instructions that explicitly write the PC,
-        *  - exception generating instructions.
-        */
-       ARMV7_PERFCTR_PC_WRITE                          = 0x0C,
-       ARMV7_PERFCTR_PC_IMM_BRANCH                     = 0x0D,
-       ARMV7_PERFCTR_PC_PROC_RETURN                    = 0x0E,
-       ARMV7_PERFCTR_MEM_UNALIGNED_ACCESS              = 0x0F,
-       ARMV7_PERFCTR_PC_BRANCH_MIS_PRED                = 0x10,
-       ARMV7_PERFCTR_CLOCK_CYCLES                      = 0x11,
-       ARMV7_PERFCTR_PC_BRANCH_PRED                    = 0x12,
-
-       /* These events are defined by the PMUv2 supplement (ARM DDI 0457A). */
-       ARMV7_PERFCTR_MEM_ACCESS                        = 0x13,
-       ARMV7_PERFCTR_L1_ICACHE_ACCESS                  = 0x14,
-       ARMV7_PERFCTR_L1_DCACHE_WB                      = 0x15,
-       ARMV7_PERFCTR_L2_CACHE_ACCESS                   = 0x16,
-       ARMV7_PERFCTR_L2_CACHE_REFILL                   = 0x17,
-       ARMV7_PERFCTR_L2_CACHE_WB                       = 0x18,
-       ARMV7_PERFCTR_BUS_ACCESS                        = 0x19,
-       ARMV7_PERFCTR_MEM_ERROR                         = 0x1A,
-       ARMV7_PERFCTR_INSTR_SPEC                        = 0x1B,
-       ARMV7_PERFCTR_TTBR_WRITE                        = 0x1C,
-       ARMV7_PERFCTR_BUS_CYCLES                        = 0x1D,
-
-       ARMV7_PERFCTR_CPU_CYCLES                        = 0xFF
-};
+/*
+ * ARMV7_PERFCTR_PC_WRITE is equivalent to HW_BRANCH_INSTRUCTIONS.
+ * It counts:
+ *  - all (taken) branch instructions,
+ *  - instructions that explicitly write the PC,
+ *  - exception generating instructions.
+ */
+#define ARMV7_PERFCTR_PC_WRITE                         0x0C
+#define ARMV7_PERFCTR_PC_IMM_BRANCH                    0x0D
+#define ARMV7_PERFCTR_PC_PROC_RETURN                   0x0E
+#define ARMV7_PERFCTR_MEM_UNALIGNED_ACCESS             0x0F
+#define ARMV7_PERFCTR_PC_BRANCH_MIS_PRED               0x10
+#define ARMV7_PERFCTR_CLOCK_CYCLES                     0x11
+#define ARMV7_PERFCTR_PC_BRANCH_PRED                   0x12
+
+/* These events are defined by the PMUv2 supplement (ARM DDI 0457A). */
+#define ARMV7_PERFCTR_MEM_ACCESS                       0x13
+#define ARMV7_PERFCTR_L1_ICACHE_ACCESS                 0x14
+#define ARMV7_PERFCTR_L1_DCACHE_WB                     0x15
+#define ARMV7_PERFCTR_L2_CACHE_ACCESS                  0x16
+#define ARMV7_PERFCTR_L2_CACHE_REFILL                  0x17
+#define ARMV7_PERFCTR_L2_CACHE_WB                      0x18
+#define ARMV7_PERFCTR_BUS_ACCESS                       0x19
+#define ARMV7_PERFCTR_MEM_ERROR                                0x1A
+#define ARMV7_PERFCTR_INSTR_SPEC                       0x1B
+#define ARMV7_PERFCTR_TTBR_WRITE                       0x1C
+#define ARMV7_PERFCTR_BUS_CYCLES                       0x1D
+
+#define ARMV7_PERFCTR_CPU_CYCLES                       0xFF
 
 /* ARMv7 Cortex-A8 specific event types */
-enum armv7_a8_perf_types {
-       ARMV7_A8_PERFCTR_L2_CACHE_ACCESS                = 0x43,
-       ARMV7_A8_PERFCTR_L2_CACHE_REFILL                = 0x44,
-       ARMV7_A8_PERFCTR_L1_ICACHE_ACCESS               = 0x50,
-       ARMV7_A8_PERFCTR_STALL_ISIDE                    = 0x56,
-};
+#define ARMV7_A8_PERFCTR_L2_CACHE_ACCESS               0x43
+#define ARMV7_A8_PERFCTR_L2_CACHE_REFILL               0x44
+#define ARMV7_A8_PERFCTR_L1_ICACHE_ACCESS              0x50
+#define ARMV7_A8_PERFCTR_STALL_ISIDE                   0x56
 
 /* ARMv7 Cortex-A9 specific event types */
-enum armv7_a9_perf_types {
-       ARMV7_A9_PERFCTR_INSTR_CORE_RENAME              = 0x68,
-       ARMV7_A9_PERFCTR_STALL_ICACHE                   = 0x60,
-       ARMV7_A9_PERFCTR_STALL_DISPATCH                 = 0x66,
-};
+#define ARMV7_A9_PERFCTR_INSTR_CORE_RENAME             0x68
+#define ARMV7_A9_PERFCTR_STALL_ICACHE                  0x60
+#define ARMV7_A9_PERFCTR_STALL_DISPATCH                        0x66
 
 /* ARMv7 Cortex-A5 specific event types */
-enum armv7_a5_perf_types {
-       ARMV7_A5_PERFCTR_PREFETCH_LINEFILL              = 0xc2,
-       ARMV7_A5_PERFCTR_PREFETCH_LINEFILL_DROP         = 0xc3,
-};
+#define ARMV7_A5_PERFCTR_PREFETCH_LINEFILL             0xc2
+#define ARMV7_A5_PERFCTR_PREFETCH_LINEFILL_DROP                0xc3
 
 /* ARMv7 Cortex-A15 specific event types */
-enum armv7_a15_perf_types {
-       ARMV7_A15_PERFCTR_L1_DCACHE_ACCESS_READ         = 0x40,
-       ARMV7_A15_PERFCTR_L1_DCACHE_ACCESS_WRITE        = 0x41,
-       ARMV7_A15_PERFCTR_L1_DCACHE_REFILL_READ         = 0x42,
-       ARMV7_A15_PERFCTR_L1_DCACHE_REFILL_WRITE        = 0x43,
+#define ARMV7_A15_PERFCTR_L1_DCACHE_ACCESS_READ                0x40
+#define ARMV7_A15_PERFCTR_L1_DCACHE_ACCESS_WRITE       0x41
+#define ARMV7_A15_PERFCTR_L1_DCACHE_REFILL_READ                0x42
+#define ARMV7_A15_PERFCTR_L1_DCACHE_REFILL_WRITE       0x43
 
-       ARMV7_A15_PERFCTR_DTLB_REFILL_L1_READ           = 0x4C,
-       ARMV7_A15_PERFCTR_DTLB_REFILL_L1_WRITE          = 0x4D,
+#define ARMV7_A15_PERFCTR_DTLB_REFILL_L1_READ          0x4C
+#define ARMV7_A15_PERFCTR_DTLB_REFILL_L1_WRITE         0x4D
 
-       ARMV7_A15_PERFCTR_L2_CACHE_ACCESS_READ          = 0x50,
-       ARMV7_A15_PERFCTR_L2_CACHE_ACCESS_WRITE         = 0x51,
-       ARMV7_A15_PERFCTR_L2_CACHE_REFILL_READ          = 0x52,
-       ARMV7_A15_PERFCTR_L2_CACHE_REFILL_WRITE         = 0x53,
+#define ARMV7_A15_PERFCTR_L2_CACHE_ACCESS_READ         0x50
+#define ARMV7_A15_PERFCTR_L2_CACHE_ACCESS_WRITE                0x51
+#define ARMV7_A15_PERFCTR_L2_CACHE_REFILL_READ         0x52
+#define ARMV7_A15_PERFCTR_L2_CACHE_REFILL_WRITE                0x53
 
-       ARMV7_A15_PERFCTR_PC_WRITE_SPEC                 = 0x76,
-};
+#define ARMV7_A15_PERFCTR_PC_WRITE_SPEC                        0x76
 
 /* ARMv7 Cortex-A12 specific event types */
-enum armv7_a12_perf_types {
-       ARMV7_A12_PERFCTR_L1_DCACHE_ACCESS_READ         = 0x40,
-       ARMV7_A12_PERFCTR_L1_DCACHE_ACCESS_WRITE        = 0x41,
+#define ARMV7_A12_PERFCTR_L1_DCACHE_ACCESS_READ                0x40
+#define ARMV7_A12_PERFCTR_L1_DCACHE_ACCESS_WRITE       0x41
 
-       ARMV7_A12_PERFCTR_L2_CACHE_ACCESS_READ          = 0x50,
-       ARMV7_A12_PERFCTR_L2_CACHE_ACCESS_WRITE         = 0x51,
+#define ARMV7_A12_PERFCTR_L2_CACHE_ACCESS_READ         0x50
+#define ARMV7_A12_PERFCTR_L2_CACHE_ACCESS_WRITE                0x51
 
-       ARMV7_A12_PERFCTR_PC_WRITE_SPEC                 = 0x76,
+#define ARMV7_A12_PERFCTR_PC_WRITE_SPEC                        0x76
 
-       ARMV7_A12_PERFCTR_PF_TLB_REFILL                 = 0xe7,
-};
+#define ARMV7_A12_PERFCTR_PF_TLB_REFILL                        0xe7
 
 /* ARMv7 Krait specific event types */
-enum krait_perf_types {
-       KRAIT_PMRESR0_GROUP0                            = 0xcc,
-       KRAIT_PMRESR1_GROUP0                            = 0xd0,
-       KRAIT_PMRESR2_GROUP0                            = 0xd4,
-       KRAIT_VPMRESR0_GROUP0                           = 0xd8,
+#define KRAIT_PMRESR0_GROUP0                           0xcc
+#define KRAIT_PMRESR1_GROUP0                           0xd0
+#define KRAIT_PMRESR2_GROUP0                           0xd4
+#define KRAIT_VPMRESR0_GROUP0                          0xd8
 
-       KRAIT_PERFCTR_L1_ICACHE_ACCESS                  = 0x10011,
-       KRAIT_PERFCTR_L1_ICACHE_MISS                    = 0x10010,
+#define KRAIT_PERFCTR_L1_ICACHE_ACCESS                 0x10011
+#define KRAIT_PERFCTR_L1_ICACHE_MISS                   0x10010
 
-       KRAIT_PERFCTR_L1_ITLB_ACCESS                    = 0x12222,
-       KRAIT_PERFCTR_L1_DTLB_ACCESS                    = 0x12210,
-};
+#define KRAIT_PERFCTR_L1_ITLB_ACCESS                   0x12222
+#define KRAIT_PERFCTR_L1_DTLB_ACCESS                   0x12210
 
 /* ARMv7 Scorpion specific event types */
-enum scorpion_perf_types {
-       SCORPION_LPM0_GROUP0                            = 0x4c,
-       SCORPION_LPM1_GROUP0                            = 0x50,
-       SCORPION_LPM2_GROUP0                            = 0x54,
-       SCORPION_L2LPM_GROUP0                           = 0x58,
-       SCORPION_VLPM_GROUP0                            = 0x5c,
+#define SCORPION_LPM0_GROUP0                           0x4c
+#define SCORPION_LPM1_GROUP0                           0x50
+#define SCORPION_LPM2_GROUP0                           0x54
+#define SCORPION_L2LPM_GROUP0                          0x58
+#define SCORPION_VLPM_GROUP0                           0x5c
 
-       SCORPION_ICACHE_ACCESS                          = 0x10053,
-       SCORPION_ICACHE_MISS                            = 0x10052,
+#define SCORPION_ICACHE_ACCESS                         0x10053
+#define SCORPION_ICACHE_MISS                           0x10052
 
-       SCORPION_DTLB_ACCESS                            = 0x12013,
-       SCORPION_DTLB_MISS                              = 0x12012,
+#define SCORPION_DTLB_ACCESS                           0x12013
+#define SCORPION_DTLB_MISS                             0x12012
 
-       SCORPION_ITLB_MISS                              = 0x12021,
-};
+#define SCORPION_ITLB_MISS                             0x12021
 
 /*
  * Cortex-A8 HW events mapping
@@ -547,6 +531,134 @@ static const unsigned scorpion_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
        [C(BPU)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
 };
 
+PMU_FORMAT_ATTR(event, "config:0-7");
+
+static struct attribute *armv7_pmu_format_attrs[] = {
+       &format_attr_event.attr,
+       NULL,
+};
+
+static struct attribute_group armv7_pmu_format_attr_group = {
+       .name = "format",
+       .attrs = armv7_pmu_format_attrs,
+};
+
+#define ARMV7_EVENT_ATTR_RESOLVE(m) #m
+#define ARMV7_EVENT_ATTR(name, config) \
+       PMU_EVENT_ATTR_STRING(name, armv7_event_attr_##name, \
+                             "event=" ARMV7_EVENT_ATTR_RESOLVE(config))
+
+ARMV7_EVENT_ATTR(sw_incr, ARMV7_PERFCTR_PMNC_SW_INCR);
+ARMV7_EVENT_ATTR(l1i_cache_refill, ARMV7_PERFCTR_L1_ICACHE_REFILL);
+ARMV7_EVENT_ATTR(l1i_tlb_refill, ARMV7_PERFCTR_ITLB_REFILL);
+ARMV7_EVENT_ATTR(l1d_cache_refill, ARMV7_PERFCTR_L1_DCACHE_REFILL);
+ARMV7_EVENT_ATTR(l1d_cache, ARMV7_PERFCTR_L1_DCACHE_ACCESS);
+ARMV7_EVENT_ATTR(l1d_tlb_refill, ARMV7_PERFCTR_DTLB_REFILL);
+ARMV7_EVENT_ATTR(ld_retired, ARMV7_PERFCTR_MEM_READ);
+ARMV7_EVENT_ATTR(st_retired, ARMV7_PERFCTR_MEM_WRITE);
+ARMV7_EVENT_ATTR(inst_retired, ARMV7_PERFCTR_INSTR_EXECUTED);
+ARMV7_EVENT_ATTR(exc_taken, ARMV7_PERFCTR_EXC_TAKEN);
+ARMV7_EVENT_ATTR(exc_return, ARMV7_PERFCTR_EXC_EXECUTED);
+ARMV7_EVENT_ATTR(cid_write_retired, ARMV7_PERFCTR_CID_WRITE);
+ARMV7_EVENT_ATTR(pc_write_retired, ARMV7_PERFCTR_PC_WRITE);
+ARMV7_EVENT_ATTR(br_immed_retired, ARMV7_PERFCTR_PC_IMM_BRANCH);
+ARMV7_EVENT_ATTR(br_return_retired, ARMV7_PERFCTR_PC_PROC_RETURN);
+ARMV7_EVENT_ATTR(unaligned_ldst_retired, ARMV7_PERFCTR_MEM_UNALIGNED_ACCESS);
+ARMV7_EVENT_ATTR(br_mis_pred, ARMV7_PERFCTR_PC_BRANCH_MIS_PRED);
+ARMV7_EVENT_ATTR(cpu_cycles, ARMV7_PERFCTR_CLOCK_CYCLES);
+ARMV7_EVENT_ATTR(br_pred, ARMV7_PERFCTR_PC_BRANCH_PRED);
+
+static struct attribute *armv7_pmuv1_event_attrs[] = {
+       &armv7_event_attr_sw_incr.attr.attr,
+       &armv7_event_attr_l1i_cache_refill.attr.attr,
+       &armv7_event_attr_l1i_tlb_refill.attr.attr,
+       &armv7_event_attr_l1d_cache_refill.attr.attr,
+       &armv7_event_attr_l1d_cache.attr.attr,
+       &armv7_event_attr_l1d_tlb_refill.attr.attr,
+       &armv7_event_attr_ld_retired.attr.attr,
+       &armv7_event_attr_st_retired.attr.attr,
+       &armv7_event_attr_inst_retired.attr.attr,
+       &armv7_event_attr_exc_taken.attr.attr,
+       &armv7_event_attr_exc_return.attr.attr,
+       &armv7_event_attr_cid_write_retired.attr.attr,
+       &armv7_event_attr_pc_write_retired.attr.attr,
+       &armv7_event_attr_br_immed_retired.attr.attr,
+       &armv7_event_attr_br_return_retired.attr.attr,
+       &armv7_event_attr_unaligned_ldst_retired.attr.attr,
+       &armv7_event_attr_br_mis_pred.attr.attr,
+       &armv7_event_attr_cpu_cycles.attr.attr,
+       &armv7_event_attr_br_pred.attr.attr,
+       NULL,
+};
+
+static struct attribute_group armv7_pmuv1_events_attr_group = {
+       .name = "events",
+       .attrs = armv7_pmuv1_event_attrs,
+};
+
+static const struct attribute_group *armv7_pmuv1_attr_groups[] = {
+       &armv7_pmuv1_events_attr_group,
+       &armv7_pmu_format_attr_group,
+       NULL,
+};
+
+ARMV7_EVENT_ATTR(mem_access, ARMV7_PERFCTR_MEM_ACCESS);
+ARMV7_EVENT_ATTR(l1i_cache, ARMV7_PERFCTR_L1_ICACHE_ACCESS);
+ARMV7_EVENT_ATTR(l1d_cache_wb, ARMV7_PERFCTR_L1_DCACHE_WB);
+ARMV7_EVENT_ATTR(l2d_cache, ARMV7_PERFCTR_L2_CACHE_ACCESS);
+ARMV7_EVENT_ATTR(l2d_cache_refill, ARMV7_PERFCTR_L2_CACHE_REFILL);
+ARMV7_EVENT_ATTR(l2d_cache_wb, ARMV7_PERFCTR_L2_CACHE_WB);
+ARMV7_EVENT_ATTR(bus_access, ARMV7_PERFCTR_BUS_ACCESS);
+ARMV7_EVENT_ATTR(memory_error, ARMV7_PERFCTR_MEM_ERROR);
+ARMV7_EVENT_ATTR(inst_spec, ARMV7_PERFCTR_INSTR_SPEC);
+ARMV7_EVENT_ATTR(ttbr_write_retired, ARMV7_PERFCTR_TTBR_WRITE);
+ARMV7_EVENT_ATTR(bus_cycles, ARMV7_PERFCTR_BUS_CYCLES);
+
+static struct attribute *armv7_pmuv2_event_attrs[] = {
+       &armv7_event_attr_sw_incr.attr.attr,
+       &armv7_event_attr_l1i_cache_refill.attr.attr,
+       &armv7_event_attr_l1i_tlb_refill.attr.attr,
+       &armv7_event_attr_l1d_cache_refill.attr.attr,
+       &armv7_event_attr_l1d_cache.attr.attr,
+       &armv7_event_attr_l1d_tlb_refill.attr.attr,
+       &armv7_event_attr_ld_retired.attr.attr,
+       &armv7_event_attr_st_retired.attr.attr,
+       &armv7_event_attr_inst_retired.attr.attr,
+       &armv7_event_attr_exc_taken.attr.attr,
+       &armv7_event_attr_exc_return.attr.attr,
+       &armv7_event_attr_cid_write_retired.attr.attr,
+       &armv7_event_attr_pc_write_retired.attr.attr,
+       &armv7_event_attr_br_immed_retired.attr.attr,
+       &armv7_event_attr_br_return_retired.attr.attr,
+       &armv7_event_attr_unaligned_ldst_retired.attr.attr,
+       &armv7_event_attr_br_mis_pred.attr.attr,
+       &armv7_event_attr_cpu_cycles.attr.attr,
+       &armv7_event_attr_br_pred.attr.attr,
+       &armv7_event_attr_mem_access.attr.attr,
+       &armv7_event_attr_l1i_cache.attr.attr,
+       &armv7_event_attr_l1d_cache_wb.attr.attr,
+       &armv7_event_attr_l2d_cache.attr.attr,
+       &armv7_event_attr_l2d_cache_refill.attr.attr,
+       &armv7_event_attr_l2d_cache_wb.attr.attr,
+       &armv7_event_attr_bus_access.attr.attr,
+       &armv7_event_attr_memory_error.attr.attr,
+       &armv7_event_attr_inst_spec.attr.attr,
+       &armv7_event_attr_ttbr_write_retired.attr.attr,
+       &armv7_event_attr_bus_cycles.attr.attr,
+       NULL,
+};
+
+static struct attribute_group armv7_pmuv2_events_attr_group = {
+       .name = "events",
+       .attrs = armv7_pmuv2_event_attrs,
+};
+
+static const struct attribute_group *armv7_pmuv2_attr_groups[] = {
+       &armv7_pmuv2_events_attr_group,
+       &armv7_pmu_format_attr_group,
+       NULL,
+};
+
 /*
  * Perf Events' indices
  */
@@ -1085,6 +1197,7 @@ static int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu)
        armv7pmu_init(cpu_pmu);
        cpu_pmu->name           = "armv7_cortex_a8";
        cpu_pmu->map_event      = armv7_a8_map_event;
+       cpu_pmu->pmu.attr_groups = armv7_pmuv1_attr_groups;
        return armv7_probe_num_events(cpu_pmu);
 }
 
@@ -1093,6 +1206,7 @@ static int armv7_a9_pmu_init(struct arm_pmu *cpu_pmu)
        armv7pmu_init(cpu_pmu);
        cpu_pmu->name           = "armv7_cortex_a9";
        cpu_pmu->map_event      = armv7_a9_map_event;
+       cpu_pmu->pmu.attr_groups = armv7_pmuv1_attr_groups;
        return armv7_probe_num_events(cpu_pmu);
 }
 
@@ -1101,6 +1215,7 @@ static int armv7_a5_pmu_init(struct arm_pmu *cpu_pmu)
        armv7pmu_init(cpu_pmu);
        cpu_pmu->name           = "armv7_cortex_a5";
        cpu_pmu->map_event      = armv7_a5_map_event;
+       cpu_pmu->pmu.attr_groups = armv7_pmuv1_attr_groups;
        return armv7_probe_num_events(cpu_pmu);
 }
 
@@ -1110,6 +1225,7 @@ static int armv7_a15_pmu_init(struct arm_pmu *cpu_pmu)
        cpu_pmu->name           = "armv7_cortex_a15";
        cpu_pmu->map_event      = armv7_a15_map_event;
        cpu_pmu->set_event_filter = armv7pmu_set_event_filter;
+       cpu_pmu->pmu.attr_groups = armv7_pmuv2_attr_groups;
        return armv7_probe_num_events(cpu_pmu);
 }
 
@@ -1119,6 +1235,7 @@ static int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu)
        cpu_pmu->name           = "armv7_cortex_a7";
        cpu_pmu->map_event      = armv7_a7_map_event;
        cpu_pmu->set_event_filter = armv7pmu_set_event_filter;
+       cpu_pmu->pmu.attr_groups = armv7_pmuv2_attr_groups;
        return armv7_probe_num_events(cpu_pmu);
 }
 
@@ -1128,6 +1245,7 @@ static int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu)
        cpu_pmu->name           = "armv7_cortex_a12";
        cpu_pmu->map_event      = armv7_a12_map_event;
        cpu_pmu->set_event_filter = armv7pmu_set_event_filter;
+       cpu_pmu->pmu.attr_groups = armv7_pmuv2_attr_groups;
        return armv7_probe_num_events(cpu_pmu);
 }
 
@@ -1135,6 +1253,7 @@ static int armv7_a17_pmu_init(struct arm_pmu *cpu_pmu)
 {
        int ret = armv7_a12_pmu_init(cpu_pmu);
        cpu_pmu->name = "armv7_cortex_a17";
+       cpu_pmu->pmu.attr_groups = armv7_pmuv2_attr_groups;
        return ret;
 }
 
index 8153e36b24917e96c8fa69d18bd78e8b0c130c1a..7c9248b74d3f41548e5ce41d614dc8850d08aa94 100644 (file)
@@ -66,9 +66,13 @@ static void __init pj4_cp_access_write(u32 value)
 
        __asm__ __volatile__ (
                "mcr    p15, 0, %1, c1, c0, 2\n\t"
+#ifdef CONFIG_THUMB2_KERNEL
+               "isb\n\t"
+#else
                "mrc    p15, 0, %0, c1, c0, 2\n\t"
                "mov    %0, %0\n\t"
                "sub    pc, pc, #4\n\t"
+#endif
                : "=r" (temp) : "r" (value));
 }
 
diff --git a/arch/arm/kernel/psci-call.S b/arch/arm/kernel/psci-call.S
deleted file mode 100644 (file)
index a78e9e1..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * Copyright (C) 2015 ARM Limited
- *
- * Author: Mark Rutland <mark.rutland@arm.com>
- */
-
-#include <linux/linkage.h>
-
-#include <asm/opcodes-sec.h>
-#include <asm/opcodes-virt.h>
-
-/* int __invoke_psci_fn_hvc(u32 function_id, u32 arg0, u32 arg1, u32 arg2) */
-ENTRY(__invoke_psci_fn_hvc)
-       __HVC(0)
-       bx      lr
-ENDPROC(__invoke_psci_fn_hvc)
-
-/* int __invoke_psci_fn_smc(u32 function_id, u32 arg0, u32 arg1, u32 arg2) */
-ENTRY(__invoke_psci_fn_smc)
-       __SMC(0)
-       bx      lr
-ENDPROC(__invoke_psci_fn_smc)
index 20edd349d379f22c583438db7fbf52f46e1133ef..7d0cba6f1cc5efadff31fd0cde2aca3279e120da 100644 (file)
@@ -7,6 +7,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <linux/efi.h>
 #include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/stddef.h>
@@ -37,7 +38,9 @@
 #include <asm/cp15.h>
 #include <asm/cpu.h>
 #include <asm/cputype.h>
+#include <asm/efi.h>
 #include <asm/elf.h>
+#include <asm/early_ioremap.h>
 #include <asm/fixmap.h>
 #include <asm/procinfo.h>
 #include <asm/psci.h>
@@ -375,6 +378,72 @@ void __init early_print(const char *str, ...)
        printk("%s", buf);
 }
 
+#ifdef CONFIG_ARM_PATCH_IDIV
+
+static inline u32 __attribute_const__ sdiv_instruction(void)
+{
+       if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
+               /* "sdiv r0, r0, r1" */
+               u32 insn = __opcode_thumb32_compose(0xfb90, 0xf0f1);
+               return __opcode_to_mem_thumb32(insn);
+       }
+
+       /* "sdiv r0, r0, r1" */
+       return __opcode_to_mem_arm(0xe710f110);
+}
+
+static inline u32 __attribute_const__ udiv_instruction(void)
+{
+       if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
+               /* "udiv r0, r0, r1" */
+               u32 insn = __opcode_thumb32_compose(0xfbb0, 0xf0f1);
+               return __opcode_to_mem_thumb32(insn);
+       }
+
+       /* "udiv r0, r0, r1" */
+       return __opcode_to_mem_arm(0xe730f110);
+}
+
+static inline u32 __attribute_const__ bx_lr_instruction(void)
+{
+       if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
+               /* "bx lr; nop" */
+               u32 insn = __opcode_thumb32_compose(0x4770, 0x46c0);
+               return __opcode_to_mem_thumb32(insn);
+       }
+
+       /* "bx lr" */
+       return __opcode_to_mem_arm(0xe12fff1e);
+}
+
+static void __init patch_aeabi_idiv(void)
+{
+       extern void __aeabi_uidiv(void);
+       extern void __aeabi_idiv(void);
+       uintptr_t fn_addr;
+       unsigned int mask;
+
+       mask = IS_ENABLED(CONFIG_THUMB2_KERNEL) ? HWCAP_IDIVT : HWCAP_IDIVA;
+       if (!(elf_hwcap & mask))
+               return;
+
+       pr_info("CPU: div instructions available: patching division code\n");
+
+       fn_addr = ((uintptr_t)&__aeabi_uidiv) & ~1;
+       ((u32 *)fn_addr)[0] = udiv_instruction();
+       ((u32 *)fn_addr)[1] = bx_lr_instruction();
+       flush_icache_range(fn_addr, fn_addr + 8);
+
+       fn_addr = ((uintptr_t)&__aeabi_idiv) & ~1;
+       ((u32 *)fn_addr)[0] = sdiv_instruction();
+       ((u32 *)fn_addr)[1] = bx_lr_instruction();
+       flush_icache_range(fn_addr, fn_addr + 8);
+}
+
+#else
+static inline void patch_aeabi_idiv(void) { }
+#endif
+
 static void __init cpuid_init_hwcaps(void)
 {
        int block;
@@ -642,6 +711,7 @@ static void __init setup_processor(void)
        elf_hwcap = list->elf_hwcap;
 
        cpuid_init_hwcaps();
+       patch_aeabi_idiv();
 
 #ifndef CONFIG_ARM_THUMB
        elf_hwcap &= ~(HWCAP_THUMB | HWCAP_IDIVT);
@@ -956,8 +1026,8 @@ void __init setup_arch(char **cmdline_p)
        strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
        *cmdline_p = cmd_line;
 
-       if (IS_ENABLED(CONFIG_FIX_EARLYCON_MEM))
-               early_fixmap_init();
+       early_fixmap_init();
+       early_ioremap_init();
 
        parse_early_param();
 
@@ -965,9 +1035,12 @@ void __init setup_arch(char **cmdline_p)
        early_paging_init(mdesc);
 #endif
        setup_dma_zone(mdesc);
+       efi_init();
        sanity_check_meminfo();
        arm_memblock_init(mdesc);
 
+       early_ioremap_reset();
+
        paging_init(mdesc);
        request_standard_resources(mdesc);
 
diff --git a/arch/arm/kernel/smccc-call.S b/arch/arm/kernel/smccc-call.S
new file mode 100644 (file)
index 0000000..2e48b67
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/linkage.h>
+
+#include <asm/opcodes-sec.h>
+#include <asm/opcodes-virt.h>
+#include <asm/unwind.h>
+
+       /*
+        * Wrap c macros in asm macros to delay expansion until after the
+        * SMCCC asm macro is expanded.
+        */
+       .macro SMCCC_SMC
+       __SMC(0)
+       .endm
+
+       .macro SMCCC_HVC
+       __HVC(0)
+       .endm
+
+       .macro SMCCC instr
+UNWIND(        .fnstart)
+       mov     r12, sp
+       push    {r4-r7}
+UNWIND(        .save   {r4-r7})
+       ldm     r12, {r4-r7}
+       \instr
+       pop     {r4-r7}
+       ldr     r12, [sp, #(4 * 4)]
+       stm     r12, {r0-r3}
+       bx      lr
+UNWIND(        .fnend)
+       .endm
+
+/*
+ * void smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2,
+ *               unsigned long a3, unsigned long a4, unsigned long a5,
+ *               unsigned long a6, unsigned long a7, struct arm_smccc_res *res)
+ */
+ENTRY(arm_smccc_smc)
+       SMCCC SMCCC_SMC
+ENDPROC(arm_smccc_smc)
+
+/*
+ * void smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2,
+ *               unsigned long a3, unsigned long a4, unsigned long a5,
+ *               unsigned long a6, unsigned long a7, struct arm_smccc_res *res)
+ */
+ENTRY(arm_smccc_hvc)
+       SMCCC SMCCC_HVC
+ENDPROC(arm_smccc_hvc)
index b26361355daeb39b61c238333c20dd2d68ec4a61..37312f6749f3dd641f48803b67c8f26a4623a8a2 100644 (file)
@@ -69,11 +69,15 @@ enum ipi_msg_type {
        IPI_TIMER,
        IPI_RESCHEDULE,
        IPI_CALL_FUNC,
-       IPI_CALL_FUNC_SINGLE,
        IPI_CPU_STOP,
        IPI_IRQ_WORK,
        IPI_COMPLETION,
-       IPI_CPU_BACKTRACE = 15,
+       IPI_CPU_BACKTRACE,
+       /*
+        * SGI8-15 can be reserved by secure firmware, and thus may
+        * not be usable by the kernel. Please keep the above limited
+        * to at most 8 entries.
+        */
 };
 
 static DECLARE_COMPLETION(cpu_running);
@@ -475,7 +479,6 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
        S(IPI_TIMER, "Timer broadcast interrupts"),
        S(IPI_RESCHEDULE, "Rescheduling interrupts"),
        S(IPI_CALL_FUNC, "Function call interrupts"),
-       S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"),
        S(IPI_CPU_STOP, "CPU stop interrupts"),
        S(IPI_IRQ_WORK, "IRQ work interrupts"),
        S(IPI_COMPLETION, "completion interrupts"),
@@ -525,7 +528,7 @@ void arch_send_wakeup_ipi_mask(const struct cpumask *mask)
 
 void arch_send_call_function_single_ipi(int cpu)
 {
-       smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
+       smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC);
 }
 
 #ifdef CONFIG_IRQ_WORK
@@ -620,12 +623,6 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
                irq_exit();
                break;
 
-       case IPI_CALL_FUNC_SINGLE:
-               irq_enter();
-               generic_smp_call_function_single_interrupt();
-               irq_exit();
-               break;
-
        case IPI_CPU_STOP:
                irq_enter();
                ipi_cpu_stop(cpu);
index b83f3b7737fb9dce2a18c66a086aac2430e98cf6..087acb569b63a4bd90982e0c9b15fc2313636c53 100644 (file)
@@ -193,15 +193,44 @@ struct oabi_flock64 {
        pid_t   l_pid;
 } __attribute__ ((packed,aligned(4)));
 
-asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd,
+static long do_locks(unsigned int fd, unsigned int cmd,
                                 unsigned long arg)
 {
-       struct oabi_flock64 user;
        struct flock64 kernel;
-       mm_segment_t fs = USER_DS; /* initialized to kill a warning */
-       unsigned long local_arg = arg;
-       int ret;
+       struct oabi_flock64 user;
+       mm_segment_t fs;
+       long ret;
+
+       if (copy_from_user(&user, (struct oabi_flock64 __user *)arg,
+                          sizeof(user)))
+               return -EFAULT;
+       kernel.l_type   = user.l_type;
+       kernel.l_whence = user.l_whence;
+       kernel.l_start  = user.l_start;
+       kernel.l_len    = user.l_len;
+       kernel.l_pid    = user.l_pid;
+
+       fs = get_fs();
+       set_fs(KERNEL_DS);
+       ret = sys_fcntl64(fd, cmd, (unsigned long)&kernel);
+       set_fs(fs);
+
+       if (!ret && (cmd == F_GETLK64 || cmd == F_OFD_GETLK)) {
+               user.l_type     = kernel.l_type;
+               user.l_whence   = kernel.l_whence;
+               user.l_start    = kernel.l_start;
+               user.l_len      = kernel.l_len;
+               user.l_pid      = kernel.l_pid;
+               if (copy_to_user((struct oabi_flock64 __user *)arg,
+                                &user, sizeof(user)))
+                       ret = -EFAULT;
+       }
+       return ret;
+}
 
+asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd,
+                                unsigned long arg)
+{
        switch (cmd) {
        case F_OFD_GETLK:
        case F_OFD_SETLK:
@@ -209,39 +238,11 @@ asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd,
        case F_GETLK64:
        case F_SETLK64:
        case F_SETLKW64:
-               if (copy_from_user(&user, (struct oabi_flock64 __user *)arg,
-                                  sizeof(user)))
-                       return -EFAULT;
-               kernel.l_type   = user.l_type;
-               kernel.l_whence = user.l_whence;
-               kernel.l_start  = user.l_start;
-               kernel.l_len    = user.l_len;
-               kernel.l_pid    = user.l_pid;
-               local_arg = (unsigned long)&kernel;
-               fs = get_fs();
-               set_fs(KERNEL_DS);
-       }
-
-       ret = sys_fcntl64(fd, cmd, local_arg);
+               return do_locks(fd, cmd, arg);
 
-       switch (cmd) {
-       case F_GETLK64:
-               if (!ret) {
-                       user.l_type     = kernel.l_type;
-                       user.l_whence   = kernel.l_whence;
-                       user.l_start    = kernel.l_start;
-                       user.l_len      = kernel.l_len;
-                       user.l_pid      = kernel.l_pid;
-                       if (copy_to_user((struct oabi_flock64 __user *)arg,
-                                        &user, sizeof(user)))
-                               ret = -EFAULT;
-               }
-       case F_SETLK64:
-       case F_SETLKW64:
-               set_fs(fs);
+       default:
+               return sys_fcntl64(fd, cmd, arg);
        }
-
-       return ret;
 }
 
 struct oabi_epoll_event {
index 54a5aeab988d3526657b8e3089942ca8cfe4fe5e..994e971a8538a2d316235ba1f61be54317fbba61 100644 (file)
@@ -224,7 +224,7 @@ static int install_vvar(struct mm_struct *mm, unsigned long addr)
                                       VM_READ | VM_MAYREAD,
                                       &vdso_data_mapping);
 
-       return IS_ERR(vma) ? PTR_ERR(vma) : 0;
+       return PTR_ERR_OR_ZERO(vma);
 }
 
 /* assumes mmap_sem is write-locked */
index e06fd299de0846b44b72cd037eacd05b0b2cb051..dda1959f0ddeb947e8a8020d7da0b02bb19f89cc 100644 (file)
@@ -44,6 +44,7 @@
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_coproc.h>
 #include <asm/kvm_psci.h>
+#include <asm/sections.h>
 
 #ifdef REQUIRES_VIRT
 __asm__(".arch_extension       virt");
@@ -58,9 +59,12 @@ static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_arm_running_vcpu);
 
 /* The VMID used in the VTTBR */
 static atomic64_t kvm_vmid_gen = ATOMIC64_INIT(1);
-static u8 kvm_next_vmid;
+static u32 kvm_next_vmid;
+static unsigned int kvm_vmid_bits __read_mostly;
 static DEFINE_SPINLOCK(kvm_vmid_lock);
 
+static bool vgic_present;
+
 static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
 {
        BUG_ON(preemptible());
@@ -132,7 +136,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
        kvm->arch.vmid_gen = 0;
 
        /* The maximum number of VCPUs is limited by the host's GIC model */
-       kvm->arch.max_vcpus = kvm_vgic_get_max_vcpus();
+       kvm->arch.max_vcpus = vgic_present ?
+                               kvm_vgic_get_max_vcpus() : KVM_MAX_VCPUS;
 
        return ret;
 out_free_stage2_pgd:
@@ -172,6 +177,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        int r;
        switch (ext) {
        case KVM_CAP_IRQCHIP:
+               r = vgic_present;
+               break;
        case KVM_CAP_IOEVENTFD:
        case KVM_CAP_DEVICE_CTRL:
        case KVM_CAP_USER_MEMORY:
@@ -433,11 +440,12 @@ static void update_vttbr(struct kvm *kvm)
        kvm->arch.vmid_gen = atomic64_read(&kvm_vmid_gen);
        kvm->arch.vmid = kvm_next_vmid;
        kvm_next_vmid++;
+       kvm_next_vmid &= (1 << kvm_vmid_bits) - 1;
 
        /* update vttbr to be used with the new vmid */
        pgd_phys = virt_to_phys(kvm_get_hwpgd(kvm));
        BUG_ON(pgd_phys & ~VTTBR_BADDR_MASK);
-       vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK;
+       vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK(kvm_vmid_bits);
        kvm->arch.vttbr = pgd_phys | vmid;
 
        spin_unlock(&kvm_vmid_lock);
@@ -603,6 +611,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
                ret = kvm_call_hyp(__kvm_vcpu_run, vcpu);
 
                vcpu->mode = OUTSIDE_GUEST_MODE;
+               vcpu->stat.exits++;
                /*
                 * Back from guest
                 *************************************************************/
@@ -913,6 +922,8 @@ static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
 
        switch (dev_id) {
        case KVM_ARM_DEVICE_VGIC_V2:
+               if (!vgic_present)
+                       return -ENXIO;
                return kvm_vgic_addr(kvm, type, &dev_addr->addr, true);
        default:
                return -ENODEV;
@@ -927,6 +938,8 @@ long kvm_arch_vm_ioctl(struct file *filp,
 
        switch (ioctl) {
        case KVM_CREATE_IRQCHIP: {
+               if (!vgic_present)
+                       return -ENXIO;
                return kvm_vgic_create(kvm, KVM_DEV_TYPE_ARM_VGIC_V2);
        }
        case KVM_ARM_SET_DEVICE_ADDR: {
@@ -1067,6 +1080,12 @@ static int init_hyp_mode(void)
                goto out_free_mappings;
        }
 
+       err = create_hyp_mappings(__start_rodata, __end_rodata);
+       if (err) {
+               kvm_err("Cannot map rodata section\n");
+               goto out_free_mappings;
+       }
+
        /*
         * Map the Hyp stack pages
         */
@@ -1111,8 +1130,17 @@ static int init_hyp_mode(void)
         * Init HYP view of VGIC
         */
        err = kvm_vgic_hyp_init();
-       if (err)
+       switch (err) {
+       case 0:
+               vgic_present = true;
+               break;
+       case -ENODEV:
+       case -ENXIO:
+               vgic_present = false;
+               break;
+       default:
                goto out_free_context;
+       }
 
        /*
         * Init HYP architected timer support
@@ -1127,6 +1155,10 @@ static int init_hyp_mode(void)
 
        kvm_perf_init();
 
+       /* set size of VMID supported by CPU */
+       kvm_vmid_bits = kvm_get_vmid_bits();
+       kvm_info("%d-bit VMID\n", kvm_vmid_bits);
+
        kvm_info("Hyp mode initialized successfully\n");
 
        return 0;
index d6c005283678fe5061a50cc8f5efd1febcc0f27b..dc99159857b4ae70d7d3785b75a1c3f0f8639906 100644 (file)
@@ -275,6 +275,40 @@ static u32 exc_vector_base(struct kvm_vcpu *vcpu)
                return vbar;
 }
 
+/*
+ * Switch to an exception mode, updating both CPSR and SPSR. Follow
+ * the logic described in AArch32.EnterMode() from the ARMv8 ARM.
+ */
+static void kvm_update_psr(struct kvm_vcpu *vcpu, unsigned long mode)
+{
+       unsigned long cpsr = *vcpu_cpsr(vcpu);
+       u32 sctlr = vcpu->arch.cp15[c1_SCTLR];
+
+       *vcpu_cpsr(vcpu) = (cpsr & ~MODE_MASK) | mode;
+
+       switch (mode) {
+       case FIQ_MODE:
+               *vcpu_cpsr(vcpu) |= PSR_F_BIT;
+               /* Fall through */
+       case ABT_MODE:
+       case IRQ_MODE:
+               *vcpu_cpsr(vcpu) |= PSR_A_BIT;
+               /* Fall through */
+       default:
+               *vcpu_cpsr(vcpu) |= PSR_I_BIT;
+       }
+
+       *vcpu_cpsr(vcpu) &= ~(PSR_IT_MASK | PSR_J_BIT | PSR_E_BIT | PSR_T_BIT);
+
+       if (sctlr & SCTLR_TE)
+               *vcpu_cpsr(vcpu) |= PSR_T_BIT;
+       if (sctlr & SCTLR_EE)
+               *vcpu_cpsr(vcpu) |= PSR_E_BIT;
+
+       /* Note: These now point to the mode banked copies */
+       *vcpu_spsr(vcpu) = cpsr;
+}
+
 /**
  * kvm_inject_undefined - inject an undefined exception into the guest
  * @vcpu: The VCPU to receive the undefined exception
@@ -286,29 +320,13 @@ static u32 exc_vector_base(struct kvm_vcpu *vcpu)
  */
 void kvm_inject_undefined(struct kvm_vcpu *vcpu)
 {
-       unsigned long new_lr_value;
-       unsigned long new_spsr_value;
        unsigned long cpsr = *vcpu_cpsr(vcpu);
-       u32 sctlr = vcpu->arch.cp15[c1_SCTLR];
        bool is_thumb = (cpsr & PSR_T_BIT);
        u32 vect_offset = 4;
        u32 return_offset = (is_thumb) ? 2 : 4;
 
-       new_spsr_value = cpsr;
-       new_lr_value = *vcpu_pc(vcpu) - return_offset;
-
-       *vcpu_cpsr(vcpu) = (cpsr & ~MODE_MASK) | UND_MODE;
-       *vcpu_cpsr(vcpu) |= PSR_I_BIT;
-       *vcpu_cpsr(vcpu) &= ~(PSR_IT_MASK | PSR_J_BIT | PSR_E_BIT | PSR_T_BIT);
-
-       if (sctlr & SCTLR_TE)
-               *vcpu_cpsr(vcpu) |= PSR_T_BIT;
-       if (sctlr & SCTLR_EE)
-               *vcpu_cpsr(vcpu) |= PSR_E_BIT;
-
-       /* Note: These now point to UND banked copies */
-       *vcpu_spsr(vcpu) = cpsr;
-       *vcpu_reg(vcpu, 14) = new_lr_value;
+       kvm_update_psr(vcpu, UND_MODE);
+       *vcpu_reg(vcpu, 14) = *vcpu_pc(vcpu) - return_offset;
 
        /* Branch to exception vector */
        *vcpu_pc(vcpu) = exc_vector_base(vcpu) + vect_offset;
@@ -320,30 +338,14 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu)
  */
 static void inject_abt(struct kvm_vcpu *vcpu, bool is_pabt, unsigned long addr)
 {
-       unsigned long new_lr_value;
-       unsigned long new_spsr_value;
        unsigned long cpsr = *vcpu_cpsr(vcpu);
-       u32 sctlr = vcpu->arch.cp15[c1_SCTLR];
        bool is_thumb = (cpsr & PSR_T_BIT);
        u32 vect_offset;
        u32 return_offset = (is_thumb) ? 4 : 0;
        bool is_lpae;
 
-       new_spsr_value = cpsr;
-       new_lr_value = *vcpu_pc(vcpu) + return_offset;
-
-       *vcpu_cpsr(vcpu) = (cpsr & ~MODE_MASK) | ABT_MODE;
-       *vcpu_cpsr(vcpu) |= PSR_I_BIT | PSR_A_BIT;
-       *vcpu_cpsr(vcpu) &= ~(PSR_IT_MASK | PSR_J_BIT | PSR_E_BIT | PSR_T_BIT);
-
-       if (sctlr & SCTLR_TE)
-               *vcpu_cpsr(vcpu) |= PSR_T_BIT;
-       if (sctlr & SCTLR_EE)
-               *vcpu_cpsr(vcpu) |= PSR_E_BIT;
-
-       /* Note: These now point to ABT banked copies */
-       *vcpu_spsr(vcpu) = cpsr;
-       *vcpu_reg(vcpu, 14) = new_lr_value;
+       kvm_update_psr(vcpu, ABT_MODE);
+       *vcpu_reg(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;
 
        if (is_pabt)
                vect_offset = 12;
index 96e935bbc38c8b4fd906aeacdc27ca28696b596a..5fa69d7bae58a06ef19f7ca72fd04cf6603d6963 100644 (file)
 #define VCPU_STAT(x) { #x, offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU }
 
 struct kvm_stats_debugfs_item debugfs_entries[] = {
+       VCPU_STAT(hvc_exit_stat),
+       VCPU_STAT(wfe_exit_stat),
+       VCPU_STAT(wfi_exit_stat),
+       VCPU_STAT(mmio_exit_user),
+       VCPU_STAT(mmio_exit_kernel),
+       VCPU_STAT(exits),
        { NULL }
 };
 
index 95f12b2ccdcb8172e4faa4f7148438ec27f08f1a..3ede90d8b20bae91c4b8f20173b307cc1b0659fd 100644 (file)
@@ -42,6 +42,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
        trace_kvm_hvc(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0),
                      kvm_vcpu_hvc_get_imm(vcpu));
+       vcpu->stat.hvc_exit_stat++;
 
        ret = kvm_psci_call(vcpu);
        if (ret < 0) {
@@ -89,9 +90,11 @@ static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
        if (kvm_vcpu_get_hsr(vcpu) & HSR_WFI_IS_WFE) {
                trace_kvm_wfx(*vcpu_pc(vcpu), true);
+               vcpu->stat.wfe_exit_stat++;
                kvm_vcpu_on_spin(vcpu);
        } else {
                trace_kvm_wfx(*vcpu_pc(vcpu), false);
+               vcpu->stat.wfi_exit_stat++;
                kvm_vcpu_block(vcpu);
        }
 
index 3a10c9f1d0a46b68b42d2e7c311a7dbd6ecd44a0..7f33b2056ae6d92f568ad71fbf28cd52044b11fb 100644 (file)
@@ -210,8 +210,11 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
 
        if (!ret) {
                /* We handled the access successfully in the kernel. */
+               vcpu->stat.mmio_exit_kernel++;
                kvm_handle_mmio_return(vcpu, run);
                return 1;
+       } else {
+               vcpu->stat.mmio_exit_user++;
        }
 
        run->exit_reason        = KVM_EXIT_MMIO;
index 61d96a645ff38aa6e304eea5a198373958fe69cb..22f7fa0124ec1d80c550fea0ecf55a2c7d603091 100644 (file)
@@ -656,9 +656,9 @@ static void *kvm_alloc_hwpgd(void)
  * kvm_alloc_stage2_pgd - allocate level-1 table for stage-2 translation.
  * @kvm:       The KVM struct pointer for the VM.
  *
- * Allocates the 1st level table only of size defined by S2_PGD_ORDER (can
- * support either full 40-bit input addresses or limited to 32-bit input
- * addresses). Clears the allocated pages.
+ * Allocates only the stage-2 HW PGD level table(s) (can support either full
+ * 40-bit input addresses or limited to 32-bit input addresses). Clears the
+ * allocated pages.
  *
  * Note we don't need locking here as this is only called when the VM is
  * created, which can only be done once.
index af2267f6a52941eb91e46f1613891d4155427b5a..9397b2e532afa3d863930b4e29a663c166ae475e 100644 (file)
@@ -205,6 +205,10 @@ Boston, MA 02111-1307, USA.  */
 .endm
 
 
+#ifdef CONFIG_ARM_PATCH_IDIV
+       .align  3
+#endif
+
 ENTRY(__udivsi3)
 ENTRY(__aeabi_uidiv)
 UNWIND(.fnstart)
@@ -253,6 +257,10 @@ UNWIND(.fnstart)
 UNWIND(.fnend)
 ENDPROC(__umodsi3)
 
+#ifdef CONFIG_ARM_PATCH_IDIV
+       .align 3
+#endif
+
 ENTRY(__divsi3)
 ENTRY(__aeabi_idiv)
 UNWIND(.fnstart)
index 1ed545cc2b83452954cc4a2217ac1be324237775..9cc7b818fbf639bae6ec76c5cc116095c98d19bf 100644 (file)
@@ -49,8 +49,8 @@
 #include <asm/mach/arch.h>
 #include <asm/system_info.h>
 
-#include <media/tvp514x.h>
-#include <media/adv7343.h>
+#include <media/i2c/tvp514x.h>
+#include <media/i2c/adv7343.h>
 
 #define DA850_EVM_PHY_ID               "davinci_mdio-0:00"
 #define DA850_LCD_PWR_PIN              GPIO_TO_PIN(2, 8)
index b46b4d25f93e889b2aa8241be2a7cd303a5459c4..c71dd9982f03a1eadf5e4b75b2d8a284f343bda8 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/gpio.h>
 #include <linux/clk.h>
 #include <linux/videodev2.h>
-#include <media/tvp514x.h>
+#include <media/i2c/tvp514x.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/eeprom.h>
 #include <linux/platform_data/gpio-davinci.h>
index a756003595e9685c739d682d83594b302e903273..f073518f621a744dcd00c9befb6abfc354a9c4ce 100644 (file)
@@ -40,8 +40,8 @@
 #include <linux/platform_data/mtd-davinci.h>
 #include <linux/platform_data/keyscan-davinci.h>
 
-#include <media/ths7303.h>
-#include <media/tvp514x.h>
+#include <media/i2c/ths7303.h>
+#include <media/i2c/tvp514x.h>
 
 #include "davinci.h"
 
index bbdd2d614b4978022f0b9f51a7abc898dc0b5e0f..7a20507a3eefb3a6197afd1861286922184b67a2 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/v4l2-dv-timings.h>
 #include <linux/export.h>
 
-#include <media/tvp514x.h>
+#include <media/i2c/tvp514x.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
index 846a84ddc28e5a6d573c9767f6e57869c3e423fe..ee6ab7e8d3b0cdf7b54399e399550609d0e9301e 100644 (file)
@@ -25,8 +25,8 @@
 #include <linux/platform_data/at24.h>
 #include <linux/i2c/pcf857x.h>
 
-#include <media/tvp514x.h>
-#include <media/adv7343.h>
+#include <media/i2c/tvp514x.h>
+#include <media/i2c/adv7343.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
index 3a10f1a8317ae7a053ed997da88a06ddd5311b57..ff105399aae48973432e4f688a4efb5a570f0216 100644 (file)
@@ -27,6 +27,7 @@ menuconfig ARCH_EXYNOS
        select SRAM
        select THERMAL
        select MFD_SYSCON
+       select CLKSRC_EXYNOS_MCT
        help
          Support for SAMSUNG EXYNOS SoCs (EXYNOS4/5)
 
index 67f7fb13050dbdec3d84cfe381943240a2e4e192..09cebd8cef2b835477e96fef15863d3b9c3ec09d 100644 (file)
@@ -177,7 +177,7 @@ struct platform_device *__init imx_add_imx_uart_1irq(
                const struct imxuart_platform_data *pdata);
 
 #include <linux/platform_data/video-mx3fb.h>
-#include <linux/platform_data/camera-mx3.h>
+#include <linux/platform_data/media/camera-mx3.h>
 struct imx_ipu_core_data {
        resource_size_t iobase;
        resource_size_t synirq;
@@ -192,7 +192,7 @@ struct platform_device *__init imx_add_mx3_sdc_fb(
                const struct imx_ipu_core_data *data,
                struct mx3fb_platform_data *pdata);
 
-#include <linux/platform_data/camera-mx2.h>
+#include <linux/platform_data/media/camera-mx2.h>
 struct imx_mx2_camera_data {
        const char *devid;
        resource_size_t iobasecsi;
index 847d00f0bb0a6ae2393e0bf116cc3df76e24b92b..caa6c0d6f0ac40d93018b9561304489ae774c0a3 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __ASM_ARCH_CAMERA_H_
 #define __ASM_ARCH_CAMERA_H_
 
-#include <media/omap1_camera.h>
+#include <linux/platform_data/media/omap1_camera.h>
 
 void omap1_camera_init(void *);
 
index 04a56cc04dfa48cfc8c9752033cff152e5f15dba..809827265fb39d1b8a7178481bb91e87951c4a14 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/of_platform.h>
 #include <linux/irqdomain.h>
 
+#include <asm/setup.h>
 #include <asm/mach/arch.h>
 
 #include "common.h"
@@ -76,8 +77,17 @@ static const char *const n900_boards_compat[] __initconst = {
        NULL,
 };
 
+/* Legacy userspace on Nokia N900 needs ATAGS exported in /proc/atags,
+ * save them while the data is still not overwritten
+ */
+static void __init rx51_reserve(void)
+{
+       save_atags((const struct tag *)(PAGE_OFFSET + 0x100));
+       omap_reserve();
+}
+
 DT_MACHINE_START(OMAP3_N900_DT, "Nokia RX-51 board")
-       .reserve        = omap_reserve,
+       .reserve        = rx51_reserve,
        .map_io         = omap3_map_io,
        .init_early     = omap3430_init_early,
        .init_machine   = omap_generic_init,
index 14edcd7a2a1d14c990848bf41c515009bb74bdb5..0a0567f8e8a030ffc2b45e4d353ebff35f5149d0 100644 (file)
@@ -39,7 +39,7 @@
 
 #include <sound/tlv320aic3x.h>
 #include <sound/tpa6130a2-plat.h>
-#include <media/si4713.h>
+#include <linux/platform_data/media/si4713.h>
 #include <linux/platform_data/leds-lp55xx.h>
 
 #include <linux/platform_data/tsl2563.h>
@@ -48,7 +48,7 @@
 #include <video/omap-panel-data.h>
 
 #if defined(CONFIG_IR_RX51) || defined(CONFIG_IR_RX51_MODULE)
-#include <media/ir-rx51.h>
+#include <linux/platform_data/media/ir-rx51.h>
 #endif
 
 #include "mux.h"
index 17a6f752a43631c59eb5fd65371672bb26757b00..7b76ce01c21dd3aa3b4cad36ce2431f3c8350900 100644 (file)
@@ -149,8 +149,8 @@ static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg,
                freq = 104;
                break;
        default:
-               freq = 54;
-               break;
+               pr_err("onenand rate not detected, bad GPMC async timings?\n");
+               freq = 0;
        }
 
        return freq;
@@ -271,6 +271,11 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base)
        struct gpmc_timings t;
        int ret;
 
+       /*
+        * Note that we need to keep sync_write set for the call to
+        * omap2_onenand_set_async_mode() to work to detect the onenand
+        * supported clock rate for the sync timings.
+        */
        if (gpmc_onenand_data->of_node) {
                gpmc_read_settings_dt(gpmc_onenand_data->of_node,
                                      &onenand_async);
@@ -281,12 +286,9 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base)
                        else
                                gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
                        onenand_async.sync_read = false;
-                       onenand_async.sync_write = false;
                }
        }
 
-       omap2_onenand_set_async_mode(onenand_base);
-
        omap2_onenand_calc_async_timings(&t);
 
        ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_async);
@@ -310,6 +312,8 @@ static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr)
        if (!freq) {
                /* Very first call freq is not known */
                freq = omap2_onenand_get_freq(gpmc_onenand_data, onenand_base);
+               if (!freq)
+                       return -ENODEV;
                set_onenand_cfg(onenand_base);
        }
 
index 2a6e0ae2b92050bb35547a54ef345e1b93a6f8a4..d1211a40f400af8658b1accc3caab2175ce62163 100644 (file)
@@ -14,7 +14,7 @@
 #include <mach/irqs.h>
 #include <linux/platform_data/usb-ohci-pxa27x.h>
 #include <linux/platform_data/keypad-pxa27x.h>
-#include <linux/platform_data/camera-pxa.h>
+#include <linux/platform_data/media/camera-pxa.h>
 #include <mach/audio.h>
 #include <mach/hardware.h>
 #include <linux/platform_data/mmp_dma.h>
index 9d7072b040458ff741ed8d30ccddaf9593fb1bd3..8b1f89e096c6638fd55e628e222ccd183f9a16fd 100644 (file)
@@ -46,7 +46,7 @@
 #include <linux/platform_data/usb-ohci-pxa27x.h>
 #include <linux/platform_data/mmc-pxamci.h>
 #include <linux/platform_data/keypad-pxa27x.h>
-#include <linux/platform_data/camera-pxa.h>
+#include <linux/platform_data/media/camera-pxa.h>
 
 #include "generic.h"
 #include "devices.h"
index 7c0d5618be5e8b6f394cec5f4d797ad931675735..cd6224032109daed75877e8e401bd0e28f38e2ec 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/platform_data/usb-ohci-pxa27x.h>
 #include <mach/hardware.h>
 #include <linux/platform_data/keypad-pxa27x.h>
-#include <linux/platform_data/camera-pxa.h>
+#include <linux/platform_data/media/camera-pxa.h>
 
 #include "devices.h"
 #include "generic.h"
index 3b52b1aa06594a7a591045f1b9f195307b0583f4..ccfd2b63c6a4e26587945c83a87f8979b9e57d9b 100644 (file)
@@ -54,7 +54,7 @@
 #include <linux/platform_data/mmc-pxamci.h>
 #include <mach/udc.h>
 #include <mach/pxa27x-udc.h>
-#include <linux/platform_data/camera-pxa.h>
+#include <linux/platform_data/media/camera-pxa.h>
 #include <mach/audio.h>
 #include <mach/smemc.h>
 #include <media/soc_camera.h>
index d8b937c870de1b26ff814d690f5a4a2a17f72ee7..2dc56062fb7e91382bd87a065d4e716d044c4a67 100644 (file)
@@ -43,7 +43,7 @@
 #include <linux/platform_data/usb-ohci-pxa27x.h>
 #include <mach/pxa2xx-regs.h>
 #include <linux/platform_data/asoc-palm27x.h>
-#include <linux/platform_data/camera-pxa.h>
+#include <linux/platform_data/media/camera-pxa.h>
 #include <mach/palm27x.h>
 
 #include <sound/pxa2xx-lib.h>
index 1a35ddf218dad44994213f97a1e288fcb76245e5..e3df17a7e8d4958778914e6631b57ff269ed5fdb 100644 (file)
@@ -49,7 +49,7 @@
 #include <mach/palm27x.h>
 
 #include <mach/pm.h>
-#include <linux/platform_data/camera-pxa.h>
+#include <linux/platform_data/media/camera-pxa.h>
 
 #include <media/soc_camera.h>
 
index b71c96f614f935317bfeb5d5b74b39a616aa64bd..8459239a093c8931007672b8a1edd46d0db4f25a 100644 (file)
 #include <linux/pwm.h>
 #include <linux/pwm_backlight.h>
 
-#include <media/mt9v022.h>
+#include <media/i2c/mt9v022.h>
 #include <media/soc_camera.h>
 
-#include <linux/platform_data/camera-pxa.h>
+#include <linux/platform_data/media/camera-pxa.h>
 #include <asm/mach/map.h>
 #include <mach/pxa27x.h>
 #include <mach/audio.h>
index 125865daaf1719e931cb051b9039292799b8e930..12dd1dc0a04116e109f4a6a8754417fc668f7741 100644 (file)
@@ -3,6 +3,7 @@ menuconfig ARCH_STI
        select ARM_GIC
        select ST_IRQCHIP
        select ARM_GLOBAL_TIMER
+       select CLKSRC_ST_LPC
        select PINCTRL
        select PINCTRL_ST
        select MFD_SYSCON
index c9ac19b24e5a5da7bbfbf7aa7afcaff34f067e96..5eacdd61e61c35ffa7edcaa64d05e4948abe05ab 100644 (file)
@@ -32,6 +32,7 @@ config UX500_SOC_DB8500
        select PINCTRL_AB8540
        select REGULATOR
        select REGULATOR_DB8500_PRCMU
+       select CLKSRC_DBX500_PRCMU
        select PM_GENERIC_DOMAINS if PM
 
 config MACH_MOP500
index 493692d838c679360c1bcdb61b4ef594b66f7f95..9f9d54271aada77708a954622269eec73000dc92 100644 (file)
@@ -790,7 +790,7 @@ static const struct l2c_init_data l2c310_init_fns __initconst = {
 };
 
 static int __init __l2c_init(const struct l2c_init_data *data,
-                            u32 aux_val, u32 aux_mask, u32 cache_id)
+                            u32 aux_val, u32 aux_mask, u32 cache_id, bool nosync)
 {
        struct outer_cache_fns fns;
        unsigned way_size_bits, ways;
@@ -866,6 +866,10 @@ static int __init __l2c_init(const struct l2c_init_data *data,
        fns.configure = outer_cache.configure;
        if (data->fixup)
                data->fixup(l2x0_base, cache_id, &fns);
+       if (nosync) {
+               pr_info("L2C: disabling outer sync\n");
+               fns.sync = NULL;
+       }
 
        /*
         * Check if l2x0 controller is already enabled.  If we are booting
@@ -925,7 +929,7 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
        if (data->save)
                data->save(l2x0_base);
 
-       __l2c_init(data, aux_val, aux_mask, cache_id);
+       __l2c_init(data, aux_val, aux_mask, cache_id, false);
 }
 
 #ifdef CONFIG_OF
@@ -1060,6 +1064,18 @@ static void __init l2x0_of_parse(const struct device_node *np,
                val |= (dirty - 1) << L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT;
        }
 
+       if (of_property_read_bool(np, "arm,parity-enable")) {
+               mask &= ~L2C_AUX_CTRL_PARITY_ENABLE;
+               val |= L2C_AUX_CTRL_PARITY_ENABLE;
+       } else if (of_property_read_bool(np, "arm,parity-disable")) {
+               mask &= ~L2C_AUX_CTRL_PARITY_ENABLE;
+       }
+
+       if (of_property_read_bool(np, "arm,shared-override")) {
+               mask &= ~L2C_AUX_CTRL_SHARED_OVERRIDE;
+               val |= L2C_AUX_CTRL_SHARED_OVERRIDE;
+       }
+
        ret = l2x0_cache_size_of_parse(np, aux_val, aux_mask, &assoc, SZ_256K);
        if (ret)
                return;
@@ -1176,6 +1192,14 @@ static void __init l2c310_of_parse(const struct device_node *np,
                *aux_mask &= ~L2C_AUX_CTRL_SHARED_OVERRIDE;
        }
 
+       if (of_property_read_bool(np, "arm,parity-enable")) {
+               *aux_val |= L2C_AUX_CTRL_PARITY_ENABLE;
+               *aux_mask &= ~L2C_AUX_CTRL_PARITY_ENABLE;
+       } else if (of_property_read_bool(np, "arm,parity-disable")) {
+               *aux_val &= ~L2C_AUX_CTRL_PARITY_ENABLE;
+               *aux_mask &= ~L2C_AUX_CTRL_PARITY_ENABLE;
+       }
+
        prefetch = l2x0_saved_regs.prefetch_ctrl;
 
        ret = of_property_read_u32(np, "arm,double-linefill", &val);
@@ -1704,6 +1728,7 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
        struct resource res;
        u32 cache_id, old_aux;
        u32 cache_level = 2;
+       bool nosync = false;
 
        np = of_find_matching_node(NULL, l2x0_ids);
        if (!np)
@@ -1742,6 +1767,8 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
        if (cache_level != 2)
                pr_err("L2C: device tree specifies invalid cache level\n");
 
+       nosync = of_property_read_bool(np, "arm,outer-sync-disable");
+
        /* Read back current (default) hardware configuration */
        if (data->save)
                data->save(l2x0_base);
@@ -1756,6 +1783,6 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
        else
                cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID);
 
-       return __l2c_init(data, aux_val, aux_mask, cache_id);
+       return __l2c_init(data, aux_val, aux_mask, cache_id, nosync);
 }
 #endif
index 0502ba17a3aba4288d3cfc778b8f5cba4a32f279..a6fa7b73fbe04a30c2902e8a54fb4019352fb6fc 100644 (file)
@@ -377,17 +377,6 @@ static const struct of_device_id uniphier_cache_match[] __initconst = {
        { /* sentinel */ }
 };
 
-static struct device_node * __init uniphier_cache_get_next_level_node(
-                                                       struct device_node *np)
-{
-       u32 phandle;
-
-       if (of_property_read_u32(np, "next-level-cache", &phandle))
-               return NULL;
-
-       return of_find_node_by_phandle(phandle);
-}
-
 static int __init __uniphier_cache_init(struct device_node *np,
                                        unsigned int *cache_level)
 {
@@ -491,7 +480,7 @@ static int __init __uniphier_cache_init(struct device_node *np,
         * next level cache fails because we want to continue with available
         * cache levels.
         */
-       next_np = uniphier_cache_get_next_level_node(np);
+       next_np = of_find_next_cache_node(np);
        if (next_np) {
                (*cache_level)++;
                ret = __uniphier_cache_init(next_np, cache_level);
index 7f8cd1b3557f071a64dafc05eba4c481ef82c79d..49bd08178008adc38cca29b5e50bf26aa14a07c9 100644 (file)
@@ -192,7 +192,7 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max_low,
 #ifdef CONFIG_HAVE_ARCH_PFN_VALID
 int pfn_valid(unsigned long pfn)
 {
-       return memblock_is_memory(__pfn_to_phys(pfn));
+       return memblock_is_map_memory(__pfn_to_phys(pfn));
 }
 EXPORT_SYMBOL(pfn_valid);
 #endif
@@ -433,6 +433,9 @@ static void __init free_highpages(void)
                if (end <= max_low)
                        continue;
 
+               if (memblock_is_nomap(mem))
+                       continue;
+
                /* Truncate partial highmem entries */
                if (start < max_low)
                        start = max_low;
index 0c81056c1dd7edac30e1d86bdd2103d1e2d6832f..66a978d059585f671d1d68277a200b661ef9637b 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/cp15.h>
 #include <asm/cputype.h>
 #include <asm/cacheflush.h>
+#include <asm/early_ioremap.h>
 #include <asm/mmu_context.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
@@ -469,3 +470,11 @@ int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr)
 }
 EXPORT_SYMBOL_GPL(pci_ioremap_io);
 #endif
+
+/*
+ * Must be called after early_fixmap_init
+ */
+void __init early_ioremap_init(void)
+{
+       early_ioremap_setup();
+}
index 4867f5daf82c99bdf4ee64ebb6b61613cd792a3e..a87f6cc3fa2b3953c07c8c9d195f02a6a5a303eb 100644 (file)
@@ -390,7 +390,7 @@ void __init early_fixmap_init(void)
         * The early fixmap range spans multiple pmds, for which
         * we are not prepared:
         */
-       BUILD_BUG_ON((__fix_to_virt(__end_of_permanent_fixed_addresses) >> PMD_SHIFT)
+       BUILD_BUG_ON((__fix_to_virt(__end_of_early_ioremap_region) >> PMD_SHIFT)
                     != FIXADDR_TOP >> PMD_SHIFT);
 
        pmd = fixmap_pmd(FIXADDR_TOP);
@@ -572,7 +572,7 @@ static void __init build_mem_type_table(void)
         * in the Short-descriptor translation table format descriptors.
         */
        if (cpu_arch == CPU_ARCH_ARMv7 &&
-               (read_cpuid_ext(CPUID_EXT_MMFR0) & 0xF) == 4) {
+               (read_cpuid_ext(CPUID_EXT_MMFR0) & 0xF) >= 4) {
                user_pmd_table |= PMD_PXNTABLE;
        }
 #endif
@@ -724,30 +724,49 @@ static void __init *early_alloc(unsigned long sz)
        return early_alloc_aligned(sz, sz);
 }
 
-static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr, unsigned long prot)
+static void *__init late_alloc(unsigned long sz)
+{
+       void *ptr = (void *)__get_free_pages(PGALLOC_GFP, get_order(sz));
+
+       BUG_ON(!ptr);
+       return ptr;
+}
+
+static pte_t * __init pte_alloc(pmd_t *pmd, unsigned long addr,
+                               unsigned long prot,
+                               void *(*alloc)(unsigned long sz))
 {
        if (pmd_none(*pmd)) {
-               pte_t *pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE);
+               pte_t *pte = alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE);
                __pmd_populate(pmd, __pa(pte), prot);
        }
        BUG_ON(pmd_bad(*pmd));
        return pte_offset_kernel(pmd, addr);
 }
 
+static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr,
+                                     unsigned long prot)
+{
+       return pte_alloc(pmd, addr, prot, early_alloc);
+}
+
 static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
                                  unsigned long end, unsigned long pfn,
-                                 const struct mem_type *type)
+                                 const struct mem_type *type,
+                                 void *(*alloc)(unsigned long sz),
+                                 bool ng)
 {
-       pte_t *pte = early_pte_alloc(pmd, addr, type->prot_l1);
+       pte_t *pte = pte_alloc(pmd, addr, type->prot_l1, alloc);
        do {
-               set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), 0);
+               set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)),
+                           ng ? PTE_EXT_NG : 0);
                pfn++;
        } while (pte++, addr += PAGE_SIZE, addr != end);
 }
 
 static void __init __map_init_section(pmd_t *pmd, unsigned long addr,
                        unsigned long end, phys_addr_t phys,
-                       const struct mem_type *type)
+                       const struct mem_type *type, bool ng)
 {
        pmd_t *p = pmd;
 
@@ -765,7 +784,7 @@ static void __init __map_init_section(pmd_t *pmd, unsigned long addr,
                pmd++;
 #endif
        do {
-               *pmd = __pmd(phys | type->prot_sect);
+               *pmd = __pmd(phys | type->prot_sect | (ng ? PMD_SECT_nG : 0));
                phys += SECTION_SIZE;
        } while (pmd++, addr += SECTION_SIZE, addr != end);
 
@@ -774,7 +793,8 @@ static void __init __map_init_section(pmd_t *pmd, unsigned long addr,
 
 static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
                                      unsigned long end, phys_addr_t phys,
-                                     const struct mem_type *type)
+                                     const struct mem_type *type,
+                                     void *(*alloc)(unsigned long sz), bool ng)
 {
        pmd_t *pmd = pmd_offset(pud, addr);
        unsigned long next;
@@ -792,10 +812,10 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
                 */
                if (type->prot_sect &&
                                ((addr | next | phys) & ~SECTION_MASK) == 0) {
-                       __map_init_section(pmd, addr, next, phys, type);
+                       __map_init_section(pmd, addr, next, phys, type, ng);
                } else {
                        alloc_init_pte(pmd, addr, next,
-                                               __phys_to_pfn(phys), type);
+                                      __phys_to_pfn(phys), type, alloc, ng);
                }
 
                phys += next - addr;
@@ -805,21 +825,24 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
 
 static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
                                  unsigned long end, phys_addr_t phys,
-                                 const struct mem_type *type)
+                                 const struct mem_type *type,
+                                 void *(*alloc)(unsigned long sz), bool ng)
 {
        pud_t *pud = pud_offset(pgd, addr);
        unsigned long next;
 
        do {
                next = pud_addr_end(addr, end);
-               alloc_init_pmd(pud, addr, next, phys, type);
+               alloc_init_pmd(pud, addr, next, phys, type, alloc, ng);
                phys += next - addr;
        } while (pud++, addr = next, addr != end);
 }
 
 #ifndef CONFIG_ARM_LPAE
-static void __init create_36bit_mapping(struct map_desc *md,
-                                       const struct mem_type *type)
+static void __init create_36bit_mapping(struct mm_struct *mm,
+                                       struct map_desc *md,
+                                       const struct mem_type *type,
+                                       bool ng)
 {
        unsigned long addr, length, end;
        phys_addr_t phys;
@@ -859,7 +882,7 @@ static void __init create_36bit_mapping(struct map_desc *md,
         */
        phys |= (((md->pfn >> (32 - PAGE_SHIFT)) & 0xF) << 20);
 
-       pgd = pgd_offset_k(addr);
+       pgd = pgd_offset(mm, addr);
        end = addr + length;
        do {
                pud_t *pud = pud_offset(pgd, addr);
@@ -867,7 +890,8 @@ static void __init create_36bit_mapping(struct map_desc *md,
                int i;
 
                for (i = 0; i < 16; i++)
-                       *pmd++ = __pmd(phys | type->prot_sect | PMD_SECT_SUPER);
+                       *pmd++ = __pmd(phys | type->prot_sect | PMD_SECT_SUPER |
+                                      (ng ? PMD_SECT_nG : 0));
 
                addr += SUPERSECTION_SIZE;
                phys += SUPERSECTION_SIZE;
@@ -876,33 +900,15 @@ static void __init create_36bit_mapping(struct map_desc *md,
 }
 #endif /* !CONFIG_ARM_LPAE */
 
-/*
- * Create the page directory entries and any necessary
- * page tables for the mapping specified by `md'.  We
- * are able to cope here with varying sizes and address
- * offsets, and we take full advantage of sections and
- * supersections.
- */
-static void __init create_mapping(struct map_desc *md)
+static void __init __create_mapping(struct mm_struct *mm, struct map_desc *md,
+                                   void *(*alloc)(unsigned long sz),
+                                   bool ng)
 {
        unsigned long addr, length, end;
        phys_addr_t phys;
        const struct mem_type *type;
        pgd_t *pgd;
 
-       if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
-               pr_warn("BUG: not creating mapping for 0x%08llx at 0x%08lx in user region\n",
-                       (long long)__pfn_to_phys((u64)md->pfn), md->virtual);
-               return;
-       }
-
-       if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
-           md->virtual >= PAGE_OFFSET && md->virtual < FIXADDR_START &&
-           (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) {
-               pr_warn("BUG: mapping for 0x%08llx at 0x%08lx out of vmalloc space\n",
-                       (long long)__pfn_to_phys((u64)md->pfn), md->virtual);
-       }
-
        type = &mem_types[md->type];
 
 #ifndef CONFIG_ARM_LPAE
@@ -910,7 +916,7 @@ static void __init create_mapping(struct map_desc *md)
         * Catch 36-bit addresses
         */
        if (md->pfn >= 0x100000) {
-               create_36bit_mapping(md, type);
+               create_36bit_mapping(mm, md, type, ng);
                return;
        }
 #endif
@@ -925,18 +931,55 @@ static void __init create_mapping(struct map_desc *md)
                return;
        }
 
-       pgd = pgd_offset_k(addr);
+       pgd = pgd_offset(mm, addr);
        end = addr + length;
        do {
                unsigned long next = pgd_addr_end(addr, end);
 
-               alloc_init_pud(pgd, addr, next, phys, type);
+               alloc_init_pud(pgd, addr, next, phys, type, alloc, ng);
 
                phys += next - addr;
                addr = next;
        } while (pgd++, addr != end);
 }
 
+/*
+ * Create the page directory entries and any necessary
+ * page tables for the mapping specified by `md'.  We
+ * are able to cope here with varying sizes and address
+ * offsets, and we take full advantage of sections and
+ * supersections.
+ */
+static void __init create_mapping(struct map_desc *md)
+{
+       if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
+               pr_warn("BUG: not creating mapping for 0x%08llx at 0x%08lx in user region\n",
+                       (long long)__pfn_to_phys((u64)md->pfn), md->virtual);
+               return;
+       }
+
+       if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
+           md->virtual >= PAGE_OFFSET && md->virtual < FIXADDR_START &&
+           (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) {
+               pr_warn("BUG: mapping for 0x%08llx at 0x%08lx out of vmalloc space\n",
+                       (long long)__pfn_to_phys((u64)md->pfn), md->virtual);
+       }
+
+       __create_mapping(&init_mm, md, early_alloc, false);
+}
+
+void __init create_mapping_late(struct mm_struct *mm, struct map_desc *md,
+                               bool ng)
+{
+#ifdef CONFIG_ARM_LPAE
+       pud_t *pud = pud_alloc(mm, pgd_offset(mm, md->virtual), md->virtual);
+       if (WARN_ON(!pud))
+               return;
+       pmd_alloc(mm, pud, 0);
+#endif
+       __create_mapping(mm, md, late_alloc, ng);
+}
+
 /*
  * Create the architecture specific mappings
  */
@@ -1392,6 +1435,9 @@ static void __init map_lowmem(void)
                phys_addr_t end = start + reg->size;
                struct map_desc map;
 
+               if (memblock_is_nomap(reg))
+                       continue;
+
                if (end > arm_lowmem_limit)
                        end = arm_lowmem_limit;
                if (start >= end)
index 8e1ea433c3f1e321d7ed4e91fe582a5be4eb85be..0f92d575a3040b53f6584759b95a0bd1217ea3c2 100644 (file)
@@ -274,10 +274,12 @@ __v7_ca15mp_setup:
 __v7_b15mp_setup:
 __v7_ca17mp_setup:
        mov     r10, #0
-1:     adr     r12, __v7_setup_stack           @ the local stack
-       stmia   r12, {r0-r5, lr}                @ v7_invalidate_l1 touches r0-r6
+1:     adr     r0, __v7_setup_stack_ptr
+       ldr     r12, [r0]
+       add     r12, r12, r0                    @ the local stack
+       stmia   r12, {r1-r6, lr}                @ v7_invalidate_l1 touches r0-r6
        bl      v7_invalidate_l1
-       ldmia   r12, {r0-r5, lr}
+       ldmia   r12, {r1-r6, lr}
 #ifdef CONFIG_SMP
        ALT_SMP(mrc     p15, 0, r0, c1, c0, 1)
        ALT_UP(mov      r0, #(1 << 6))          @ fake it for UP
@@ -415,10 +417,12 @@ __v7_pj4b_setup:
 #endif /* CONFIG_CPU_PJ4B */
 
 __v7_setup:
-       adr     r12, __v7_setup_stack           @ the local stack
-       stmia   r12, {r0-r5, lr}                @ v7_invalidate_l1 touches r0-r6
+       adr     r0, __v7_setup_stack_ptr
+       ldr     r12, [r0]
+       add     r12, r12, r0                    @ the local stack
+       stmia   r12, {r1-r6, lr}                @ v7_invalidate_l1 touches r0-r6
        bl      v7_invalidate_l1
-       ldmia   r12, {r0-r5, lr}
+       ldmia   r12, {r1-r6, lr}
 
 __v7_setup_cont:
        and     r0, r9, #0xff000000             @ ARM?
@@ -480,11 +484,16 @@ __errata_finish:
        orr     r0, r0, r6                      @ set them
  THUMB(        orr     r0, r0, #1 << 30        )       @ Thumb exceptions
        ret     lr                              @ return to head.S:__ret
+
+       .align  2
+__v7_setup_stack_ptr:
+       .word   __v7_setup_stack - .
 ENDPROC(__v7_setup)
 
+       .bss
        .align  2
 __v7_setup_stack:
-       .space  4 * 7                           @ 12 registers
+       .space  4 * 7                           @ 7 registers
 
        __INITDATA
 
index 67d9209077c6b586debd9d745e8f3e3389c92567..7229d8d0be1af2eba82adaf8825fd88490c8a4f4 100644 (file)
@@ -12,6 +12,7 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include <asm/memory.h>
 #include <asm/v7m.h>
 #include "proc-macros.S"
 
@@ -97,19 +98,19 @@ __v7m_setup:
        mov     r5, #0x00800000
        str     r5, [r0, V7M_SCB_SHPR3] @ set PendSV priority
 
-       @ SVC to run the kernel in this mode
+       @ SVC to switch to handler mode. Notice that this requires sp to
+       @ point to writeable memory because the processor saves
+       @ some registers to the stack.
        badr    r1, 1f
        ldr     r5, [r12, #11 * 4]      @ read the SVC vector entry
        str     r1, [r12, #11 * 4]      @ write the temporary SVC vector entry
        mov     r6, lr                  @ save LR
-       mov     r7, sp                  @ save SP
-       ldr     sp, =__v7m_setup_stack_top
+       ldr     sp, =init_thread_union + THREAD_START_SP
        cpsie   i
        svc     #0
 1:     cpsid   i
        str     r5, [r12, #11 * 4]      @ restore the original SVC vector entry
        mov     lr, r6                  @ restore LR
-       mov     sp, r7                  @ restore SP
 
        @ Special-purpose control register
        mov     r1, #1
@@ -123,11 +124,6 @@ __v7m_setup:
        ret     lr
 ENDPROC(__v7m_setup)
 
-       .align 2
-__v7m_setup_stack:
-       .space  4 * 8                           @ 8 registers
-__v7m_setup_stack_top:
-
        define_processor_functions v7m, dabort=nommu_early_abort, pabort=legacy_pabort, nommu=1
 
        .section ".rodata"
index 591f9db3bf4048a4d727f195e4e2fb95e4ca06c4..93d0b6d0b63eede5f36de91428bb181bab2e0971 100644 (file)
@@ -187,19 +187,6 @@ static inline int mem_words_used(struct jit_ctx *ctx)
        return fls(ctx->seen & SEEN_MEM);
 }
 
-static inline bool is_load_to_a(u16 inst)
-{
-       switch (inst) {
-       case BPF_LD | BPF_W | BPF_LEN:
-       case BPF_LD | BPF_W | BPF_ABS:
-       case BPF_LD | BPF_H | BPF_ABS:
-       case BPF_LD | BPF_B | BPF_ABS:
-               return true;
-       default:
-               return false;
-       }
-}
-
 static void jit_fill_hole(void *area, unsigned int size)
 {
        u32 *ptr;
@@ -211,7 +198,6 @@ static void jit_fill_hole(void *area, unsigned int size)
 static void build_prologue(struct jit_ctx *ctx)
 {
        u16 reg_set = saved_regs(ctx);
-       u16 first_inst = ctx->skf->insns[0].code;
        u16 off;
 
 #ifdef CONFIG_FRAME_POINTER
@@ -241,7 +227,7 @@ static void build_prologue(struct jit_ctx *ctx)
                emit(ARM_MOV_I(r_X, 0), ctx);
 
        /* do not leak kernel data to userspace */
-       if ((first_inst != (BPF_RET | BPF_K)) && !(is_load_to_a(first_inst)))
+       if (bpf_needs_clear_a(&ctx->skf->insns[0]))
                emit(ARM_MOV_I(r_A, 0), ctx);
 
        /* stack space for the BPF_MEM words */
@@ -770,7 +756,8 @@ load_ind:
                case BPF_ALU | BPF_RSH | BPF_K:
                        if (unlikely(k > 31))
                                return -1;
-                       emit(ARM_LSR_I(r_A, r_A, k), ctx);
+                       if (k)
+                               emit(ARM_LSR_I(r_A, r_A, k), ctx);
                        break;
                case BPF_ALU | BPF_RSH | BPF_X:
                        update_on_xread(ctx);
index 82074625de5cebfc7681f72c931c90d1b7e951ac..74ef8891254e717408297eb0e492ed76beefe390 100644 (file)
@@ -36,7 +36,7 @@
 #include <linux/platform_data/s3c-hsotg.h>
 #include <linux/platform_data/dma-s3c24xx.h>
 
-#include <media/s5p_hdmi.h>
+#include <linux/platform_data/media/s5p_hdmi.h>
 
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
index fc7ea529f462de75149c31168f01f17a42908e76..75cd7345c654d82d8174f00f3a88b2322a502b43 100644 (file)
@@ -12,6 +12,7 @@
 #include <xen/page.h>
 #include <xen/interface/sched.h>
 #include <xen/xen-ops.h>
+#include <asm/paravirt.h>
 #include <asm/xen/hypervisor.h>
 #include <asm/xen/hypercall.h>
 #include <asm/system_misc.h>
 #include <linux/cpufreq.h>
 #include <linux/cpu.h>
 #include <linux/console.h>
+#include <linux/pvclock_gtod.h>
+#include <linux/time64.h>
+#include <linux/timekeeping.h>
+#include <linux/timekeeper_internal.h>
 
 #include <linux/mm.h>
 
@@ -79,6 +84,83 @@ int xen_unmap_domain_gfn_range(struct vm_area_struct *vma,
 }
 EXPORT_SYMBOL_GPL(xen_unmap_domain_gfn_range);
 
+static unsigned long long xen_stolen_accounting(int cpu)
+{
+       struct vcpu_runstate_info state;
+
+       BUG_ON(cpu != smp_processor_id());
+
+       xen_get_runstate_snapshot(&state);
+
+       WARN_ON(state.state != RUNSTATE_running);
+
+       return state.time[RUNSTATE_runnable] + state.time[RUNSTATE_offline];
+}
+
+static void xen_read_wallclock(struct timespec64 *ts)
+{
+       u32 version;
+       struct timespec64 now, ts_monotonic;
+       struct shared_info *s = HYPERVISOR_shared_info;
+       struct pvclock_wall_clock *wall_clock = &(s->wc);
+
+       /* get wallclock at system boot */
+       do {
+               version = wall_clock->version;
+               rmb();          /* fetch version before time */
+               now.tv_sec  = ((uint64_t)wall_clock->sec_hi << 32) | wall_clock->sec;
+               now.tv_nsec = wall_clock->nsec;
+               rmb();          /* fetch time before checking version */
+       } while ((wall_clock->version & 1) || (version != wall_clock->version));
+
+       /* time since system boot */
+       ktime_get_ts64(&ts_monotonic);
+       *ts = timespec64_add(now, ts_monotonic);
+}
+
+static int xen_pvclock_gtod_notify(struct notifier_block *nb,
+                                  unsigned long was_set, void *priv)
+{
+       /* Protected by the calling core code serialization */
+       static struct timespec64 next_sync;
+
+       struct xen_platform_op op;
+       struct timespec64 now, system_time;
+       struct timekeeper *tk = priv;
+
+       now.tv_sec = tk->xtime_sec;
+       now.tv_nsec = (long)(tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift);
+       system_time = timespec64_add(now, tk->wall_to_monotonic);
+
+       /*
+        * We only take the expensive HV call when the clock was set
+        * or when the 11 minutes RTC synchronization time elapsed.
+        */
+       if (!was_set && timespec64_compare(&now, &next_sync) < 0)
+               return NOTIFY_OK;
+
+       op.cmd = XENPF_settime64;
+       op.u.settime64.mbz = 0;
+       op.u.settime64.secs = now.tv_sec;
+       op.u.settime64.nsecs = now.tv_nsec;
+       op.u.settime64.system_time = timespec64_to_ns(&system_time);
+       (void)HYPERVISOR_platform_op(&op);
+
+       /*
+        * Move the next drift compensation time 11 minutes
+        * ahead. That's emulating the sync_cmos_clock() update for
+        * the hardware RTC.
+        */
+       next_sync = now;
+       next_sync.tv_sec += 11 * 60;
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block xen_pvclock_gtod_notifier = {
+       .notifier_call = xen_pvclock_gtod_notify,
+};
+
 static void xen_percpu_init(void)
 {
        struct vcpu_register_vcpu_info info;
@@ -104,6 +186,8 @@ static void xen_percpu_init(void)
        BUG_ON(err);
        per_cpu(xen_vcpu, cpu) = vcpup;
 
+       xen_setup_runstate_info(cpu);
+
 after_register_vcpu_info:
        enable_percpu_irq(xen_events_irq, 0);
        put_cpu();
@@ -271,6 +355,11 @@ static int __init xen_guest_init(void)
 
        register_cpu_notifier(&xen_cpu_notifier);
 
+       pv_time_ops.steal_clock = xen_stolen_accounting;
+       static_key_slow_inc(&paravirt_steal_enabled);
+       if (xen_initial_domain())
+               pvclock_gtod_register_notifier(&xen_pvclock_gtod_notifier);
+
        return 0;
 }
 early_initcall(xen_guest_init);
@@ -282,6 +371,11 @@ static int __init xen_pm_init(void)
 
        pm_power_off = xen_power_off;
        arm_pm_restart = xen_restart;
+       if (!xen_initial_domain()) {
+               struct timespec64 ts;
+               xen_read_wallclock(&ts);
+               do_settimeofday64(&ts);
+       }
 
        return 0;
 }
@@ -307,5 +401,6 @@ EXPORT_SYMBOL_GPL(HYPERVISOR_memory_op);
 EXPORT_SYMBOL_GPL(HYPERVISOR_physdev_op);
 EXPORT_SYMBOL_GPL(HYPERVISOR_vcpu_op);
 EXPORT_SYMBOL_GPL(HYPERVISOR_tmem_op);
+EXPORT_SYMBOL_GPL(HYPERVISOR_platform_op);
 EXPORT_SYMBOL_GPL(HYPERVISOR_multicall);
 EXPORT_SYMBOL_GPL(privcmd_call);
index 10fd99c568c62a9296b4ad7d2cc3584360b1b8a0..9a36f4f49c10499788d4ec8387297c76da7caadf 100644 (file)
@@ -89,6 +89,7 @@ HYPERCALL2(memory_op);
 HYPERCALL2(physdev_op);
 HYPERCALL3(vcpu_op);
 HYPERCALL1(tmem_op);
+HYPERCALL1(platform_op_raw);
 HYPERCALL2(multicall);
 
 ENTRY(privcmd_call)
index 871f21783866d5fdb1557ec56e5f13b602ba331a..d6ebffdc6bb11dce0d2b6c96a87b976b4de5115b 100644 (file)
@@ -70,6 +70,7 @@ config ARM64
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_GENERIC_DMA_COHERENT
        select HAVE_HW_BREAKPOINT if PERF_EVENTS
+       select HAVE_IRQ_TIME_ACCOUNTING
        select HAVE_MEMBLOCK
        select HAVE_PATA_PLATFORM
        select HAVE_PERF_EVENTS
@@ -92,6 +93,7 @@ config ARM64
        select SPARSE_IRQ
        select SYSCTL_EXCEPTION_TRACE
        select HAVE_CONTEXT_TRACKING
+       select HAVE_ARM_SMCCC
        help
          ARM 64-bit (AArch64) Linux support.
 
@@ -529,9 +531,6 @@ config HW_PERF_EVENTS
 config SYS_SUPPORTS_HUGETLBFS
        def_bool y
 
-config ARCH_WANT_GENERAL_HUGETLB
-       def_bool y
-
 config ARCH_WANT_HUGE_PMD_SHARE
        def_bool y if ARM64_4K_PAGES || (ARM64_16K_PAGES && !ARM64_VA_BITS_36)
 
@@ -556,6 +555,25 @@ config SECCOMP
          and the task is only allowed to execute a few safe syscalls
          defined by each seccomp mode.
 
+config PARAVIRT
+       bool "Enable paravirtualization code"
+       help
+         This changes the kernel so it can modify itself when it is run
+         under a hypervisor, potentially improving performance significantly
+         over full virtualization.
+
+config PARAVIRT_TIME_ACCOUNTING
+       bool "Paravirtual steal time accounting"
+       select PARAVIRT
+       default n
+       help
+         Select this option to enable fine granularity task steal time
+         accounting. Time spent executing other tasks in parallel with
+         the current vCPU is discounted from the vCPU power. To account for
+         that, there can be a small performance impact.
+
+         If in doubt, say N here.
+
 config XEN_DOM0
        def_bool y
        depends on XEN
@@ -564,6 +582,7 @@ config XEN
        bool "Xen guest support on ARM64"
        depends on ARM64 && OF
        select SWIOTLB_XEN
+       select PARAVIRT
        help
          Say Y if you want to run Linux in a Virtual Machine on Xen on ARM64.
 
index d56ec07151570e6e498e9bf35b2fd9ccaed335fe..e4962f04201e295d933d33f7f39745a5f5e65f65 100644 (file)
@@ -19,7 +19,6 @@ struct alt_instr {
 
 void __init apply_alternatives_all(void);
 void apply_alternatives(void *start, size_t length);
-void free_alternatives_memory(void);
 
 #define ALTINSTR_ENTRY(feature)                                                      \
        " .word 661b - .\n"                             /* label           */ \
index 12eff928ef8b38dd18ae3bd157b12eb918f797a6..bb7b72734c24ae5f5572d2b01c70900abe99abcf 100644 (file)
@@ -193,6 +193,17 @@ lr .req    x30             // link register
        str     \src, [\tmp, :lo12:\sym]
        .endm
 
+       /*
+        * @sym: The name of the per-cpu variable
+        * @reg: Result of per_cpu(sym, smp_processor_id())
+        * @tmp: scratch register
+        */
+       .macro this_cpu_ptr, sym, reg, tmp
+       adr_l   \reg, \sym
+       mrs     \tmp, tpidr_el1
+       add     \reg, \reg, \tmp
+       .endm
+
 /*
  * Annotate a function as position independent, i.e., safe to be called before
  * the kernel virtual mapping is activated.
index 54efedaf331fda55478d001d860d6137be5d08e8..7fc294c3bc5baab31b13b1e23753d17835ce3b27 100644 (file)
@@ -68,6 +68,7 @@
 extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
 extern void flush_icache_range(unsigned long start, unsigned long end);
 extern void __flush_dcache_area(void *addr, size_t len);
+extern void __clean_dcache_area_pou(void *addr, size_t len);
 extern long __flush_cache_user_range(unsigned long start, unsigned long end);
 
 static inline void flush_cache_mm(struct mm_struct *mm)
index 9ea611ea69df739009d0a6d432bbbedcab05284b..510c7b4044547f82750ca9295e6d35bdeb0b67bf 100644 (file)
@@ -19,7 +19,6 @@
 #define __ASM_CMPXCHG_H
 
 #include <linux/bug.h>
-#include <linux/mmdebug.h>
 
 #include <asm/atomic.h>
 #include <asm/barrier.h>
index ef572206f1c3eb6658618b40568e662f7e1865fc..8e88a696c9cbcbd2c8f717ea1c929b87750f1b03 100644 (file)
@@ -2,7 +2,9 @@
 #define _ASM_EFI_H
 
 #include <asm/io.h>
+#include <asm/mmu_context.h>
 #include <asm/neon.h>
+#include <asm/tlbflush.h>
 
 #ifdef CONFIG_EFI
 extern void efi_init(void);
@@ -10,6 +12,8 @@ extern void efi_init(void);
 #define efi_init()
 #endif
 
+int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
+
 #define efi_call_virt(f, ...)                                          \
 ({                                                                     \
        efi_##f##_t *__f;                                               \
@@ -63,6 +67,11 @@ extern void efi_init(void);
  *   Services are enabled and the EFI_RUNTIME_SERVICES bit set.
  */
 
+static inline void efi_set_pgd(struct mm_struct *mm)
+{
+       switch_mm(NULL, mm, NULL);
+}
+
 void efi_virtmap_load(void);
 void efi_virtmap_unload(void);
 
index c5534facf9416fefbec606ad8f320f023f662ce7..3c60f37e48ab51998db2c5870fe2df4427949b37 100644 (file)
@@ -28,6 +28,8 @@ struct dyn_arch_ftrace {
 
 extern unsigned long ftrace_graph_call;
 
+extern void return_to_handler(void);
+
 static inline unsigned long ftrace_call_adjust(unsigned long addr)
 {
        /*
index bb4052e85dbac913c1670fd622f66a6c47909fd8..bbc1e35aa6014c8ea83a1c06acbea83da250121d 100644 (file)
@@ -26,36 +26,7 @@ static inline pte_t huge_ptep_get(pte_t *ptep)
        return *ptep;
 }
 
-static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
-                                  pte_t *ptep, pte_t pte)
-{
-       set_pte_at(mm, addr, ptep, pte);
-}
-
-static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
-                                        unsigned long addr, pte_t *ptep)
-{
-       ptep_clear_flush(vma, addr, ptep);
-}
-
-static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
-                                          unsigned long addr, pte_t *ptep)
-{
-       ptep_set_wrprotect(mm, addr, ptep);
-}
 
-static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
-                                           unsigned long addr, pte_t *ptep)
-{
-       return ptep_get_and_clear(mm, addr, ptep);
-}
-
-static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
-                                            unsigned long addr, pte_t *ptep,
-                                            pte_t pte, int dirty)
-{
-       return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
-}
 
 static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
                                          unsigned long addr, unsigned long end,
@@ -97,4 +68,19 @@ static inline void arch_clear_hugepage_flags(struct page *page)
        clear_bit(PG_dcache_clean, &page->flags);
 }
 
+extern pte_t arch_make_huge_pte(pte_t entry, struct vm_area_struct *vma,
+                               struct page *page, int writable);
+#define arch_make_huge_pte arch_make_huge_pte
+extern void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+                           pte_t *ptep, pte_t pte);
+extern int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+                                     unsigned long addr, pte_t *ptep,
+                                     pte_t pte, int dirty);
+extern pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
+                                    unsigned long addr, pte_t *ptep);
+extern void huge_ptep_set_wrprotect(struct mm_struct *mm,
+                                   unsigned long addr, pte_t *ptep);
+extern void huge_ptep_clear_flush(struct vm_area_struct *vma,
+                                 unsigned long addr, pte_t *ptep);
+
 #endif /* __ASM_HUGETLB_H */
index 8e8d30684392b1065b0c5d1f65e7715e4028331c..b77197d941fc442c4bad04b185d5cf786ca9fea5 100644 (file)
@@ -1,10 +1,45 @@
 #ifndef __ASM_IRQ_H
 #define __ASM_IRQ_H
 
+#define IRQ_STACK_SIZE                 THREAD_SIZE
+#define IRQ_STACK_START_SP             THREAD_START_SP
+
+#ifndef __ASSEMBLER__
+
+#include <linux/percpu.h>
+
 #include <asm-generic/irq.h>
+#include <asm/thread_info.h>
 
 struct pt_regs;
 
+DECLARE_PER_CPU(unsigned long [IRQ_STACK_SIZE/sizeof(long)], irq_stack);
+
+/*
+ * The highest address on the stack, and the first to be used. Used to
+ * find the dummy-stack frame put down by el?_irq() in entry.S, which
+ * is structured as follows:
+ *
+ *       ------------
+ *       |          |  <- irq_stack_ptr
+ *   top ------------
+ *       |   x19    | <- irq_stack_ptr - 0x08
+ *       ------------
+ *       |   x29    | <- irq_stack_ptr - 0x10
+ *       ------------
+ *
+ * where x19 holds a copy of the task stack pointer where the struct pt_regs
+ * from kernel_entry can be found.
+ *
+ */
+#define IRQ_STACK_PTR(cpu) ((unsigned long)per_cpu(irq_stack, cpu) + IRQ_STACK_START_SP)
+
+/*
+ * The offset from irq_stack_ptr where entry.S will store the original
+ * stack pointer. Used by unwind_frame() and dump_backtrace().
+ */
+#define IRQ_STACK_TO_TASK_STACK(ptr) (*((unsigned long *)((ptr) - 0x08)))
+
 extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
 
 static inline int nr_legacy_irqs(void)
@@ -12,4 +47,14 @@ static inline int nr_legacy_irqs(void)
        return 0;
 }
 
+static inline bool on_irq_stack(unsigned long sp, int cpu)
+{
+       /* variable names the same as kernel/stacktrace.c */
+       unsigned long low = (unsigned long)per_cpu(irq_stack, cpu);
+       unsigned long high = low + IRQ_STACK_START_SP;
+
+       return (low <= sp && sp <= high);
+}
+
+#endif /* !__ASSEMBLER__ */
 #endif
index 5e6857b6bdc45cc100d293cbdf1e3d683a4763e7..738a95f93e493e3002ac8749857f8599c5ae3404 100644 (file)
 #define VTCR_EL2_SL0_LVL1      (1 << 6)
 #define VTCR_EL2_T0SZ_MASK     0x3f
 #define VTCR_EL2_T0SZ_40B      24
+#define VTCR_EL2_VS            19
 
 /*
  * We configure the Stage-2 page tables to always restrict the IPA space to be
 #define VTTBR_BADDR_SHIFT (VTTBR_X - 1)
 #define VTTBR_BADDR_MASK  (((UL(1) << (PHYS_MASK_SHIFT - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT)
 #define VTTBR_VMID_SHIFT  (UL(48))
-#define VTTBR_VMID_MASK          (UL(0xFF) << VTTBR_VMID_SHIFT)
+#define VTTBR_VMID_MASK(size) (_AT(u64, (1 << size) - 1) << VTTBR_VMID_SHIFT)
 
 /* Hyp System Trap Register */
 #define HSTR_EL2_T(x)  (1 << x)
index 5e377101f91948f9ee711bea3f7659c86010301c..52b777b7d407cfd9c2fe5036c1c7ae96bf025c0b 100644 (file)
 
 #include <asm/virt.h>
 
-/*
- * 0 is reserved as an invalid value.
- * Order *must* be kept in sync with the hyp switch code.
- */
-#define        MPIDR_EL1       1       /* MultiProcessor Affinity Register */
-#define        CSSELR_EL1      2       /* Cache Size Selection Register */
-#define        SCTLR_EL1       3       /* System Control Register */
-#define        ACTLR_EL1       4       /* Auxiliary Control Register */
-#define        CPACR_EL1       5       /* Coprocessor Access Control */
-#define        TTBR0_EL1       6       /* Translation Table Base Register 0 */
-#define        TTBR1_EL1       7       /* Translation Table Base Register 1 */
-#define        TCR_EL1         8       /* Translation Control Register */
-#define        ESR_EL1         9       /* Exception Syndrome Register */
-#define        AFSR0_EL1       10      /* Auxilary Fault Status Register 0 */
-#define        AFSR1_EL1       11      /* Auxilary Fault Status Register 1 */
-#define        FAR_EL1         12      /* Fault Address Register */
-#define        MAIR_EL1        13      /* Memory Attribute Indirection Register */
-#define        VBAR_EL1        14      /* Vector Base Address Register */
-#define        CONTEXTIDR_EL1  15      /* Context ID Register */
-#define        TPIDR_EL0       16      /* Thread ID, User R/W */
-#define        TPIDRRO_EL0     17      /* Thread ID, User R/O */
-#define        TPIDR_EL1       18      /* Thread ID, Privileged */
-#define        AMAIR_EL1       19      /* Aux Memory Attribute Indirection Register */
-#define        CNTKCTL_EL1     20      /* Timer Control Register (EL1) */
-#define        PAR_EL1         21      /* Physical Address Register */
-#define MDSCR_EL1      22      /* Monitor Debug System Control Register */
-#define MDCCINT_EL1    23      /* Monitor Debug Comms Channel Interrupt Enable Reg */
-
-/* 32bit specific registers. Keep them at the end of the range */
-#define        DACR32_EL2      24      /* Domain Access Control Register */
-#define        IFSR32_EL2      25      /* Instruction Fault Status Register */
-#define        FPEXC32_EL2     26      /* Floating-Point Exception Control Register */
-#define        DBGVCR32_EL2    27      /* Debug Vector Catch Register */
-#define        NR_SYS_REGS     28
-
-/* 32bit mapping */
-#define c0_MPIDR       (MPIDR_EL1 * 2) /* MultiProcessor ID Register */
-#define c0_CSSELR      (CSSELR_EL1 * 2)/* Cache Size Selection Register */
-#define c1_SCTLR       (SCTLR_EL1 * 2) /* System Control Register */
-#define c1_ACTLR       (ACTLR_EL1 * 2) /* Auxiliary Control Register */
-#define c1_CPACR       (CPACR_EL1 * 2) /* Coprocessor Access Control */
-#define c2_TTBR0       (TTBR0_EL1 * 2) /* Translation Table Base Register 0 */
-#define c2_TTBR0_high  (c2_TTBR0 + 1)  /* TTBR0 top 32 bits */
-#define c2_TTBR1       (TTBR1_EL1 * 2) /* Translation Table Base Register 1 */
-#define c2_TTBR1_high  (c2_TTBR1 + 1)  /* TTBR1 top 32 bits */
-#define c2_TTBCR       (TCR_EL1 * 2)   /* Translation Table Base Control R. */
-#define c3_DACR                (DACR32_EL2 * 2)/* Domain Access Control Register */
-#define c5_DFSR                (ESR_EL1 * 2)   /* Data Fault Status Register */
-#define c5_IFSR                (IFSR32_EL2 * 2)/* Instruction Fault Status Register */
-#define c5_ADFSR       (AFSR0_EL1 * 2) /* Auxiliary Data Fault Status R */
-#define c5_AIFSR       (AFSR1_EL1 * 2) /* Auxiliary Instr Fault Status R */
-#define c6_DFAR                (FAR_EL1 * 2)   /* Data Fault Address Register */
-#define c6_IFAR                (c6_DFAR + 1)   /* Instruction Fault Address Register */
-#define c7_PAR         (PAR_EL1 * 2)   /* Physical Address Register */
-#define c7_PAR_high    (c7_PAR + 1)    /* PAR top 32 bits */
-#define c10_PRRR       (MAIR_EL1 * 2)  /* Primary Region Remap Register */
-#define c10_NMRR       (c10_PRRR + 1)  /* Normal Memory Remap Register */
-#define c12_VBAR       (VBAR_EL1 * 2)  /* Vector Base Address Register */
-#define c13_CID                (CONTEXTIDR_EL1 * 2)    /* Context ID Register */
-#define c13_TID_URW    (TPIDR_EL0 * 2) /* Thread ID, User R/W */
-#define c13_TID_URO    (TPIDRRO_EL0 * 2)/* Thread ID, User R/O */
-#define c13_TID_PRIV   (TPIDR_EL1 * 2) /* Thread ID, Privileged */
-#define c10_AMAIR0     (AMAIR_EL1 * 2) /* Aux Memory Attr Indirection Reg */
-#define c10_AMAIR1     (c10_AMAIR0 + 1)/* Aux Memory Attr Indirection Reg */
-#define c14_CNTKCTL    (CNTKCTL_EL1 * 2) /* Timer Control Register (PL1) */
-
-#define cp14_DBGDSCRext        (MDSCR_EL1 * 2)
-#define cp14_DBGBCR0   (DBGBCR0_EL1 * 2)
-#define cp14_DBGBVR0   (DBGBVR0_EL1 * 2)
-#define cp14_DBGBXVR0  (cp14_DBGBVR0 + 1)
-#define cp14_DBGWCR0   (DBGWCR0_EL1 * 2)
-#define cp14_DBGWVR0   (DBGWVR0_EL1 * 2)
-#define cp14_DBGDCCINT (MDCCINT_EL1 * 2)
-
-#define NR_COPRO_REGS  (NR_SYS_REGS * 2)
-
 #define ARM_EXCEPTION_IRQ        0
 #define ARM_EXCEPTION_TRAP       1
 
index 25a40213bd9b87cb6802ecfd4204dc66c41e5850..3066328cd86b69a91274e0cb841059b428666140 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <asm/esr.h>
 #include <asm/kvm_arm.h>
-#include <asm/kvm_asm.h>
 #include <asm/kvm_mmio.h>
 #include <asm/ptrace.h>
 #include <asm/cputype.h>
index a35ce7266aac3688fa6460bace61f90477448aa6..689d4c95e12fbd0dd7c1cf7ca9521918f37aaab0 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/types.h>
 #include <linux/kvm_types.h>
 #include <asm/kvm.h>
-#include <asm/kvm_asm.h>
 #include <asm/kvm_mmio.h>
 
 #define __KVM_HAVE_ARCH_INTC_INITIALIZED
@@ -85,6 +84,86 @@ struct kvm_vcpu_fault_info {
        u64 hpfar_el2;          /* Hyp IPA Fault Address Register */
 };
 
+/*
+ * 0 is reserved as an invalid value.
+ * Order should be kept in sync with the save/restore code.
+ */
+enum vcpu_sysreg {
+       __INVALID_SYSREG__,
+       MPIDR_EL1,      /* MultiProcessor Affinity Register */
+       CSSELR_EL1,     /* Cache Size Selection Register */
+       SCTLR_EL1,      /* System Control Register */
+       ACTLR_EL1,      /* Auxiliary Control Register */
+       CPACR_EL1,      /* Coprocessor Access Control */
+       TTBR0_EL1,      /* Translation Table Base Register 0 */
+       TTBR1_EL1,      /* Translation Table Base Register 1 */
+       TCR_EL1,        /* Translation Control Register */
+       ESR_EL1,        /* Exception Syndrome Register */
+       AFSR0_EL1,      /* Auxilary Fault Status Register 0 */
+       AFSR1_EL1,      /* Auxilary Fault Status Register 1 */
+       FAR_EL1,        /* Fault Address Register */
+       MAIR_EL1,       /* Memory Attribute Indirection Register */
+       VBAR_EL1,       /* Vector Base Address Register */
+       CONTEXTIDR_EL1, /* Context ID Register */
+       TPIDR_EL0,      /* Thread ID, User R/W */
+       TPIDRRO_EL0,    /* Thread ID, User R/O */
+       TPIDR_EL1,      /* Thread ID, Privileged */
+       AMAIR_EL1,      /* Aux Memory Attribute Indirection Register */
+       CNTKCTL_EL1,    /* Timer Control Register (EL1) */
+       PAR_EL1,        /* Physical Address Register */
+       MDSCR_EL1,      /* Monitor Debug System Control Register */
+       MDCCINT_EL1,    /* Monitor Debug Comms Channel Interrupt Enable Reg */
+
+       /* 32bit specific registers. Keep them at the end of the range */
+       DACR32_EL2,     /* Domain Access Control Register */
+       IFSR32_EL2,     /* Instruction Fault Status Register */
+       FPEXC32_EL2,    /* Floating-Point Exception Control Register */
+       DBGVCR32_EL2,   /* Debug Vector Catch Register */
+
+       NR_SYS_REGS     /* Nothing after this line! */
+};
+
+/* 32bit mapping */
+#define c0_MPIDR       (MPIDR_EL1 * 2) /* MultiProcessor ID Register */
+#define c0_CSSELR      (CSSELR_EL1 * 2)/* Cache Size Selection Register */
+#define c1_SCTLR       (SCTLR_EL1 * 2) /* System Control Register */
+#define c1_ACTLR       (ACTLR_EL1 * 2) /* Auxiliary Control Register */
+#define c1_CPACR       (CPACR_EL1 * 2) /* Coprocessor Access Control */
+#define c2_TTBR0       (TTBR0_EL1 * 2) /* Translation Table Base Register 0 */
+#define c2_TTBR0_high  (c2_TTBR0 + 1)  /* TTBR0 top 32 bits */
+#define c2_TTBR1       (TTBR1_EL1 * 2) /* Translation Table Base Register 1 */
+#define c2_TTBR1_high  (c2_TTBR1 + 1)  /* TTBR1 top 32 bits */
+#define c2_TTBCR       (TCR_EL1 * 2)   /* Translation Table Base Control R. */
+#define c3_DACR                (DACR32_EL2 * 2)/* Domain Access Control Register */
+#define c5_DFSR                (ESR_EL1 * 2)   /* Data Fault Status Register */
+#define c5_IFSR                (IFSR32_EL2 * 2)/* Instruction Fault Status Register */
+#define c5_ADFSR       (AFSR0_EL1 * 2) /* Auxiliary Data Fault Status R */
+#define c5_AIFSR       (AFSR1_EL1 * 2) /* Auxiliary Instr Fault Status R */
+#define c6_DFAR                (FAR_EL1 * 2)   /* Data Fault Address Register */
+#define c6_IFAR                (c6_DFAR + 1)   /* Instruction Fault Address Register */
+#define c7_PAR         (PAR_EL1 * 2)   /* Physical Address Register */
+#define c7_PAR_high    (c7_PAR + 1)    /* PAR top 32 bits */
+#define c10_PRRR       (MAIR_EL1 * 2)  /* Primary Region Remap Register */
+#define c10_NMRR       (c10_PRRR + 1)  /* Normal Memory Remap Register */
+#define c12_VBAR       (VBAR_EL1 * 2)  /* Vector Base Address Register */
+#define c13_CID                (CONTEXTIDR_EL1 * 2)    /* Context ID Register */
+#define c13_TID_URW    (TPIDR_EL0 * 2) /* Thread ID, User R/W */
+#define c13_TID_URO    (TPIDRRO_EL0 * 2)/* Thread ID, User R/O */
+#define c13_TID_PRIV   (TPIDR_EL1 * 2) /* Thread ID, Privileged */
+#define c10_AMAIR0     (AMAIR_EL1 * 2) /* Aux Memory Attr Indirection Reg */
+#define c10_AMAIR1     (c10_AMAIR0 + 1)/* Aux Memory Attr Indirection Reg */
+#define c14_CNTKCTL    (CNTKCTL_EL1 * 2) /* Timer Control Register (PL1) */
+
+#define cp14_DBGDSCRext        (MDSCR_EL1 * 2)
+#define cp14_DBGBCR0   (DBGBCR0_EL1 * 2)
+#define cp14_DBGBVR0   (DBGBVR0_EL1 * 2)
+#define cp14_DBGBXVR0  (cp14_DBGBVR0 + 1)
+#define cp14_DBGWCR0   (DBGWCR0_EL1 * 2)
+#define cp14_DBGWVR0   (DBGWVR0_EL1 * 2)
+#define cp14_DBGDCCINT (MDCCINT_EL1 * 2)
+
+#define NR_COPRO_REGS  (NR_SYS_REGS * 2)
+
 struct kvm_cpu_context {
        struct kvm_regs gp_regs;
        union {
@@ -197,6 +276,12 @@ struct kvm_vcpu_stat {
        u32 halt_successful_poll;
        u32 halt_attempted_poll;
        u32 halt_wakeup;
+       u32 hvc_exit_stat;
+       u64 wfe_exit_stat;
+       u64 wfi_exit_stat;
+       u64 mmio_exit_user;
+       u64 mmio_exit_kernel;
+       u64 exits;
 };
 
 int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init);
index 889c908ee631b526594b5dfc32ef5dfde15480df..fe612a9625766b5fff3698e2d1014d7376744e4f 100644 (file)
@@ -19,7 +19,6 @@
 #define __ARM64_KVM_MMIO_H__
 
 #include <linux/kvm_host.h>
-#include <asm/kvm_asm.h>
 #include <asm/kvm_arm.h>
 
 /*
index 61505676d0853bb65710fc9ad7746db8f58e4658..0bf8b4320a9154fda9e6fd3d999ef37a356bee85 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <asm/page.h>
 #include <asm/memory.h>
+#include <asm/cpufeature.h>
 
 /*
  * As we only have the TTBR0_EL2 register, we cannot express
@@ -158,7 +159,6 @@ static inline bool kvm_s2pmd_readonly(pmd_t *pmd)
 #define PTRS_PER_S2_PGD_SHIFT  (KVM_PHYS_SHIFT - PGDIR_SHIFT)
 #endif
 #define PTRS_PER_S2_PGD                (1 << PTRS_PER_S2_PGD_SHIFT)
-#define S2_PGD_ORDER           get_order(PTRS_PER_S2_PGD * sizeof(pgd_t))
 
 #define kvm_pgd_index(addr)    (((addr) >> PGDIR_SHIFT) & (PTRS_PER_S2_PGD - 1))
 
@@ -302,5 +302,12 @@ static inline void __kvm_extend_hypmap(pgd_t *boot_hyp_pgd,
        merged_hyp_pgd[idmap_idx] = __pgd(__pa(boot_hyp_pgd) | PMD_TYPE_TABLE);
 }
 
+static inline unsigned int kvm_get_vmid_bits(void)
+{
+       int reg = read_system_reg(SYS_ID_AA64MMFR1_EL1);
+
+       return (cpuid_feature_extract_field(reg, ID_AA64MMFR1_VMIDBITS_SHIFT) == 2) ? 16 : 8;
+}
+
 #endif /* __ASSEMBLY__ */
 #endif /* __ARM64_KVM_MMU_H__ */
diff --git a/arch/arm64/include/asm/paravirt.h b/arch/arm64/include/asm/paravirt.h
new file mode 100644 (file)
index 0000000..fd5f428
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _ASM_ARM64_PARAVIRT_H
+#define _ASM_ARM64_PARAVIRT_H
+
+#ifdef CONFIG_PARAVIRT
+struct static_key;
+extern struct static_key paravirt_steal_enabled;
+extern struct static_key paravirt_steal_rq_enabled;
+
+struct pv_time_ops {
+       unsigned long long (*steal_clock)(int cpu);
+};
+extern struct pv_time_ops pv_time_ops;
+
+static inline u64 paravirt_steal_clock(int cpu)
+{
+       return pv_time_ops.steal_clock(cpu);
+}
+#endif
+
+#endif
index d6739e836f7bb919a7e49b7e14fc43d2454f46de..5c25b831273dbfaa183a769a108331df43a9c498 100644 (file)
 /*
  * Contiguous page definitions.
  */
-#define CONT_PTES              (_AC(1, UL) << CONT_SHIFT)
+#ifdef CONFIG_ARM64_64K_PAGES
+#define CONT_PTE_SHIFT         5
+#define CONT_PMD_SHIFT         5
+#elif defined(CONFIG_ARM64_16K_PAGES)
+#define CONT_PTE_SHIFT         7
+#define CONT_PMD_SHIFT         5
+#else
+#define CONT_PTE_SHIFT         4
+#define CONT_PMD_SHIFT         4
+#endif
+
+#define CONT_PTES              (1 << CONT_PTE_SHIFT)
+#define CONT_PTE_SIZE          (CONT_PTES * PAGE_SIZE)
+#define CONT_PTE_MASK          (~(CONT_PTE_SIZE - 1))
+#define CONT_PMDS              (1 << CONT_PMD_SHIFT)
+#define CONT_PMD_SIZE          (CONT_PMDS * PMD_SIZE)
+#define CONT_PMD_MASK          (~(CONT_PMD_SIZE - 1))
 /* the the numerical offset of the PTE within a range of CONT_PTES */
 #define CONT_RANGE_OFFSET(addr) (((addr)>>PAGE_SHIFT)&(CONT_PTES-1))
 
index 63f52b55defe1041a7913217db490528c441c6f3..69d2e2f86bce3f65a76637e9ab3cd9251d6f3d16 100644 (file)
@@ -167,6 +167,16 @@ extern struct page *empty_zero_page;
        ((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER))
 #define pte_valid_not_user(pte) \
        ((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
+#define pte_valid_young(pte) \
+       ((pte_val(pte) & (PTE_VALID | PTE_AF)) == (PTE_VALID | PTE_AF))
+
+/*
+ * Could the pte be present in the TLB? We must check mm_tlb_flush_pending
+ * so that we don't erroneously return false for pages that have been
+ * remapped as PROT_NONE but are yet to be flushed from the TLB.
+ */
+#define pte_accessible(mm, pte)        \
+       (mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid_young(pte))
 
 static inline pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
 {
@@ -217,7 +227,8 @@ static inline pte_t pte_mkspecial(pte_t pte)
 
 static inline pte_t pte_mkcont(pte_t pte)
 {
-       return set_pte_bit(pte, __pgprot(PTE_CONT));
+       pte = set_pte_bit(pte, __pgprot(PTE_CONT));
+       return set_pte_bit(pte, __pgprot(PTE_TYPE_PAGE));
 }
 
 static inline pte_t pte_mknoncont(pte_t pte)
@@ -225,6 +236,11 @@ static inline pte_t pte_mknoncont(pte_t pte)
        return clear_pte_bit(pte, __pgprot(PTE_CONT));
 }
 
+static inline pmd_t pmd_mkcont(pmd_t pmd)
+{
+       return __pmd(pmd_val(pmd) | PMD_SECT_CONT);
+}
+
 static inline void set_pte(pte_t *ptep, pte_t pte)
 {
        *ptep = pte;
@@ -298,7 +314,7 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
 /*
  * Hugetlb definitions.
  */
-#define HUGE_MAX_HSTATE                2
+#define HUGE_MAX_HSTATE                4
 #define HPAGE_SHIFT            PMD_SHIFT
 #define HPAGE_SIZE             (_AC(1, UL) << HPAGE_SHIFT)
 #define HPAGE_MASK             (~(HPAGE_SIZE - 1))
@@ -664,7 +680,8 @@ extern int kern_addr_valid(unsigned long addr);
 
 #include <asm-generic/pgtable.h>
 
-#define pgtable_cache_init() do { } while (0)
+void pgd_cache_init(void);
+#define pgtable_cache_init     pgd_cache_init
 
 /*
  * On AArch64, the cache coherency is handled via the set_pte_at() function.
index 4df608a8459e27c657055edd5ca519b34e755b80..e368a55ebd22d0c3dab4a690afdd33d62c76ef73 100644 (file)
@@ -21,7 +21,7 @@
  * alignment value. Since we don't have aliasing D-caches, the rest of
  * the time we can safely use PAGE_SIZE.
  */
-#define COMPAT_SHMLBA  0x4000
+#define COMPAT_SHMLBA  (4 * PAGE_SIZE)
 
 #include <asm-generic/shmparam.h>
 
index c85e96d174a5fbd4764adb748b9bc11c70479617..fc9682bfe0020caebf99412131fb760d5b8b870d 100644 (file)
  * The memory barriers are implicit with the load-acquire and store-release
  * instructions.
  */
+static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
+{
+       unsigned int tmp;
+       arch_spinlock_t lockval;
 
-#define arch_spin_unlock_wait(lock) \
-       do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0)
+       asm volatile(
+"      sevl\n"
+"1:    wfe\n"
+"2:    ldaxr   %w0, %2\n"
+"      eor     %w1, %w0, %w0, ror #16\n"
+"      cbnz    %w1, 1b\n"
+       ARM64_LSE_ATOMIC_INSN(
+       /* LL/SC */
+"      stxr    %w1, %w0, %2\n"
+"      cbnz    %w1, 2b\n", /* Serialise against any concurrent lockers */
+       /* LSE atomics */
+"      nop\n"
+"      nop\n")
+       : "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
+       :
+       : "memory");
+}
 
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
index 7318f6d54aa949ca906a990cce357a4cdd1358db..801a16dbbdf622d5239cf61be4f67eccab5c1e09 100644 (file)
 #ifndef __ASM_STACKTRACE_H
 #define __ASM_STACKTRACE_H
 
+struct task_struct;
+
 struct stackframe {
        unsigned long fp;
        unsigned long sp;
        unsigned long pc;
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       unsigned int graph;
+#endif
 };
 
-extern int unwind_frame(struct stackframe *frame);
-extern void walk_stackframe(struct stackframe *frame,
+extern int unwind_frame(struct task_struct *tsk, struct stackframe *frame);
+extern void walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
                            int (*fn)(struct stackframe *, void *), void *data);
 
 #endif /* __ASM_STACKTRACE_H */
index d48ab5b41f521c23819c0b3927a9ea0f73db242c..4aeebec3d8828431a59b757f421b6260511f3455 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef __ASM_SYSREG_H
 #define __ASM_SYSREG_H
 
+#include <linux/stringify.h>
+
 #include <asm/opcodes.h>
 
 /*
 
 #else
 
+#include <linux/types.h>
+
 asm(
 "      .irp    num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n"
 "      .equ    __reg_num_x\\num, \\num\n"
@@ -232,6 +236,23 @@ static inline void config_sctlr_el1(u32 clear, u32 set)
        val |= set;
        asm volatile("msr sctlr_el1, %0" : : "r" (val));
 }
+
+/*
+ * Unlike read_cpuid, calls to read_sysreg are never expected to be
+ * optimized away or replaced with synthetic values.
+ */
+#define read_sysreg(r) ({                                      \
+       u64 __val;                                              \
+       asm volatile("mrs %0, " __stringify(r) : "=r" (__val)); \
+       __val;                                                  \
+})
+
+#define write_sysreg(v, r) do {                                        \
+       u64 __val = (u64)v;                                     \
+       asm volatile("msr " __stringify(r) ", %0"               \
+                    : : "r" (__val));                          \
+} while (0)
+
 #endif
 
 #endif /* __ASM_SYSREG_H */
index 90c7ff233735d7691bf3b34b7075dffd07dbf939..abd64bd1f6d9f0160a3122555cf23be1a30f87eb 100644 (file)
@@ -73,10 +73,16 @@ register unsigned long current_stack_pointer asm ("sp");
  */
 static inline struct thread_info *current_thread_info(void) __attribute_const__;
 
+/*
+ * struct thread_info can be accessed directly via sp_el0.
+ */
 static inline struct thread_info *current_thread_info(void)
 {
-       return (struct thread_info *)
-               (current_stack_pointer & ~(THREAD_SIZE - 1));
+       unsigned long sp_el0;
+
+       asm ("mrs %0, sp_el0" : "=r" (sp_el0));
+
+       return (struct thread_info *)sp_el0;
 }
 
 #define thread_saved_pc(tsk)   \
index 474691f8b13ab893cf403b8c1737a91aeff87bc0..83cd7e68e83b2e59740b8e56268b7f0a2604aa63 100644 (file)
@@ -14,10 +14,10 @@ CFLAGS_REMOVE_return_address.o = -pg
 arm64-obj-y            := debug-monitors.o entry.o irq.o fpsimd.o              \
                           entry-fpsimd.o process.o ptrace.o setup.o signal.o   \
                           sys.o stacktrace.o time.o traps.o io.o vdso.o        \
-                          hyp-stub.o psci.o psci-call.o cpu_ops.o insn.o       \
+                          hyp-stub.o psci.o cpu_ops.o insn.o   \
                           return_address.o cpuinfo.o cpu_errata.o              \
                           cpufeature.o alternative.o cacheinfo.o               \
-                          smp.o smp_spin_table.o topology.o
+                          smp.o smp_spin_table.o topology.o smccc-call.o
 
 extra-$(CONFIG_EFI)                    := efi-entry.o
 
@@ -41,6 +41,7 @@ arm64-obj-$(CONFIG_EFI)                       += efi.o efi-entry.stub.o
 arm64-obj-$(CONFIG_PCI)                        += pci.o
 arm64-obj-$(CONFIG_ARMV8_DEPRECATED)   += armv8_deprecated.o
 arm64-obj-$(CONFIG_ACPI)               += acpi.o
+arm64-obj-$(CONFIG_PARAVIRT)           += paravirt.o
 
 obj-y                                  += $(arm64-obj-y) vdso/
 obj-m                                  += $(arm64-obj-m)
index ab9db0e9818c0caa52aa040b7c01aa83183d774e..d2ee1b21a10ddd1bcce1718210c6ce7b7725cfe3 100644 (file)
@@ -158,9 +158,3 @@ void apply_alternatives(void *start, size_t length)
 
        __apply_alternatives(&region);
 }
-
-void free_alternatives_memory(void)
-{
-       free_reserved_area(__alt_instructions, __alt_instructions_end,
-                          0, "alternatives");
-}
index 3b6d8cc9dfe00ce14b764a3102ad0cd73f546c82..678f30b05a45580a7805b42a8cea235431b93bda 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/syscalls.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
+#include <linux/arm-smccc.h>
 
 #include <asm/checksum.h>
 
@@ -68,3 +69,7 @@ EXPORT_SYMBOL(test_and_change_bit);
 #ifdef CONFIG_FUNCTION_TRACER
 EXPORT_SYMBOL(_mcount);
 #endif
+
+       /* arm-smccc */
+EXPORT_SYMBOL(arm_smccc_smc);
+EXPORT_SYMBOL(arm_smccc_hvc);
index 937f5e58a4d340a27234c76b5a84fedcf9aa6373..3e01207917b13db999b08d36cb722c153ad8cd7f 100644 (file)
@@ -62,7 +62,7 @@ struct insn_emulation {
 };
 
 static LIST_HEAD(insn_emulation);
-static int nr_insn_emulated;
+static int nr_insn_emulated __initdata;
 static DEFINE_RAW_SPINLOCK(insn_emulation_lock);
 
 static void register_emulation_hooks(struct insn_emulation_ops *ops)
@@ -173,7 +173,7 @@ static int update_insn_emulation_mode(struct insn_emulation *insn,
        return ret;
 }
 
-static void register_insn_emulation(struct insn_emulation_ops *ops)
+static void __init register_insn_emulation(struct insn_emulation_ops *ops)
 {
        unsigned long flags;
        struct insn_emulation *insn;
@@ -237,7 +237,7 @@ static struct ctl_table ctl_abi[] = {
        { }
 };
 
-static void register_insn_emulation_sysctl(struct ctl_table *table)
+static void __init register_insn_emulation_sysctl(struct ctl_table *table)
 {
        unsigned long flags;
        int i = 0;
index 25de8b244961312c4b55c02ffdc1e91e0e765b6c..fffa4ac6c25a31a8dc7b2d1865b6c2f459aa64f5 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/suspend.h>
 #include <asm/vdso_datapage.h>
 #include <linux/kbuild.h>
+#include <linux/arm-smccc.h>
 
 int main(void)
 {
@@ -108,49 +109,11 @@ int main(void)
   DEFINE(CPU_GP_REGS,          offsetof(struct kvm_cpu_context, gp_regs));
   DEFINE(CPU_USER_PT_REGS,     offsetof(struct kvm_regs, regs));
   DEFINE(CPU_FP_REGS,          offsetof(struct kvm_regs, fp_regs));
-  DEFINE(CPU_SP_EL1,           offsetof(struct kvm_regs, sp_el1));
-  DEFINE(CPU_ELR_EL1,          offsetof(struct kvm_regs, elr_el1));
-  DEFINE(CPU_SPSR,             offsetof(struct kvm_regs, spsr));
-  DEFINE(CPU_SYSREGS,          offsetof(struct kvm_cpu_context, sys_regs));
+  DEFINE(VCPU_FPEXC32_EL2,     offsetof(struct kvm_vcpu, arch.ctxt.sys_regs[FPEXC32_EL2]));
   DEFINE(VCPU_ESR_EL2,         offsetof(struct kvm_vcpu, arch.fault.esr_el2));
   DEFINE(VCPU_FAR_EL2,         offsetof(struct kvm_vcpu, arch.fault.far_el2));
   DEFINE(VCPU_HPFAR_EL2,       offsetof(struct kvm_vcpu, arch.fault.hpfar_el2));
-  DEFINE(VCPU_DEBUG_FLAGS,     offsetof(struct kvm_vcpu, arch.debug_flags));
-  DEFINE(VCPU_DEBUG_PTR,       offsetof(struct kvm_vcpu, arch.debug_ptr));
-  DEFINE(DEBUG_BCR,            offsetof(struct kvm_guest_debug_arch, dbg_bcr));
-  DEFINE(DEBUG_BVR,            offsetof(struct kvm_guest_debug_arch, dbg_bvr));
-  DEFINE(DEBUG_WCR,            offsetof(struct kvm_guest_debug_arch, dbg_wcr));
-  DEFINE(DEBUG_WVR,            offsetof(struct kvm_guest_debug_arch, dbg_wvr));
-  DEFINE(VCPU_HCR_EL2,         offsetof(struct kvm_vcpu, arch.hcr_el2));
-  DEFINE(VCPU_MDCR_EL2,        offsetof(struct kvm_vcpu, arch.mdcr_el2));
-  DEFINE(VCPU_IRQ_LINES,       offsetof(struct kvm_vcpu, arch.irq_lines));
   DEFINE(VCPU_HOST_CONTEXT,    offsetof(struct kvm_vcpu, arch.host_cpu_context));
-  DEFINE(VCPU_HOST_DEBUG_STATE, offsetof(struct kvm_vcpu, arch.host_debug_state));
-  DEFINE(VCPU_TIMER_CNTV_CTL,  offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_ctl));
-  DEFINE(VCPU_TIMER_CNTV_CVAL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_cval));
-  DEFINE(KVM_TIMER_CNTVOFF,    offsetof(struct kvm, arch.timer.cntvoff));
-  DEFINE(KVM_TIMER_ENABLED,    offsetof(struct kvm, arch.timer.enabled));
-  DEFINE(VCPU_KVM,             offsetof(struct kvm_vcpu, kvm));
-  DEFINE(VCPU_VGIC_CPU,                offsetof(struct kvm_vcpu, arch.vgic_cpu));
-  DEFINE(VGIC_V2_CPU_HCR,      offsetof(struct vgic_cpu, vgic_v2.vgic_hcr));
-  DEFINE(VGIC_V2_CPU_VMCR,     offsetof(struct vgic_cpu, vgic_v2.vgic_vmcr));
-  DEFINE(VGIC_V2_CPU_MISR,     offsetof(struct vgic_cpu, vgic_v2.vgic_misr));
-  DEFINE(VGIC_V2_CPU_EISR,     offsetof(struct vgic_cpu, vgic_v2.vgic_eisr));
-  DEFINE(VGIC_V2_CPU_ELRSR,    offsetof(struct vgic_cpu, vgic_v2.vgic_elrsr));
-  DEFINE(VGIC_V2_CPU_APR,      offsetof(struct vgic_cpu, vgic_v2.vgic_apr));
-  DEFINE(VGIC_V2_CPU_LR,       offsetof(struct vgic_cpu, vgic_v2.vgic_lr));
-  DEFINE(VGIC_V3_CPU_SRE,      offsetof(struct vgic_cpu, vgic_v3.vgic_sre));
-  DEFINE(VGIC_V3_CPU_HCR,      offsetof(struct vgic_cpu, vgic_v3.vgic_hcr));
-  DEFINE(VGIC_V3_CPU_VMCR,     offsetof(struct vgic_cpu, vgic_v3.vgic_vmcr));
-  DEFINE(VGIC_V3_CPU_MISR,     offsetof(struct vgic_cpu, vgic_v3.vgic_misr));
-  DEFINE(VGIC_V3_CPU_EISR,     offsetof(struct vgic_cpu, vgic_v3.vgic_eisr));
-  DEFINE(VGIC_V3_CPU_ELRSR,    offsetof(struct vgic_cpu, vgic_v3.vgic_elrsr));
-  DEFINE(VGIC_V3_CPU_AP0R,     offsetof(struct vgic_cpu, vgic_v3.vgic_ap0r));
-  DEFINE(VGIC_V3_CPU_AP1R,     offsetof(struct vgic_cpu, vgic_v3.vgic_ap1r));
-  DEFINE(VGIC_V3_CPU_LR,       offsetof(struct vgic_cpu, vgic_v3.vgic_lr));
-  DEFINE(VGIC_CPU_NR_LR,       offsetof(struct vgic_cpu, nr_lr));
-  DEFINE(KVM_VTTBR,            offsetof(struct kvm, arch.vttbr));
-  DEFINE(KVM_VGIC_VCTRL,       offsetof(struct kvm, arch.vgic.vctrl_base));
 #endif
 #ifdef CONFIG_CPU_PM
   DEFINE(CPU_SUSPEND_SZ,       sizeof(struct cpu_suspend_ctx));
@@ -161,5 +124,7 @@ int main(void)
   DEFINE(SLEEP_SAVE_SP_PHYS,   offsetof(struct sleep_save_sp, save_ptr_stash_phys));
   DEFINE(SLEEP_SAVE_SP_VIRT,   offsetof(struct sleep_save_sp, save_ptr_stash));
 #endif
+  DEFINE(ARM_SMCCC_RES_X0_OFFS,        offsetof(struct arm_smccc_res, a0));
+  DEFINE(ARM_SMCCC_RES_X2_OFFS,        offsetof(struct arm_smccc_res, a2));
   return 0;
 }
index 0669c63281ea01a93ef9794f9731b424b6afd28e..5c90aa490a2bee2368ae45bba2628603afe1c659 100644 (file)
@@ -684,7 +684,7 @@ static const struct arm64_cpu_capabilities arm64_hwcaps[] = {
        {},
 };
 
-static void cap_set_hwcap(const struct arm64_cpu_capabilities *cap)
+static void __init cap_set_hwcap(const struct arm64_cpu_capabilities *cap)
 {
        switch (cap->hwcap_type) {
        case CAP_HWCAP:
@@ -729,7 +729,7 @@ static bool __maybe_unused cpus_have_hwcap(const struct arm64_cpu_capabilities *
        return rc;
 }
 
-static void setup_cpu_hwcaps(void)
+static void __init setup_cpu_hwcaps(void)
 {
        int i;
        const struct arm64_cpu_capabilities *hwcaps = arm64_hwcaps;
@@ -758,7 +758,8 @@ void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
  * Run through the enabled capabilities and enable() it on all active
  * CPUs
  */
-static void enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps)
+static void __init
+enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps)
 {
        int i;
 
@@ -897,7 +898,7 @@ static inline void set_sys_caps_initialised(void)
 
 #endif /* CONFIG_HOTPLUG_CPU */
 
-static void setup_feature_capabilities(void)
+static void __init setup_feature_capabilities(void)
 {
        update_cpu_capabilities(arm64_features, "detected feature:");
        enable_cpu_capabilities(arm64_features);
index 4eeb17198cfaf598fd403b1e4040c77f5ee3068a..b6abc852f2a142123150662bc6dd6bf5c3de62af 100644 (file)
  *
  */
 
-#include <linux/atomic.h>
 #include <linux/dmi.h>
 #include <linux/efi.h>
-#include <linux/export.h>
-#include <linux/memblock.h>
-#include <linux/mm_types.h>
-#include <linux/bootmem.h>
-#include <linux/of.h>
-#include <linux/of_fdt.h>
-#include <linux/preempt.h>
-#include <linux/rbtree.h>
-#include <linux/rwsem.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
+#include <linux/init.h>
 
-#include <asm/cacheflush.h>
 #include <asm/efi.h>
-#include <asm/tlbflush.h>
-#include <asm/mmu_context.h>
-#include <asm/mmu.h>
-#include <asm/pgtable.h>
 
-struct efi_memory_map memmap;
-
-static u64 efi_system_table;
-
-static pgd_t efi_pgd[PTRS_PER_PGD] __page_aligned_bss;
-
-static struct mm_struct efi_mm = {
-       .mm_rb                  = RB_ROOT,
-       .pgd                    = efi_pgd,
-       .mm_users               = ATOMIC_INIT(2),
-       .mm_count               = ATOMIC_INIT(1),
-       .mmap_sem               = __RWSEM_INITIALIZER(efi_mm.mmap_sem),
-       .page_table_lock        = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock),
-       .mmlist                 = LIST_HEAD_INIT(efi_mm.mmlist),
-};
-
-static int __init is_normal_ram(efi_memory_desc_t *md)
-{
-       if (md->attribute & EFI_MEMORY_WB)
-               return 1;
-       return 0;
-}
-
-/*
- * Translate a EFI virtual address into a physical address: this is necessary,
- * as some data members of the EFI system table are virtually remapped after
- * SetVirtualAddressMap() has been called.
- */
-static phys_addr_t efi_to_phys(unsigned long addr)
+int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
 {
-       efi_memory_desc_t *md;
-
-       for_each_efi_memory_desc(&memmap, md) {
-               if (!(md->attribute & EFI_MEMORY_RUNTIME))
-                       continue;
-               if (md->virt_addr == 0)
-                       /* no virtual mapping has been installed by the stub */
-                       break;
-               if (md->virt_addr <= addr &&
-                   (addr - md->virt_addr) < (md->num_pages << EFI_PAGE_SHIFT))
-                       return md->phys_addr + addr - md->virt_addr;
-       }
-       return addr;
-}
-
-static int __init uefi_init(void)
-{
-       efi_char16_t *c16;
-       void *config_tables;
-       u64 table_size;
-       char vendor[100] = "unknown";
-       int i, retval;
-
-       efi.systab = early_memremap(efi_system_table,
-                                   sizeof(efi_system_table_t));
-       if (efi.systab == NULL) {
-               pr_warn("Unable to map EFI system table.\n");
-               return -ENOMEM;
-       }
-
-       set_bit(EFI_BOOT, &efi.flags);
-       set_bit(EFI_64BIT, &efi.flags);
+       pteval_t prot_val;
 
        /*
-        * Verify the EFI Table
+        * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be
+        * executable, everything else can be mapped with the XN bits
+        * set.
         */
-       if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
-               pr_err("System table signature incorrect\n");
-               retval = -EINVAL;
-               goto out;
-       }
-       if ((efi.systab->hdr.revision >> 16) < 2)
-               pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n",
-                       efi.systab->hdr.revision >> 16,
-                       efi.systab->hdr.revision & 0xffff);
-
-       /* Show what we know for posterity */
-       c16 = early_memremap(efi_to_phys(efi.systab->fw_vendor),
-                            sizeof(vendor) * sizeof(efi_char16_t));
-       if (c16) {
-               for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
-                       vendor[i] = c16[i];
-               vendor[i] = '\0';
-               early_memunmap(c16, sizeof(vendor) * sizeof(efi_char16_t));
-       }
-
-       pr_info("EFI v%u.%.02u by %s\n",
-               efi.systab->hdr.revision >> 16,
-               efi.systab->hdr.revision & 0xffff, vendor);
-
-       table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables;
-       config_tables = early_memremap(efi_to_phys(efi.systab->tables),
-                                      table_size);
-       if (config_tables == NULL) {
-               pr_warn("Unable to map EFI config table array.\n");
-               retval = -ENOMEM;
-               goto out;
-       }
-       retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables,
-                                        sizeof(efi_config_table_64_t), NULL);
-
-       early_memunmap(config_tables, table_size);
-out:
-       early_memunmap(efi.systab,  sizeof(efi_system_table_t));
-       return retval;
-}
-
-/*
- * Return true for RAM regions we want to permanently reserve.
- */
-static __init int is_reserve_region(efi_memory_desc_t *md)
-{
-       switch (md->type) {
-       case EFI_LOADER_CODE:
-       case EFI_LOADER_DATA:
-       case EFI_BOOT_SERVICES_CODE:
-       case EFI_BOOT_SERVICES_DATA:
-       case EFI_CONVENTIONAL_MEMORY:
-       case EFI_PERSISTENT_MEMORY:
-               return 0;
-       default:
-               break;
-       }
-       return is_normal_ram(md);
-}
-
-static __init void reserve_regions(void)
-{
-       efi_memory_desc_t *md;
-       u64 paddr, npages, size;
-
-       if (efi_enabled(EFI_DBG))
-               pr_info("Processing EFI memory map:\n");
-
-       for_each_efi_memory_desc(&memmap, md) {
-               paddr = md->phys_addr;
-               npages = md->num_pages;
-
-               if (efi_enabled(EFI_DBG)) {
-                       char buf[64];
-
-                       pr_info("  0x%012llx-0x%012llx %s",
-                               paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1,
-                               efi_md_typeattr_format(buf, sizeof(buf), md));
-               }
-
-               memrange_efi_to_native(&paddr, &npages);
-               size = npages << PAGE_SHIFT;
-
-               if (is_normal_ram(md))
-                       early_init_dt_add_memory_arch(paddr, size);
-
-               if (is_reserve_region(md)) {
-                       memblock_reserve(paddr, size);
-                       if (efi_enabled(EFI_DBG))
-                               pr_cont("*");
-               }
-
-               if (efi_enabled(EFI_DBG))
-                       pr_cont("\n");
-       }
-
-       set_bit(EFI_MEMMAP, &efi.flags);
-}
-
-void __init efi_init(void)
-{
-       struct efi_fdt_params params;
-
-       /* Grab UEFI information placed in FDT by stub */
-       if (!efi_get_fdt_params(&params))
-               return;
-
-       efi_system_table = params.system_table;
-
-       memblock_reserve(params.mmap & PAGE_MASK,
-                        PAGE_ALIGN(params.mmap_size + (params.mmap & ~PAGE_MASK)));
-       memmap.phys_map = params.mmap;
-       memmap.map = early_memremap(params.mmap, params.mmap_size);
-       if (memmap.map == NULL) {
-               /*
-               * If we are booting via UEFI, the UEFI memory map is the only
-               * description of memory we have, so there is little point in
-               * proceeding if we cannot access it.
-               */
-               panic("Unable to map EFI memory map.\n");
-       }
-       memmap.map_end = memmap.map + params.mmap_size;
-       memmap.desc_size = params.desc_size;
-       memmap.desc_version = params.desc_ver;
-
-       if (uefi_init() < 0)
-               return;
-
-       reserve_regions();
-       early_memunmap(memmap.map, params.mmap_size);
-}
-
-static bool __init efi_virtmap_init(void)
-{
-       efi_memory_desc_t *md;
-
-       init_new_context(NULL, &efi_mm);
-
-       for_each_efi_memory_desc(&memmap, md) {
-               pgprot_t prot;
-
-               if (!(md->attribute & EFI_MEMORY_RUNTIME))
-                       continue;
-               if (md->virt_addr == 0)
-                       return false;
-
-               pr_info("  EFI remap 0x%016llx => %p\n",
-                       md->phys_addr, (void *)md->virt_addr);
-
-               /*
-                * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be
-                * executable, everything else can be mapped with the XN bits
-                * set.
-                */
-               if (!is_normal_ram(md))
-                       prot = __pgprot(PROT_DEVICE_nGnRE);
-               else if (md->type == EFI_RUNTIME_SERVICES_CODE ||
-                        !PAGE_ALIGNED(md->phys_addr))
-                       prot = PAGE_KERNEL_EXEC;
-               else
-                       prot = PAGE_KERNEL;
-
-               create_pgd_mapping(&efi_mm, md->phys_addr, md->virt_addr,
-                                  md->num_pages << EFI_PAGE_SHIFT, 
-                                  __pgprot(pgprot_val(prot) | PTE_NG));
-       }
-       return true;
-}
-
-/*
- * Enable the UEFI Runtime Services if all prerequisites are in place, i.e.,
- * non-early mapping of the UEFI system table and virtual mappings for all
- * EFI_MEMORY_RUNTIME regions.
- */
-static int __init arm64_enable_runtime_services(void)
-{
-       u64 mapsize;
-
-       if (!efi_enabled(EFI_BOOT)) {
-               pr_info("EFI services will not be available.\n");
-               return 0;
-       }
-
-       if (efi_runtime_disabled()) {
-               pr_info("EFI runtime services will be disabled.\n");
-               return 0;
-       }
-
-       pr_info("Remapping and enabling EFI services.\n");
-
-       mapsize = memmap.map_end - memmap.map;
-       memmap.map = (__force void *)ioremap_cache(memmap.phys_map,
-                                                  mapsize);
-       if (!memmap.map) {
-               pr_err("Failed to remap EFI memory map\n");
-               return -ENOMEM;
-       }
-       memmap.map_end = memmap.map + mapsize;
-       efi.memmap = &memmap;
-
-       efi.systab = (__force void *)ioremap_cache(efi_system_table,
-                                                  sizeof(efi_system_table_t));
-       if (!efi.systab) {
-               pr_err("Failed to remap EFI System Table\n");
-               return -ENOMEM;
-       }
-       set_bit(EFI_SYSTEM_TABLES, &efi.flags);
-
-       if (!efi_virtmap_init()) {
-               pr_err("No UEFI virtual mapping was installed -- runtime services will not be available\n");
-               return -ENOMEM;
-       }
-
-       /* Set up runtime services function pointers */
-       efi_native_runtime_setup();
-       set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
-
-       efi.runtime_version = efi.systab->hdr.revision;
-
+       if ((md->attribute & EFI_MEMORY_WB) == 0)
+               prot_val = PROT_DEVICE_nGnRE;
+       else if (md->type == EFI_RUNTIME_SERVICES_CODE ||
+                !PAGE_ALIGNED(md->phys_addr))
+               prot_val = pgprot_val(PAGE_KERNEL_EXEC);
+       else
+               prot_val = pgprot_val(PAGE_KERNEL);
+
+       create_pgd_mapping(mm, md->phys_addr, md->virt_addr,
+                          md->num_pages << EFI_PAGE_SHIFT,
+                          __pgprot(prot_val | PTE_NG));
        return 0;
 }
-early_initcall(arm64_enable_runtime_services);
 
 static int __init arm64_dmi_init(void)
 {
@@ -337,23 +54,6 @@ static int __init arm64_dmi_init(void)
 }
 core_initcall(arm64_dmi_init);
 
-static void efi_set_pgd(struct mm_struct *mm)
-{
-       switch_mm(NULL, mm, NULL);
-}
-
-void efi_virtmap_load(void)
-{
-       preempt_disable();
-       efi_set_pgd(&efi_mm);
-}
-
-void efi_virtmap_unload(void)
-{
-       efi_set_pgd(current->active_mm);
-       preempt_enable();
-}
-
 /*
  * UpdateCapsule() depends on the system being shutdown via
  * ResetSystem().
index 7ed3d75f630418b56a1add8c91b308b48cd69774..1f7f5a2b61bf0de999d80e6ced16bec120f716b6 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/cpufeature.h>
 #include <asm/errno.h>
 #include <asm/esr.h>
+#include <asm/irq.h>
 #include <asm/thread_info.h>
 #include <asm/unistd.h>
 
 
        .if     \el == 0
        mrs     x21, sp_el0
-       get_thread_info tsk                     // Ensure MDSCR_EL1.SS is clear,
+       mov     tsk, sp
+       and     tsk, tsk, #~(THREAD_SIZE - 1)   // Ensure MDSCR_EL1.SS is clear,
        ldr     x19, [tsk, #TI_FLAGS]           // since we can unmask debug
        disable_step_tsk x19, x20               // exceptions when scheduling.
+
+       mov     x29, xzr                        // fp pointed to user-space
        .else
        add     x21, sp, #S_FRAME_SIZE
        .endif
        str     x21, [sp, #S_SYSCALLNO]
        .endif
 
+       /*
+        * Set sp_el0 to current thread_info.
+        */
+       .if     \el == 0
+       msr     sp_el0, tsk
+       .endif
+
        /*
         * Registers that may be useful after this macro is invoked:
         *
@@ -164,8 +175,44 @@ alternative_endif
        .endm
 
        .macro  get_thread_info, rd
-       mov     \rd, sp
-       and     \rd, \rd, #~(THREAD_SIZE - 1)   // top of stack
+       mrs     \rd, sp_el0
+       .endm
+
+       .macro  irq_stack_entry
+       mov     x19, sp                 // preserve the original sp
+
+       /*
+        * Compare sp with the current thread_info, if the top
+        * ~(THREAD_SIZE - 1) bits match, we are on a task stack, and
+        * should switch to the irq stack.
+        */
+       and     x25, x19, #~(THREAD_SIZE - 1)
+       cmp     x25, tsk
+       b.ne    9998f
+
+       this_cpu_ptr irq_stack, x25, x26
+       mov     x26, #IRQ_STACK_START_SP
+       add     x26, x25, x26
+
+       /* switch to the irq stack */
+       mov     sp, x26
+
+       /*
+        * Add a dummy stack frame, this non-standard format is fixed up
+        * by unwind_frame()
+        */
+       stp     x29, x19, [sp, #-16]!
+       mov     x29, sp
+
+9998:
+       .endm
+
+       /*
+        * x19 should be preserved between irq_stack_entry and
+        * irq_stack_exit.
+        */
+       .macro  irq_stack_exit
+       mov     sp, x19
        .endm
 
 /*
@@ -183,10 +230,11 @@ tsk       .req    x28             // current thread_info
  * Interrupt handling.
  */
        .macro  irq_handler
-       adrp    x1, handle_arch_irq
-       ldr     x1, [x1, #:lo12:handle_arch_irq]
+       ldr_l   x1, handle_arch_irq
        mov     x0, sp
+       irq_stack_entry
        blr     x1
+       irq_stack_exit
        .endm
 
        .text
@@ -358,10 +406,10 @@ el1_irq:
        bl      trace_hardirqs_off
 #endif
 
+       get_thread_info tsk
        irq_handler
 
 #ifdef CONFIG_PREEMPT
-       get_thread_info tsk
        ldr     w24, [tsk, #TI_PREEMPT]         // get preempt count
        cbnz    w24, 1f                         // preempt count != 0
        ldr     x0, [tsk, #TI_FLAGS]            // get flags
@@ -599,6 +647,8 @@ ENTRY(cpu_switch_to)
        ldp     x29, x9, [x8], #16
        ldr     lr, [x8]
        mov     sp, x9
+       and     x9, x9, #~(THREAD_SIZE - 1)
+       msr     sp_el0, x9
        ret
 ENDPROC(cpu_switch_to)
 
@@ -626,14 +676,14 @@ ret_fast_syscall_trace:
 work_pending:
        tbnz    x1, #TIF_NEED_RESCHED, work_resched
        /* TIF_SIGPENDING, TIF_NOTIFY_RESUME or TIF_FOREIGN_FPSTATE case */
-       ldr     x2, [sp, #S_PSTATE]
        mov     x0, sp                          // 'regs'
-       tst     x2, #PSR_MODE_MASK              // user mode regs?
-       b.ne    no_work_pending                 // returning to kernel
        enable_irq                              // enable interrupts for do_notify_resume()
        bl      do_notify_resume
        b       ret_to_user
 work_resched:
+#ifdef CONFIG_TRACE_IRQFLAGS
+       bl      trace_hardirqs_off              // the IRQs are off here, inform the tracing code
+#endif
        bl      schedule
 
 /*
@@ -645,7 +695,6 @@ ret_to_user:
        and     x2, x1, #_TIF_WORK_MASK
        cbnz    x2, work_pending
        enable_step_tsk x1, x2
-no_work_pending:
        kernel_exit 0
 ENDPROC(ret_to_user)
 
index 4c46c54a3ad7ad817b8ba410565b8eff47cd3c08..acc1afd5c749a62b7c0bae5a14d2fd7dbc33adf2 100644 (file)
@@ -289,7 +289,7 @@ static struct notifier_block fpsimd_cpu_pm_notifier_block = {
        .notifier_call = fpsimd_cpu_pm_notifier,
 };
 
-static void fpsimd_pm_init(void)
+static void __init fpsimd_pm_init(void)
 {
        cpu_pm_register_notifier(&fpsimd_cpu_pm_notifier_block);
 }
index c851be795080336938f4826cc0608234b0e34bfa..ebecf9aa33d12da8a564ea0314f59a71b89e64a0 100644 (file)
@@ -29,12 +29,11 @@ static int ftrace_modify_code(unsigned long pc, u32 old, u32 new,
 
        /*
         * Note:
-        * Due to modules and __init, code can disappear and change,
-        * we need to protect against faulting as well as code changing.
-        * We do this by aarch64_insn_*() which use the probe_kernel_*().
-        *
-        * No lock is held here because all the modifications are run
-        * through stop_machine().
+        * We are paranoid about modifying text, as if a bug were to happen, it
+        * could cause us to read or write to someplace that could cause harm.
+        * Carefully read and modify the code with aarch64_insn_*() which uses
+        * probe_kernel_*(), and make sure what we read is what we expected it
+        * to be before modifying it.
         */
        if (validate) {
                if (aarch64_insn_read((void *)pc, &replaced))
@@ -93,6 +92,11 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
        return ftrace_modify_code(pc, old, new, true);
 }
 
+void arch_ftrace_update_code(int command)
+{
+       ftrace_modify_all_code(command);
+}
+
 int __init ftrace_dyn_arch_init(void)
 {
        return 0;
@@ -125,23 +129,20 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
         * on other archs. It's unlikely on AArch64.
         */
        old = *parent;
-       *parent = return_hooker;
 
        trace.func = self_addr;
        trace.depth = current->curr_ret_stack + 1;
 
        /* Only trace if the calling function expects to */
-       if (!ftrace_graph_entry(&trace)) {
-               *parent = old;
+       if (!ftrace_graph_entry(&trace))
                return;
-       }
 
        err = ftrace_push_return_trace(old, self_addr, &trace.depth,
                                       frame_pointer);
-       if (err == -EBUSY) {
-               *parent = old;
+       if (err == -EBUSY)
                return;
-       }
+       else
+               *parent = return_hooker;
 }
 
 #ifdef CONFIG_DYNAMIC_FTRACE
index 23cfc08fc8ba88683600d7618acb9bdb400ae2b9..ffe9c2b6431bd5c0cb1e9982afe84e13a82e2043 100644 (file)
@@ -415,15 +415,17 @@ ENDPROC(__create_page_tables)
  */
        .set    initial_sp, init_thread_union + THREAD_START_SP
 __mmap_switched:
-       adr_l   x6, __bss_start
-       adr_l   x7, __bss_stop
-
-1:     cmp     x6, x7
-       b.hs    2f
-       str     xzr, [x6], #8                   // Clear BSS
-       b       1b
-2:
+       // Clear BSS
+       adr_l   x0, __bss_start
+       mov     x1, xzr
+       adr_l   x2, __bss_stop
+       sub     x2, x2, x0
+       bl      __pi_memset
+
        adr_l   sp, initial_sp, x4
+       mov     x4, sp
+       and     x4, x4, #~(THREAD_SIZE - 1)
+       msr     sp_el0, x4                      // Save thread_info
        str_l   x21, __fdt_pointer, x5          // Save FDT pointer
        str_l   x24, memstart_addr, x6          // Save PHYS_OFFSET
        mov     x29, #0
@@ -606,6 +608,8 @@ ENDPROC(secondary_startup)
 ENTRY(__secondary_switched)
        ldr     x0, [x21]                       // get secondary_data.stack
        mov     sp, x0
+       and     x0, x0, #~(THREAD_SIZE - 1)
+       msr     sp_el0, x0                      // save thread_info
        mov     x29, #0
        b       secondary_start_kernel
 ENDPROC(__secondary_switched)
index 9f17ec071ee0e8a8b1380133cf319a9ad1c80de5..2386b26c071274d4d563a4fdc5e864aedda37204 100644 (file)
@@ -30,6 +30,9 @@
 
 unsigned long irq_err_count;
 
+/* irq stack only needs to be 16 byte aligned - not IRQ_STACK_SIZE aligned. */
+DEFINE_PER_CPU(unsigned long [IRQ_STACK_SIZE/sizeof(long)], irq_stack) __aligned(16);
+
 int arch_show_interrupts(struct seq_file *p, int prec)
 {
        show_ipi_list(p, prec);
index f4bc779e62e887547b7a17b7672487f0851e1479..93e970231ca9d5a6a69bf721fadc8cfc5b7344c2 100644 (file)
@@ -30,9 +30,6 @@
 #include <asm/insn.h>
 #include <asm/sections.h>
 
-#define        AARCH64_INSN_IMM_MOVNZ          AARCH64_INSN_IMM_MAX
-#define        AARCH64_INSN_IMM_MOVK           AARCH64_INSN_IMM_16
-
 void *module_alloc(unsigned long size)
 {
        void *p;
@@ -75,15 +72,18 @@ static u64 do_reloc(enum aarch64_reloc_op reloc_op, void *place, u64 val)
 
 static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len)
 {
-       u64 imm_mask = (1 << len) - 1;
        s64 sval = do_reloc(op, place, val);
 
        switch (len) {
        case 16:
                *(s16 *)place = sval;
+               if (sval < S16_MIN || sval > U16_MAX)
+                       return -ERANGE;
                break;
        case 32:
                *(s32 *)place = sval;
+               if (sval < S32_MIN || sval > U32_MAX)
+                       return -ERANGE;
                break;
        case 64:
                *(s64 *)place = sval;
@@ -92,34 +92,23 @@ static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len)
                pr_err("Invalid length (%d) for data relocation\n", len);
                return 0;
        }
-
-       /*
-        * Extract the upper value bits (including the sign bit) and
-        * shift them to bit 0.
-        */
-       sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1);
-
-       /*
-        * Overflow has occurred if the value is not representable in
-        * len bits (i.e the bottom len bits are not sign-extended and
-        * the top bits are not all zero).
-        */
-       if ((u64)(sval + 1) > 2)
-               return -ERANGE;
-
        return 0;
 }
 
+enum aarch64_insn_movw_imm_type {
+       AARCH64_INSN_IMM_MOVNZ,
+       AARCH64_INSN_IMM_MOVKZ,
+};
+
 static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val,
-                          int lsb, enum aarch64_insn_imm_type imm_type)
+                          int lsb, enum aarch64_insn_movw_imm_type imm_type)
 {
-       u64 imm, limit = 0;
+       u64 imm;
        s64 sval;
        u32 insn = le32_to_cpu(*(u32 *)place);
 
        sval = do_reloc(op, place, val);
-       sval >>= lsb;
-       imm = sval & 0xffff;
+       imm = sval >> lsb;
 
        if (imm_type == AARCH64_INSN_IMM_MOVNZ) {
                /*
@@ -128,7 +117,7 @@ static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val,
                 * immediate is less than zero.
                 */
                insn &= ~(3 << 29);
-               if ((s64)imm >= 0) {
+               if (sval >= 0) {
                        /* >=0: Set the instruction to MOVZ (opcode 10b). */
                        insn |= 2 << 29;
                } else {
@@ -140,29 +129,13 @@ static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val,
                         */
                        imm = ~imm;
                }
-               imm_type = AARCH64_INSN_IMM_MOVK;
        }
 
        /* Update the instruction with the new encoding. */
-       insn = aarch64_insn_encode_immediate(imm_type, insn, imm);
+       insn = aarch64_insn_encode_immediate(AARCH64_INSN_IMM_16, insn, imm);
        *(u32 *)place = cpu_to_le32(insn);
 
-       /* Shift out the immediate field. */
-       sval >>= 16;
-
-       /*
-        * For unsigned immediates, the overflow check is straightforward.
-        * For signed immediates, the sign bit is actually the bit past the
-        * most significant bit of the field.
-        * The AARCH64_INSN_IMM_16 immediate type is unsigned.
-        */
-       if (imm_type != AARCH64_INSN_IMM_16) {
-               sval++;
-               limit++;
-       }
-
-       /* Check the upper bits depending on the sign of the immediate. */
-       if ((u64)sval > limit)
+       if (imm > U16_MAX)
                return -ERANGE;
 
        return 0;
@@ -267,25 +240,25 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                        overflow_check = false;
                case R_AARCH64_MOVW_UABS_G0:
                        ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0,
-                                             AARCH64_INSN_IMM_16);
+                                             AARCH64_INSN_IMM_MOVKZ);
                        break;
                case R_AARCH64_MOVW_UABS_G1_NC:
                        overflow_check = false;
                case R_AARCH64_MOVW_UABS_G1:
                        ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16,
-                                             AARCH64_INSN_IMM_16);
+                                             AARCH64_INSN_IMM_MOVKZ);
                        break;
                case R_AARCH64_MOVW_UABS_G2_NC:
                        overflow_check = false;
                case R_AARCH64_MOVW_UABS_G2:
                        ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32,
-                                             AARCH64_INSN_IMM_16);
+                                             AARCH64_INSN_IMM_MOVKZ);
                        break;
                case R_AARCH64_MOVW_UABS_G3:
                        /* We're using the top bits so we can't overflow. */
                        overflow_check = false;
                        ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 48,
-                                             AARCH64_INSN_IMM_16);
+                                             AARCH64_INSN_IMM_MOVKZ);
                        break;
                case R_AARCH64_MOVW_SABS_G0:
                        ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0,
@@ -302,7 +275,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                case R_AARCH64_MOVW_PREL_G0_NC:
                        overflow_check = false;
                        ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0,
-                                             AARCH64_INSN_IMM_MOVK);
+                                             AARCH64_INSN_IMM_MOVKZ);
                        break;
                case R_AARCH64_MOVW_PREL_G0:
                        ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0,
@@ -311,7 +284,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                case R_AARCH64_MOVW_PREL_G1_NC:
                        overflow_check = false;
                        ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16,
-                                             AARCH64_INSN_IMM_MOVK);
+                                             AARCH64_INSN_IMM_MOVKZ);
                        break;
                case R_AARCH64_MOVW_PREL_G1:
                        ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16,
@@ -320,7 +293,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                case R_AARCH64_MOVW_PREL_G2_NC:
                        overflow_check = false;
                        ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32,
-                                             AARCH64_INSN_IMM_MOVK);
+                                             AARCH64_INSN_IMM_MOVKZ);
                        break;
                case R_AARCH64_MOVW_PREL_G2:
                        ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32,
diff --git a/arch/arm64/kernel/paravirt.c b/arch/arm64/kernel/paravirt.c
new file mode 100644 (file)
index 0000000..53f371e
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2013 Citrix Systems
+ *
+ * Author: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+ */
+
+#include <linux/export.h>
+#include <linux/jump_label.h>
+#include <linux/types.h>
+#include <asm/paravirt.h>
+
+struct static_key paravirt_steal_enabled;
+struct static_key paravirt_steal_rq_enabled;
+
+struct pv_time_ops pv_time_ops;
+EXPORT_SYMBOL_GPL(pv_time_ops);
index 3aa74830cc69af0053efb77c72e9c26ae3bd6c02..ff4665462a025d4ec2655ca30d49732a63194e53 100644 (file)
@@ -164,8 +164,11 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry,
        frame.fp = regs->regs[29];
        frame.sp = regs->sp;
        frame.pc = regs->pc;
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       frame.graph = current->curr_ret_stack;
+#endif
 
-       walk_stackframe(&frame, callchain_trace, entry);
+       walk_stackframe(current, &frame, callchain_trace, entry);
 }
 
 unsigned long perf_instruction_pointer(struct pt_regs *regs)
index 5b1897e8ca2476b20336658c65e3e19665bf0cdd..f7ab14c4d5df2c6cb9d754299292409465602259 100644 (file)
  * ARMv8 PMUv3 Performance Events handling code.
  * Common event types.
  */
-enum armv8_pmuv3_perf_types {
-       /* Required events. */
-       ARMV8_PMUV3_PERFCTR_PMNC_SW_INCR                        = 0x00,
-       ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL                    = 0x03,
-       ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS                    = 0x04,
-       ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED                  = 0x10,
-       ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES                        = 0x11,
-       ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED                      = 0x12,
-
-       /* At least one of the following is required. */
-       ARMV8_PMUV3_PERFCTR_INSTR_EXECUTED                      = 0x08,
-       ARMV8_PMUV3_PERFCTR_OP_SPEC                             = 0x1B,
-
-       /* Common architectural events. */
-       ARMV8_PMUV3_PERFCTR_MEM_READ                            = 0x06,
-       ARMV8_PMUV3_PERFCTR_MEM_WRITE                           = 0x07,
-       ARMV8_PMUV3_PERFCTR_EXC_TAKEN                           = 0x09,
-       ARMV8_PMUV3_PERFCTR_EXC_EXECUTED                        = 0x0A,
-       ARMV8_PMUV3_PERFCTR_CID_WRITE                           = 0x0B,
-       ARMV8_PMUV3_PERFCTR_PC_WRITE                            = 0x0C,
-       ARMV8_PMUV3_PERFCTR_PC_IMM_BRANCH                       = 0x0D,
-       ARMV8_PMUV3_PERFCTR_PC_PROC_RETURN                      = 0x0E,
-       ARMV8_PMUV3_PERFCTR_MEM_UNALIGNED_ACCESS                = 0x0F,
-       ARMV8_PMUV3_PERFCTR_TTBR_WRITE                          = 0x1C,
-
-       /* Common microarchitectural events. */
-       ARMV8_PMUV3_PERFCTR_L1_ICACHE_REFILL                    = 0x01,
-       ARMV8_PMUV3_PERFCTR_ITLB_REFILL                         = 0x02,
-       ARMV8_PMUV3_PERFCTR_DTLB_REFILL                         = 0x05,
-       ARMV8_PMUV3_PERFCTR_MEM_ACCESS                          = 0x13,
-       ARMV8_PMUV3_PERFCTR_L1_ICACHE_ACCESS                    = 0x14,
-       ARMV8_PMUV3_PERFCTR_L1_DCACHE_WB                        = 0x15,
-       ARMV8_PMUV3_PERFCTR_L2_CACHE_ACCESS                     = 0x16,
-       ARMV8_PMUV3_PERFCTR_L2_CACHE_REFILL                     = 0x17,
-       ARMV8_PMUV3_PERFCTR_L2_CACHE_WB                         = 0x18,
-       ARMV8_PMUV3_PERFCTR_BUS_ACCESS                          = 0x19,
-       ARMV8_PMUV3_PERFCTR_MEM_ERROR                           = 0x1A,
-       ARMV8_PMUV3_PERFCTR_BUS_CYCLES                          = 0x1D,
-};
+
+/* Required events. */
+#define ARMV8_PMUV3_PERFCTR_PMNC_SW_INCR                       0x00
+#define ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL                   0x03
+#define ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS                   0x04
+#define ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED                 0x10
+#define ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES                       0x11
+#define ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED                     0x12
+
+/* At least one of the following is required. */
+#define ARMV8_PMUV3_PERFCTR_INSTR_EXECUTED                     0x08
+#define ARMV8_PMUV3_PERFCTR_OP_SPEC                            0x1B
+
+/* Common architectural events. */
+#define ARMV8_PMUV3_PERFCTR_MEM_READ                           0x06
+#define ARMV8_PMUV3_PERFCTR_MEM_WRITE                          0x07
+#define ARMV8_PMUV3_PERFCTR_EXC_TAKEN                          0x09
+#define ARMV8_PMUV3_PERFCTR_EXC_EXECUTED                       0x0A
+#define ARMV8_PMUV3_PERFCTR_CID_WRITE                          0x0B
+#define ARMV8_PMUV3_PERFCTR_PC_WRITE                           0x0C
+#define ARMV8_PMUV3_PERFCTR_PC_IMM_BRANCH                      0x0D
+#define ARMV8_PMUV3_PERFCTR_PC_PROC_RETURN                     0x0E
+#define ARMV8_PMUV3_PERFCTR_MEM_UNALIGNED_ACCESS               0x0F
+#define ARMV8_PMUV3_PERFCTR_TTBR_WRITE                         0x1C
+#define ARMV8_PMUV3_PERFCTR_CHAIN                              0x1E
+#define ARMV8_PMUV3_PERFCTR_BR_RETIRED                         0x21
+
+/* Common microarchitectural events. */
+#define ARMV8_PMUV3_PERFCTR_L1_ICACHE_REFILL                   0x01
+#define ARMV8_PMUV3_PERFCTR_ITLB_REFILL                                0x02
+#define ARMV8_PMUV3_PERFCTR_DTLB_REFILL                                0x05
+#define ARMV8_PMUV3_PERFCTR_MEM_ACCESS                         0x13
+#define ARMV8_PMUV3_PERFCTR_L1_ICACHE_ACCESS                   0x14
+#define ARMV8_PMUV3_PERFCTR_L1_DCACHE_WB                       0x15
+#define ARMV8_PMUV3_PERFCTR_L2_CACHE_ACCESS                    0x16
+#define ARMV8_PMUV3_PERFCTR_L2_CACHE_REFILL                    0x17
+#define ARMV8_PMUV3_PERFCTR_L2_CACHE_WB                                0x18
+#define ARMV8_PMUV3_PERFCTR_BUS_ACCESS                         0x19
+#define ARMV8_PMUV3_PERFCTR_MEM_ERROR                          0x1A
+#define ARMV8_PMUV3_PERFCTR_BUS_CYCLES                         0x1D
+#define ARMV8_PMUV3_PERFCTR_L1D_CACHE_ALLOCATE                 0x1F
+#define ARMV8_PMUV3_PERFCTR_L2D_CACHE_ALLOCATE                 0x20
+#define ARMV8_PMUV3_PERFCTR_BR_MIS_PRED_RETIRED                        0x22
+#define ARMV8_PMUV3_PERFCTR_STALL_FRONTEND                     0x23
+#define ARMV8_PMUV3_PERFCTR_STALL_BACKEND                      0x24
+#define ARMV8_PMUV3_PERFCTR_L1D_TLB                            0x25
+#define ARMV8_PMUV3_PERFCTR_L1I_TLB                            0x26
+#define ARMV8_PMUV3_PERFCTR_L2I_CACHE                          0x27
+#define ARMV8_PMUV3_PERFCTR_L2I_CACHE_REFILL                   0x28
+#define ARMV8_PMUV3_PERFCTR_L3D_CACHE_ALLOCATE                 0x29
+#define ARMV8_PMUV3_PERFCTR_L3D_CACHE_REFILL                   0x2A
+#define ARMV8_PMUV3_PERFCTR_L3D_CACHE                          0x2B
+#define ARMV8_PMUV3_PERFCTR_L3D_CACHE_WB                       0x2C
+#define ARMV8_PMUV3_PERFCTR_L2D_TLB_REFILL                     0x2D
+#define ARMV8_PMUV3_PERFCTR_L21_TLB_REFILL                     0x2E
+#define ARMV8_PMUV3_PERFCTR_L2D_TLB                            0x2F
+#define ARMV8_PMUV3_PERFCTR_L21_TLB                            0x30
 
 /* ARMv8 Cortex-A53 specific event types. */
-enum armv8_a53_pmu_perf_types {
-       ARMV8_A53_PERFCTR_PREFETCH_LINEFILL                     = 0xC2,
-};
+#define ARMV8_A53_PERFCTR_PREFETCH_LINEFILL                    0xC2
 
-/* ARMv8 Cortex-A57 specific event types. */
-enum armv8_a57_perf_types {
-       ARMV8_A57_PERFCTR_L1_DCACHE_ACCESS_LD                   = 0x40,
-       ARMV8_A57_PERFCTR_L1_DCACHE_ACCESS_ST                   = 0x41,
-       ARMV8_A57_PERFCTR_L1_DCACHE_REFILL_LD                   = 0x42,
-       ARMV8_A57_PERFCTR_L1_DCACHE_REFILL_ST                   = 0x43,
-       ARMV8_A57_PERFCTR_DTLB_REFILL_LD                        = 0x4c,
-       ARMV8_A57_PERFCTR_DTLB_REFILL_ST                        = 0x4d,
-};
+/* ARMv8 Cortex-A57 and Cortex-A72 specific event types. */
+#define ARMV8_A57_PERFCTR_L1_DCACHE_ACCESS_LD                  0x40
+#define ARMV8_A57_PERFCTR_L1_DCACHE_ACCESS_ST                  0x41
+#define ARMV8_A57_PERFCTR_L1_DCACHE_REFILL_LD                  0x42
+#define ARMV8_A57_PERFCTR_L1_DCACHE_REFILL_ST                  0x43
+#define ARMV8_A57_PERFCTR_DTLB_REFILL_LD                       0x4c
+#define ARMV8_A57_PERFCTR_DTLB_REFILL_ST                       0x4d
 
 /* PMUv3 HW events mapping. */
 static const unsigned armv8_pmuv3_perf_map[PERF_COUNT_HW_MAX] = {
@@ -106,6 +120,7 @@ static const unsigned armv8_a53_perf_map[PERF_COUNT_HW_MAX] = {
        [PERF_COUNT_HW_BUS_CYCLES]              = ARMV8_PMUV3_PERFCTR_BUS_CYCLES,
 };
 
+/* ARM Cortex-A57 and Cortex-A72 events mapping. */
 static const unsigned armv8_a57_perf_map[PERF_COUNT_HW_MAX] = {
        PERF_MAP_ALL_UNSUPPORTED,
        [PERF_COUNT_HW_CPU_CYCLES]              = ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES,
@@ -178,6 +193,137 @@ static const unsigned armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
        [C(BPU)][C(OP_WRITE)][C(RESULT_MISS)]   = ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED,
 };
 
+#define ARMV8_EVENT_ATTR_RESOLVE(m) #m
+#define ARMV8_EVENT_ATTR(name, config) \
+       PMU_EVENT_ATTR_STRING(name, armv8_event_attr_##name, \
+                             "event=" ARMV8_EVENT_ATTR_RESOLVE(config))
+
+ARMV8_EVENT_ATTR(sw_incr, ARMV8_PMUV3_PERFCTR_PMNC_SW_INCR);
+ARMV8_EVENT_ATTR(l1i_cache_refill, ARMV8_PMUV3_PERFCTR_L1_ICACHE_REFILL);
+ARMV8_EVENT_ATTR(l1i_tlb_refill, ARMV8_PMUV3_PERFCTR_ITLB_REFILL);
+ARMV8_EVENT_ATTR(l1d_cache_refill, ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL);
+ARMV8_EVENT_ATTR(l1d_cache, ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS);
+ARMV8_EVENT_ATTR(l1d_tlb_refill, ARMV8_PMUV3_PERFCTR_DTLB_REFILL);
+ARMV8_EVENT_ATTR(ld_retired, ARMV8_PMUV3_PERFCTR_MEM_READ);
+ARMV8_EVENT_ATTR(st_retired, ARMV8_PMUV3_PERFCTR_MEM_WRITE);
+ARMV8_EVENT_ATTR(inst_retired, ARMV8_PMUV3_PERFCTR_INSTR_EXECUTED);
+ARMV8_EVENT_ATTR(exc_taken, ARMV8_PMUV3_PERFCTR_EXC_TAKEN);
+ARMV8_EVENT_ATTR(exc_return, ARMV8_PMUV3_PERFCTR_EXC_EXECUTED);
+ARMV8_EVENT_ATTR(cid_write_retired, ARMV8_PMUV3_PERFCTR_CID_WRITE);
+ARMV8_EVENT_ATTR(pc_write_retired, ARMV8_PMUV3_PERFCTR_PC_WRITE);
+ARMV8_EVENT_ATTR(br_immed_retired, ARMV8_PMUV3_PERFCTR_PC_IMM_BRANCH);
+ARMV8_EVENT_ATTR(br_return_retired, ARMV8_PMUV3_PERFCTR_PC_PROC_RETURN);
+ARMV8_EVENT_ATTR(unaligned_ldst_retired, ARMV8_PMUV3_PERFCTR_MEM_UNALIGNED_ACCESS);
+ARMV8_EVENT_ATTR(br_mis_pred, ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED);
+ARMV8_EVENT_ATTR(cpu_cycles, ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES);
+ARMV8_EVENT_ATTR(br_pred, ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED);
+ARMV8_EVENT_ATTR(mem_access, ARMV8_PMUV3_PERFCTR_MEM_ACCESS);
+ARMV8_EVENT_ATTR(l1i_cache, ARMV8_PMUV3_PERFCTR_L1_ICACHE_ACCESS);
+ARMV8_EVENT_ATTR(l1d_cache_wb, ARMV8_PMUV3_PERFCTR_L1_DCACHE_WB);
+ARMV8_EVENT_ATTR(l2d_cache, ARMV8_PMUV3_PERFCTR_L2_CACHE_ACCESS);
+ARMV8_EVENT_ATTR(l2d_cache_refill, ARMV8_PMUV3_PERFCTR_L2_CACHE_REFILL);
+ARMV8_EVENT_ATTR(l2d_cache_wb, ARMV8_PMUV3_PERFCTR_L2_CACHE_WB);
+ARMV8_EVENT_ATTR(bus_access, ARMV8_PMUV3_PERFCTR_BUS_ACCESS);
+ARMV8_EVENT_ATTR(memory_error, ARMV8_PMUV3_PERFCTR_MEM_ERROR);
+ARMV8_EVENT_ATTR(inst_spec, ARMV8_PMUV3_PERFCTR_OP_SPEC);
+ARMV8_EVENT_ATTR(ttbr_write_retired, ARMV8_PMUV3_PERFCTR_TTBR_WRITE);
+ARMV8_EVENT_ATTR(bus_cycles, ARMV8_PMUV3_PERFCTR_BUS_CYCLES);
+ARMV8_EVENT_ATTR(chain, ARMV8_PMUV3_PERFCTR_CHAIN);
+ARMV8_EVENT_ATTR(l1d_cache_allocate, ARMV8_PMUV3_PERFCTR_L1D_CACHE_ALLOCATE);
+ARMV8_EVENT_ATTR(l2d_cache_allocate, ARMV8_PMUV3_PERFCTR_L2D_CACHE_ALLOCATE);
+ARMV8_EVENT_ATTR(br_retired, ARMV8_PMUV3_PERFCTR_BR_RETIRED);
+ARMV8_EVENT_ATTR(br_mis_pred_retired, ARMV8_PMUV3_PERFCTR_BR_MIS_PRED_RETIRED);
+ARMV8_EVENT_ATTR(stall_frontend, ARMV8_PMUV3_PERFCTR_STALL_FRONTEND);
+ARMV8_EVENT_ATTR(stall_backend, ARMV8_PMUV3_PERFCTR_STALL_BACKEND);
+ARMV8_EVENT_ATTR(l1d_tlb, ARMV8_PMUV3_PERFCTR_L1D_TLB);
+ARMV8_EVENT_ATTR(l1i_tlb, ARMV8_PMUV3_PERFCTR_L1I_TLB);
+ARMV8_EVENT_ATTR(l2i_cache, ARMV8_PMUV3_PERFCTR_L2I_CACHE);
+ARMV8_EVENT_ATTR(l2i_cache_refill, ARMV8_PMUV3_PERFCTR_L2I_CACHE_REFILL);
+ARMV8_EVENT_ATTR(l3d_cache_allocate, ARMV8_PMUV3_PERFCTR_L3D_CACHE_ALLOCATE);
+ARMV8_EVENT_ATTR(l3d_cache_refill, ARMV8_PMUV3_PERFCTR_L3D_CACHE_REFILL);
+ARMV8_EVENT_ATTR(l3d_cache, ARMV8_PMUV3_PERFCTR_L3D_CACHE);
+ARMV8_EVENT_ATTR(l3d_cache_wb, ARMV8_PMUV3_PERFCTR_L3D_CACHE_WB);
+ARMV8_EVENT_ATTR(l2d_tlb_refill, ARMV8_PMUV3_PERFCTR_L2D_TLB_REFILL);
+ARMV8_EVENT_ATTR(l21_tlb_refill, ARMV8_PMUV3_PERFCTR_L21_TLB_REFILL);
+ARMV8_EVENT_ATTR(l2d_tlb, ARMV8_PMUV3_PERFCTR_L2D_TLB);
+ARMV8_EVENT_ATTR(l21_tlb, ARMV8_PMUV3_PERFCTR_L21_TLB);
+
+static struct attribute *armv8_pmuv3_event_attrs[] = {
+       &armv8_event_attr_sw_incr.attr.attr,
+       &armv8_event_attr_l1i_cache_refill.attr.attr,
+       &armv8_event_attr_l1i_tlb_refill.attr.attr,
+       &armv8_event_attr_l1d_cache_refill.attr.attr,
+       &armv8_event_attr_l1d_cache.attr.attr,
+       &armv8_event_attr_l1d_tlb_refill.attr.attr,
+       &armv8_event_attr_ld_retired.attr.attr,
+       &armv8_event_attr_st_retired.attr.attr,
+       &armv8_event_attr_inst_retired.attr.attr,
+       &armv8_event_attr_exc_taken.attr.attr,
+       &armv8_event_attr_exc_return.attr.attr,
+       &armv8_event_attr_cid_write_retired.attr.attr,
+       &armv8_event_attr_pc_write_retired.attr.attr,
+       &armv8_event_attr_br_immed_retired.attr.attr,
+       &armv8_event_attr_br_return_retired.attr.attr,
+       &armv8_event_attr_unaligned_ldst_retired.attr.attr,
+       &armv8_event_attr_br_mis_pred.attr.attr,
+       &armv8_event_attr_cpu_cycles.attr.attr,
+       &armv8_event_attr_br_pred.attr.attr,
+       &armv8_event_attr_mem_access.attr.attr,
+       &armv8_event_attr_l1i_cache.attr.attr,
+       &armv8_event_attr_l1d_cache_wb.attr.attr,
+       &armv8_event_attr_l2d_cache.attr.attr,
+       &armv8_event_attr_l2d_cache_refill.attr.attr,
+       &armv8_event_attr_l2d_cache_wb.attr.attr,
+       &armv8_event_attr_bus_access.attr.attr,
+       &armv8_event_attr_memory_error.attr.attr,
+       &armv8_event_attr_inst_spec.attr.attr,
+       &armv8_event_attr_ttbr_write_retired.attr.attr,
+       &armv8_event_attr_bus_cycles.attr.attr,
+       &armv8_event_attr_chain.attr.attr,
+       &armv8_event_attr_l1d_cache_allocate.attr.attr,
+       &armv8_event_attr_l2d_cache_allocate.attr.attr,
+       &armv8_event_attr_br_retired.attr.attr,
+       &armv8_event_attr_br_mis_pred_retired.attr.attr,
+       &armv8_event_attr_stall_frontend.attr.attr,
+       &armv8_event_attr_stall_backend.attr.attr,
+       &armv8_event_attr_l1d_tlb.attr.attr,
+       &armv8_event_attr_l1i_tlb.attr.attr,
+       &armv8_event_attr_l2i_cache.attr.attr,
+       &armv8_event_attr_l2i_cache_refill.attr.attr,
+       &armv8_event_attr_l3d_cache_allocate.attr.attr,
+       &armv8_event_attr_l3d_cache_refill.attr.attr,
+       &armv8_event_attr_l3d_cache.attr.attr,
+       &armv8_event_attr_l3d_cache_wb.attr.attr,
+       &armv8_event_attr_l2d_tlb_refill.attr.attr,
+       &armv8_event_attr_l21_tlb_refill.attr.attr,
+       &armv8_event_attr_l2d_tlb.attr.attr,
+       &armv8_event_attr_l21_tlb.attr.attr,
+       NULL,
+};
+
+static struct attribute_group armv8_pmuv3_events_attr_group = {
+       .name = "events",
+       .attrs = armv8_pmuv3_event_attrs,
+};
+
+PMU_FORMAT_ATTR(event, "config:0-9");
+
+static struct attribute *armv8_pmuv3_format_attrs[] = {
+       &format_attr_event.attr,
+       NULL,
+};
+
+static struct attribute_group armv8_pmuv3_format_attr_group = {
+       .name = "format",
+       .attrs = armv8_pmuv3_format_attrs,
+};
+
+static const struct attribute_group *armv8_pmuv3_attr_groups[] = {
+       &armv8_pmuv3_events_attr_group,
+       &armv8_pmuv3_format_attr_group,
+       NULL,
+};
+
 
 /*
  * Perf Events' indices
@@ -574,9 +720,6 @@ static void armv8pmu_reset(void *info)
 
        /* Initialize & Reset PMNC: C and P bits. */
        armv8pmu_pmcr_write(ARMV8_PMCR_P | ARMV8_PMCR_C);
-
-       /* Disable access from userspace. */
-       asm volatile("msr pmuserenr_el0, %0" :: "r" (0));
 }
 
 static int armv8_pmuv3_map_event(struct perf_event *event)
@@ -646,6 +789,7 @@ static int armv8_a53_pmu_init(struct arm_pmu *cpu_pmu)
        armv8_pmu_init(cpu_pmu);
        cpu_pmu->name                   = "armv8_cortex_a53";
        cpu_pmu->map_event              = armv8_a53_map_event;
+       cpu_pmu->pmu.attr_groups        = armv8_pmuv3_attr_groups;
        return armv8pmu_probe_num_events(cpu_pmu);
 }
 
@@ -654,6 +798,16 @@ static int armv8_a57_pmu_init(struct arm_pmu *cpu_pmu)
        armv8_pmu_init(cpu_pmu);
        cpu_pmu->name                   = "armv8_cortex_a57";
        cpu_pmu->map_event              = armv8_a57_map_event;
+       cpu_pmu->pmu.attr_groups        = armv8_pmuv3_attr_groups;
+       return armv8pmu_probe_num_events(cpu_pmu);
+}
+
+static int armv8_a72_pmu_init(struct arm_pmu *cpu_pmu)
+{
+       armv8_pmu_init(cpu_pmu);
+       cpu_pmu->name                   = "armv8_cortex_a72";
+       cpu_pmu->map_event              = armv8_a57_map_event;
+       cpu_pmu->pmu.attr_groups        = armv8_pmuv3_attr_groups;
        return armv8pmu_probe_num_events(cpu_pmu);
 }
 
@@ -661,6 +815,7 @@ static const struct of_device_id armv8_pmu_of_device_ids[] = {
        {.compatible = "arm,armv8-pmuv3",       .data = armv8_pmuv3_init},
        {.compatible = "arm,cortex-a53-pmu",    .data = armv8_a53_pmu_init},
        {.compatible = "arm,cortex-a57-pmu",    .data = armv8_a57_pmu_init},
+       {.compatible = "arm,cortex-a72-pmu",    .data = armv8_a72_pmu_init},
        {},
 };
 
index f75b540bc3b4b0daae4a8773cd0eddf1a86a90aa..88d742ba19d50590561c741ff3a1d48ba49c0ce3 100644 (file)
@@ -344,11 +344,14 @@ unsigned long get_wchan(struct task_struct *p)
        frame.fp = thread_saved_fp(p);
        frame.sp = thread_saved_sp(p);
        frame.pc = thread_saved_pc(p);
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       frame.graph = p->curr_ret_stack;
+#endif
        stack_page = (unsigned long)task_stack_page(p);
        do {
                if (frame.sp < stack_page ||
                    frame.sp >= stack_page + THREAD_SIZE ||
-                   unwind_frame(&frame))
+                   unwind_frame(p, &frame))
                        return 0;
                if (!in_sched_functions(frame.pc))
                        return frame.pc;
diff --git a/arch/arm64/kernel/psci-call.S b/arch/arm64/kernel/psci-call.S
deleted file mode 100644 (file)
index cf83e61..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * Copyright (C) 2015 ARM Limited
- *
- * Author: Will Deacon <will.deacon@arm.com>
- */
-
-#include <linux/linkage.h>
-
-/* int __invoke_psci_fn_hvc(u64 function_id, u64 arg0, u64 arg1, u64 arg2) */
-ENTRY(__invoke_psci_fn_hvc)
-       hvc     #0
-       ret
-ENDPROC(__invoke_psci_fn_hvc)
-
-/* int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1, u64 arg2) */
-ENTRY(__invoke_psci_fn_smc)
-       smc     #0
-       ret
-ENDPROC(__invoke_psci_fn_smc)
index 1971f491bb90c28d279b4e9b799aa64f8923c849..ff7f13239515676262864f3c9d1a7a938c7e63d3 100644 (file)
  */
 void ptrace_disable(struct task_struct *child)
 {
+       /*
+        * This would be better off in core code, but PTRACE_DETACH has
+        * grown its fair share of arch-specific worts and changing it
+        * is likely to cause regressions on obscure architectures.
+        */
+       user_disable_single_step(child);
 }
 
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
index 6c4fd2810ecb35b3e648db18923d21f19a50f422..1718706fde83604f78d81d850bf8827705338f1a 100644 (file)
@@ -43,8 +43,11 @@ void *return_address(unsigned int level)
        frame.fp = (unsigned long)__builtin_frame_address(0);
        frame.sp = current_stack_pointer;
        frame.pc = (unsigned long)return_address; /* dummy */
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       frame.graph = current->curr_ret_stack;
+#endif
 
-       walk_stackframe(&frame, save_return_addr, &data);
+       walk_stackframe(current, &frame, save_return_addr, &data);
 
        if (!data.level)
                return data.addr;
index f586f7c875e29295b6094efd4967e26cb6d01a99..e33fe33876ab3804f2c6dcd6c5458e576596ef24 100644 (file)
@@ -173,6 +173,9 @@ ENTRY(cpu_resume)
        /* load physical address of identity map page table in x1 */
        adrp    x1, idmap_pg_dir
        mov     sp, x2
+       /* save thread_info */
+       and     x2, x2, #~(THREAD_SIZE - 1)
+       msr     sp_el0, x2
        /*
         * cpu_do_resume expects x0 to contain context physical address
         * pointer and x1 to contain physical address of 1:1 page tables
diff --git a/arch/arm64/kernel/smccc-call.S b/arch/arm64/kernel/smccc-call.S
new file mode 100644 (file)
index 0000000..ae0496f
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * 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/linkage.h>
+#include <asm/asm-offsets.h>
+
+       .macro SMCCC instr
+       .cfi_startproc
+       \instr  #0
+       ldr     x4, [sp]
+       stp     x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS]
+       stp     x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS]
+       ret
+       .cfi_endproc
+       .endm
+
+/*
+ * void arm_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2,
+ *               unsigned long a3, unsigned long a4, unsigned long a5,
+ *               unsigned long a6, unsigned long a7, struct arm_smccc_res *res)
+ */
+ENTRY(arm_smccc_smc)
+       SMCCC   smc
+ENDPROC(arm_smccc_smc)
+
+/*
+ * void arm_smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2,
+ *               unsigned long a3, unsigned long a4, unsigned long a5,
+ *               unsigned long a6, unsigned long a7, struct arm_smccc_res *res)
+ */
+ENTRY(arm_smccc_hvc)
+       SMCCC   hvc
+ENDPROC(arm_smccc_hvc)
index ccb6078ed9f20fb55132deb48504df3a3134a784..4fad9787ab46ed04bf36873e8f7f7eb724beb262 100644 (file)
  */
 #include <linux/kernel.h>
 #include <linux/export.h>
+#include <linux/ftrace.h>
 #include <linux/sched.h>
 #include <linux/stacktrace.h>
 
+#include <asm/irq.h>
 #include <asm/stacktrace.h>
 
 /*
  *     ldp     x29, x30, [sp]
  *     add     sp, sp, #0x10
  */
-int notrace unwind_frame(struct stackframe *frame)
+int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
 {
        unsigned long high, low;
        unsigned long fp = frame->fp;
+       unsigned long irq_stack_ptr;
+
+       /*
+        * Use raw_smp_processor_id() to avoid false-positives from
+        * CONFIG_DEBUG_PREEMPT. get_wchan() calls unwind_frame() on sleeping
+        * task stacks, we can be pre-empted in this case, so
+        * {raw_,}smp_processor_id() may give us the wrong value. Sleeping
+        * tasks can't ever be on an interrupt stack, so regardless of cpu,
+        * the checks will always fail.
+        */
+       irq_stack_ptr = IRQ_STACK_PTR(raw_smp_processor_id());
 
        low  = frame->sp;
-       high = ALIGN(low, THREAD_SIZE);
+       /* irq stacks are not THREAD_SIZE aligned */
+       if (on_irq_stack(frame->sp, raw_smp_processor_id()))
+               high = irq_stack_ptr;
+       else
+               high = ALIGN(low, THREAD_SIZE) - 0x20;
 
-       if (fp < low || fp > high - 0x18 || fp & 0xf)
+       if (fp < low || fp > high || fp & 0xf)
                return -EINVAL;
 
        frame->sp = fp + 0x10;
        frame->fp = *(unsigned long *)(fp);
        frame->pc = *(unsigned long *)(fp + 8);
 
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       if (tsk && tsk->ret_stack &&
+                       (frame->pc == (unsigned long)return_to_handler)) {
+               /*
+                * This is a case where function graph tracer has
+                * modified a return address (LR) in a stack frame
+                * to hook a function return.
+                * So replace it to an original value.
+                */
+               frame->pc = tsk->ret_stack[frame->graph--].ret;
+       }
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+       /*
+        * Check whether we are going to walk through from interrupt stack
+        * to task stack.
+        * If we reach the end of the stack - and its an interrupt stack,
+        * unpack the dummy frame to find the original elr.
+        *
+        * Check the frame->fp we read from the bottom of the irq_stack,
+        * and the original task stack pointer are both in current->stack.
+        */
+       if (frame->sp == irq_stack_ptr) {
+               struct pt_regs *irq_args;
+               unsigned long orig_sp = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr);
+
+               if (object_is_on_stack((void *)orig_sp) &&
+                  object_is_on_stack((void *)frame->fp)) {
+                       frame->sp = orig_sp;
+
+                       /* orig_sp is the saved pt_regs, find the elr */
+                       irq_args = (struct pt_regs *)orig_sp;
+                       frame->pc = irq_args->pc;
+               } else {
+                       /*
+                        * This frame has a non-standard format, and we
+                        * didn't fix it, because the data looked wrong.
+                        * Refuse to output this frame.
+                        */
+                       return -EINVAL;
+               }
+       }
+
        return 0;
 }
 
-void notrace walk_stackframe(struct stackframe *frame,
+void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
                     int (*fn)(struct stackframe *, void *), void *data)
 {
        while (1) {
@@ -61,7 +121,7 @@ void notrace walk_stackframe(struct stackframe *frame,
 
                if (fn(frame, data))
                        break;
-               ret = unwind_frame(frame);
+               ret = unwind_frame(tsk, frame);
                if (ret < 0)
                        break;
        }
@@ -112,8 +172,11 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
                frame.sp = current_stack_pointer;
                frame.pc = (unsigned long)save_stack_trace_tsk;
        }
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       frame.graph = tsk->curr_ret_stack;
+#endif
 
-       walk_stackframe(&frame, save_trace, &data);
+       walk_stackframe(tsk, &frame, save_trace, &data);
        if (trace->nr_entries < trace->max_entries)
                trace->entries[trace->nr_entries++] = ULONG_MAX;
 }
index 13339b6ffc1a07839103fca328f1eccd6d185c12..59779699a1a40ef3a1940aa0d878c16164ea5398 100644 (file)
@@ -52,8 +52,11 @@ unsigned long profile_pc(struct pt_regs *regs)
        frame.fp = regs->regs[29];
        frame.sp = regs->sp;
        frame.pc = regs->pc;
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       frame.graph = -1; /* no task info */
+#endif
        do {
-               int ret = unwind_frame(&frame);
+               int ret = unwind_frame(NULL, &frame);
                if (ret < 0)
                        return 0;
        } while (in_lock_functions(frame.pc));
index e9b9b53643936a121e8c73db99373d7e7cab9b48..cbedd724f48efcf487e443fa3fc21516d8d898a6 100644 (file)
@@ -146,17 +146,15 @@ static void dump_instr(const char *lvl, struct pt_regs *regs)
 static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
 {
        struct stackframe frame;
+       unsigned long irq_stack_ptr = IRQ_STACK_PTR(smp_processor_id());
+       int skip;
 
        pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
 
        if (!tsk)
                tsk = current;
 
-       if (regs) {
-               frame.fp = regs->regs[29];
-               frame.sp = regs->sp;
-               frame.pc = regs->pc;
-       } else if (tsk == current) {
+       if (tsk == current) {
                frame.fp = (unsigned long)__builtin_frame_address(0);
                frame.sp = current_stack_pointer;
                frame.pc = (unsigned long)dump_backtrace;
@@ -168,21 +166,49 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
                frame.sp = thread_saved_sp(tsk);
                frame.pc = thread_saved_pc(tsk);
        }
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       frame.graph = tsk->curr_ret_stack;
+#endif
 
-       pr_emerg("Call trace:\n");
+       skip = !!regs;
+       printk("Call trace:\n");
        while (1) {
                unsigned long where = frame.pc;
                unsigned long stack;
                int ret;
 
-               dump_backtrace_entry(where);
-               ret = unwind_frame(&frame);
+               /* skip until specified stack frame */
+               if (!skip) {
+                       dump_backtrace_entry(where);
+               } else if (frame.fp == regs->regs[29]) {
+                       skip = 0;
+                       /*
+                        * Mostly, this is the case where this function is
+                        * called in panic/abort. As exception handler's
+                        * stack frame does not contain the corresponding pc
+                        * at which an exception has taken place, use regs->pc
+                        * instead.
+                        */
+                       dump_backtrace_entry(regs->pc);
+               }
+               ret = unwind_frame(tsk, &frame);
                if (ret < 0)
                        break;
                stack = frame.sp;
-               if (in_exception_text(where))
+               if (in_exception_text(where)) {
+                       /*
+                        * If we switched to the irq_stack before calling this
+                        * exception handler, then the pt_regs will be on the
+                        * task stack. The easiest way to tell is if the large
+                        * pt_regs would overlap with the end of the irq_stack.
+                        */
+                       if (stack < irq_stack_ptr &&
+                           (stack + sizeof(struct pt_regs)) > irq_stack_ptr)
+                               stack = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr);
+
                        dump_mem("", "Exception stack", stack,
                                 stack + sizeof(struct pt_regs), false);
+               }
        }
 }
 
@@ -456,22 +482,22 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
 
 void __pte_error(const char *file, int line, unsigned long val)
 {
-       pr_crit("%s:%d: bad pte %016lx.\n", file, line, val);
+       pr_err("%s:%d: bad pte %016lx.\n", file, line, val);
 }
 
 void __pmd_error(const char *file, int line, unsigned long val)
 {
-       pr_crit("%s:%d: bad pmd %016lx.\n", file, line, val);
+       pr_err("%s:%d: bad pmd %016lx.\n", file, line, val);
 }
 
 void __pud_error(const char *file, int line, unsigned long val)
 {
-       pr_crit("%s:%d: bad pud %016lx.\n", file, line, val);
+       pr_err("%s:%d: bad pud %016lx.\n", file, line, val);
 }
 
 void __pgd_error(const char *file, int line, unsigned long val)
 {
-       pr_crit("%s:%d: bad pgd %016lx.\n", file, line, val);
+       pr_err("%s:%d: bad pgd %016lx.\n", file, line, val);
 }
 
 /* GENERIC_BUG traps */
index 71426a78db123d13e98acf8659d65155ff342a06..e3928f578891fdd0a5d3535975d350b6489f8df1 100644 (file)
@@ -113,7 +113,6 @@ SECTIONS
                *(.got)                 /* Global offset table          */
        }
 
-       ALIGN_DEBUG_RO
        RO_DATA(PAGE_SIZE)
        EXCEPTION_TABLE(8)
        NOTES
@@ -128,7 +127,6 @@ SECTIONS
                ARM_EXIT_KEEP(EXIT_TEXT)
        }
 
-       ALIGN_DEBUG_RO_MIN(16)
        .init.data : {
                INIT_DATA
                INIT_SETUP(16)
@@ -143,9 +141,6 @@ SECTIONS
 
        PERCPU_SECTION(L1_CACHE_BYTES)
 
-       . = ALIGN(PAGE_SIZE);
-       __init_end = .;
-
        . = ALIGN(4);
        .altinstructions : {
                __alt_instructions = .;
@@ -157,6 +152,8 @@ SECTIONS
        }
 
        . = ALIGN(PAGE_SIZE);
+       __init_end = .;
+
        _data = .;
        _sdata = .;
        RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE)
index 1949fe5f54246a3f14983753570f4e4d0f978e76..caee9ee8e12af1eef4c13ebd1f750d7a3b5ee7f2 100644 (file)
@@ -10,6 +10,7 @@ KVM=../../../virt/kvm
 ARM=../../../arch/arm/kvm
 
 obj-$(CONFIG_KVM_ARM_HOST) += kvm.o
+obj-$(CONFIG_KVM_ARM_HOST) += hyp/
 
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o $(KVM)/vfio.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(ARM)/arm.o $(ARM)/mmu.o $(ARM)/mmio.o
@@ -22,8 +23,6 @@ kvm-$(CONFIG_KVM_ARM_HOST) += guest.o debug.o reset.o sys_regs.o sys_regs_generi
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2-emul.o
-kvm-$(CONFIG_KVM_ARM_HOST) += vgic-v2-switch.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
-kvm-$(CONFIG_KVM_ARM_HOST) += vgic-v3-switch.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
index d250160d32bc68ae636c804b9cdfe2499bdddcb9..fcb778899a3804455f2e9ef5f3fad33456d2d96e 100644 (file)
 #include <asm/cputype.h>
 #include <asm/uaccess.h>
 #include <asm/kvm.h>
-#include <asm/kvm_asm.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_coproc.h>
 
 #include "trace.h"
 
+#define VM_STAT(x) { #x, offsetof(struct kvm, stat.x), KVM_STAT_VM }
+#define VCPU_STAT(x) { #x, offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU }
+
 struct kvm_stats_debugfs_item debugfs_entries[] = {
+       VCPU_STAT(hvc_exit_stat),
+       VCPU_STAT(wfe_exit_stat),
+       VCPU_STAT(wfi_exit_stat),
+       VCPU_STAT(mmio_exit_user),
+       VCPU_STAT(mmio_exit_kernel),
+       VCPU_STAT(exits),
        { NULL }
 };
 
index 15f0477b0d2adc53d86573b1733d2fa7f368bbd9..eba89e42f0ed377f76588f2821d2b4b224d0280e 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/kvm_host.h>
 
 #include <asm/esr.h>
+#include <asm/kvm_asm.h>
 #include <asm/kvm_coproc.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_mmu.h>
@@ -39,6 +40,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
        trace_kvm_hvc_arm64(*vcpu_pc(vcpu), vcpu_get_reg(vcpu, 0),
                            kvm_vcpu_hvc_get_imm(vcpu));
+       vcpu->stat.hvc_exit_stat++;
 
        ret = kvm_psci_call(vcpu);
        if (ret < 0) {
@@ -71,9 +73,11 @@ static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
        if (kvm_vcpu_get_hsr(vcpu) & ESR_ELx_WFx_ISS_WFE) {
                trace_kvm_wfx_arm64(*vcpu_pc(vcpu), true);
+               vcpu->stat.wfe_exit_stat++;
                kvm_vcpu_on_spin(vcpu);
        } else {
                trace_kvm_wfx_arm64(*vcpu_pc(vcpu), false);
+               vcpu->stat.wfi_exit_stat++;
                kvm_vcpu_block(vcpu);
        }
 
index 178ba2248a9804b82157f392e16026b010cb76b6..3e568dcd907b8c82806ee4c2bf4f355e64cf7d51 100644 (file)
@@ -94,6 +94,15 @@ __do_hyp_init:
         */
        mrs     x5, ID_AA64MMFR0_EL1
        bfi     x4, x5, #16, #3
+       /*
+        * Read the VMIDBits bits from ID_AA64MMFR1_EL1 and set the VS bit in
+        * VTCR_EL2.
+        */
+       mrs     x5, ID_AA64MMFR1_EL1
+       ubfx    x5, x5, #5, #1
+       lsl     x5, x5, #VTCR_EL2_VS
+       orr     x4, x4, x5
+
        msr     vtcr_el2, x4
 
        mrs     x4, mair_el1
index 86c289832272d71ba48786414bb6e4ecb9b9cb14..0ccdcbbef3c20ce0b4afa9874eb128cf55beb683 100644 (file)
 
 #include <linux/linkage.h>
 
-#include <asm/alternative.h>
-#include <asm/asm-offsets.h>
 #include <asm/assembler.h>
-#include <asm/cpufeature.h>
-#include <asm/debug-monitors.h>
-#include <asm/esr.h>
-#include <asm/fpsimdmacros.h>
-#include <asm/kvm.h>
-#include <asm/kvm_arm.h>
-#include <asm/kvm_asm.h>
-#include <asm/kvm_mmu.h>
-#include <asm/memory.h>
-
-#define CPU_GP_REG_OFFSET(x)   (CPU_GP_REGS + x)
-#define CPU_XREG_OFFSET(x)     CPU_GP_REG_OFFSET(CPU_USER_PT_REGS + 8*x)
-#define CPU_SPSR_OFFSET(x)     CPU_GP_REG_OFFSET(CPU_SPSR + 8*x)
-#define CPU_SYSREG_OFFSET(x)   (CPU_SYSREGS + 8*x)
-
-       .text
-       .pushsection    .hyp.text, "ax"
-       .align  PAGE_SHIFT
-
-.macro save_common_regs
-       // x2: base address for cpu context
-       // x3: tmp register
-
-       add     x3, x2, #CPU_XREG_OFFSET(19)
-       stp     x19, x20, [x3]
-       stp     x21, x22, [x3, #16]
-       stp     x23, x24, [x3, #32]
-       stp     x25, x26, [x3, #48]
-       stp     x27, x28, [x3, #64]
-       stp     x29, lr, [x3, #80]
-
-       mrs     x19, sp_el0
-       mrs     x20, elr_el2            // pc before entering el2
-       mrs     x21, spsr_el2           // pstate before entering el2
-
-       stp     x19, x20, [x3, #96]
-       str     x21, [x3, #112]
-
-       mrs     x22, sp_el1
-       mrs     x23, elr_el1
-       mrs     x24, spsr_el1
-
-       str     x22, [x2, #CPU_GP_REG_OFFSET(CPU_SP_EL1)]
-       str     x23, [x2, #CPU_GP_REG_OFFSET(CPU_ELR_EL1)]
-       str     x24, [x2, #CPU_SPSR_OFFSET(KVM_SPSR_EL1)]
-.endm
-
-.macro restore_common_regs
-       // x2: base address for cpu context
-       // x3: tmp register
-
-       ldr     x22, [x2, #CPU_GP_REG_OFFSET(CPU_SP_EL1)]
-       ldr     x23, [x2, #CPU_GP_REG_OFFSET(CPU_ELR_EL1)]
-       ldr     x24, [x2, #CPU_SPSR_OFFSET(KVM_SPSR_EL1)]
-
-       msr     sp_el1, x22
-       msr     elr_el1, x23
-       msr     spsr_el1, x24
-
-       add     x3, x2, #CPU_XREG_OFFSET(31)    // SP_EL0
-       ldp     x19, x20, [x3]
-       ldr     x21, [x3, #16]
-
-       msr     sp_el0, x19
-       msr     elr_el2, x20            // pc on return from el2
-       msr     spsr_el2, x21           // pstate on return from el2
-
-       add     x3, x2, #CPU_XREG_OFFSET(19)
-       ldp     x19, x20, [x3]
-       ldp     x21, x22, [x3, #16]
-       ldp     x23, x24, [x3, #32]
-       ldp     x25, x26, [x3, #48]
-       ldp     x27, x28, [x3, #64]
-       ldp     x29, lr, [x3, #80]
-.endm
-
-.macro save_host_regs
-       save_common_regs
-.endm
-
-.macro restore_host_regs
-       restore_common_regs
-.endm
-
-.macro save_fpsimd
-       // x2: cpu context address
-       // x3, x4: tmp regs
-       add     x3, x2, #CPU_GP_REG_OFFSET(CPU_FP_REGS)
-       fpsimd_save x3, 4
-.endm
-
-.macro restore_fpsimd
-       // x2: cpu context address
-       // x3, x4: tmp regs
-       add     x3, x2, #CPU_GP_REG_OFFSET(CPU_FP_REGS)
-       fpsimd_restore x3, 4
-.endm
-
-.macro save_guest_regs
-       // x0 is the vcpu address
-       // x1 is the return code, do not corrupt!
-       // x2 is the cpu context
-       // x3 is a tmp register
-       // Guest's x0-x3 are on the stack
-
-       // Compute base to save registers
-       add     x3, x2, #CPU_XREG_OFFSET(4)
-       stp     x4, x5, [x3]
-       stp     x6, x7, [x3, #16]
-       stp     x8, x9, [x3, #32]
-       stp     x10, x11, [x3, #48]
-       stp     x12, x13, [x3, #64]
-       stp     x14, x15, [x3, #80]
-       stp     x16, x17, [x3, #96]
-       str     x18, [x3, #112]
-
-       pop     x6, x7                  // x2, x3
-       pop     x4, x5                  // x0, x1
-
-       add     x3, x2, #CPU_XREG_OFFSET(0)
-       stp     x4, x5, [x3]
-       stp     x6, x7, [x3, #16]
-
-       save_common_regs
-.endm
-
-.macro restore_guest_regs
-       // x0 is the vcpu address.
-       // x2 is the cpu context
-       // x3 is a tmp register
-
-       // Prepare x0-x3 for later restore
-       add     x3, x2, #CPU_XREG_OFFSET(0)
-       ldp     x4, x5, [x3]
-       ldp     x6, x7, [x3, #16]
-       push    x4, x5          // Push x0-x3 on the stack
-       push    x6, x7
-
-       // x4-x18
-       ldp     x4, x5, [x3, #32]
-       ldp     x6, x7, [x3, #48]
-       ldp     x8, x9, [x3, #64]
-       ldp     x10, x11, [x3, #80]
-       ldp     x12, x13, [x3, #96]
-       ldp     x14, x15, [x3, #112]
-       ldp     x16, x17, [x3, #128]
-       ldr     x18, [x3, #144]
-
-       // x19-x29, lr, sp*, elr*, spsr*
-       restore_common_regs
-
-       // Last bits of the 64bit state
-       pop     x2, x3
-       pop     x0, x1
-
-       // Do not touch any register after this!
-.endm
-
-/*
- * Macros to perform system register save/restore.
- *
- * Ordering here is absolutely critical, and must be kept consistent
- * in {save,restore}_sysregs, {save,restore}_guest_32bit_state,
- * and in kvm_asm.h.
- *
- * In other words, don't touch any of these unless you know what
- * you are doing.
- */
-.macro save_sysregs
-       // x2: base address for cpu context
-       // x3: tmp register
-
-       add     x3, x2, #CPU_SYSREG_OFFSET(MPIDR_EL1)
-
-       mrs     x4,     vmpidr_el2
-       mrs     x5,     csselr_el1
-       mrs     x6,     sctlr_el1
-       mrs     x7,     actlr_el1
-       mrs     x8,     cpacr_el1
-       mrs     x9,     ttbr0_el1
-       mrs     x10,    ttbr1_el1
-       mrs     x11,    tcr_el1
-       mrs     x12,    esr_el1
-       mrs     x13,    afsr0_el1
-       mrs     x14,    afsr1_el1
-       mrs     x15,    far_el1
-       mrs     x16,    mair_el1
-       mrs     x17,    vbar_el1
-       mrs     x18,    contextidr_el1
-       mrs     x19,    tpidr_el0
-       mrs     x20,    tpidrro_el0
-       mrs     x21,    tpidr_el1
-       mrs     x22,    amair_el1
-       mrs     x23,    cntkctl_el1
-       mrs     x24,    par_el1
-       mrs     x25,    mdscr_el1
-
-       stp     x4, x5, [x3]
-       stp     x6, x7, [x3, #16]
-       stp     x8, x9, [x3, #32]
-       stp     x10, x11, [x3, #48]
-       stp     x12, x13, [x3, #64]
-       stp     x14, x15, [x3, #80]
-       stp     x16, x17, [x3, #96]
-       stp     x18, x19, [x3, #112]
-       stp     x20, x21, [x3, #128]
-       stp     x22, x23, [x3, #144]
-       stp     x24, x25, [x3, #160]
-.endm
-
-.macro save_debug type
-       // x4: pointer to register set
-       // x5: number of registers to skip
-       // x6..x22 trashed
-
-       adr     x22, 1f
-       add     x22, x22, x5, lsl #2
-       br      x22
-1:
-       mrs     x21, \type\()15_el1
-       mrs     x20, \type\()14_el1
-       mrs     x19, \type\()13_el1
-       mrs     x18, \type\()12_el1
-       mrs     x17, \type\()11_el1
-       mrs     x16, \type\()10_el1
-       mrs     x15, \type\()9_el1
-       mrs     x14, \type\()8_el1
-       mrs     x13, \type\()7_el1
-       mrs     x12, \type\()6_el1
-       mrs     x11, \type\()5_el1
-       mrs     x10, \type\()4_el1
-       mrs     x9, \type\()3_el1
-       mrs     x8, \type\()2_el1
-       mrs     x7, \type\()1_el1
-       mrs     x6, \type\()0_el1
-
-       adr     x22, 1f
-       add     x22, x22, x5, lsl #2
-       br      x22
-1:
-       str     x21, [x4, #(15 * 8)]
-       str     x20, [x4, #(14 * 8)]
-       str     x19, [x4, #(13 * 8)]
-       str     x18, [x4, #(12 * 8)]
-       str     x17, [x4, #(11 * 8)]
-       str     x16, [x4, #(10 * 8)]
-       str     x15, [x4, #(9 * 8)]
-       str     x14, [x4, #(8 * 8)]
-       str     x13, [x4, #(7 * 8)]
-       str     x12, [x4, #(6 * 8)]
-       str     x11, [x4, #(5 * 8)]
-       str     x10, [x4, #(4 * 8)]
-       str     x9, [x4, #(3 * 8)]
-       str     x8, [x4, #(2 * 8)]
-       str     x7, [x4, #(1 * 8)]
-       str     x6, [x4, #(0 * 8)]
-.endm
-
-.macro restore_sysregs
-       // x2: base address for cpu context
-       // x3: tmp register
-
-       add     x3, x2, #CPU_SYSREG_OFFSET(MPIDR_EL1)
-
-       ldp     x4, x5, [x3]
-       ldp     x6, x7, [x3, #16]
-       ldp     x8, x9, [x3, #32]
-       ldp     x10, x11, [x3, #48]
-       ldp     x12, x13, [x3, #64]
-       ldp     x14, x15, [x3, #80]
-       ldp     x16, x17, [x3, #96]
-       ldp     x18, x19, [x3, #112]
-       ldp     x20, x21, [x3, #128]
-       ldp     x22, x23, [x3, #144]
-       ldp     x24, x25, [x3, #160]
-
-       msr     vmpidr_el2,     x4
-       msr     csselr_el1,     x5
-       msr     sctlr_el1,      x6
-       msr     actlr_el1,      x7
-       msr     cpacr_el1,      x8
-       msr     ttbr0_el1,      x9
-       msr     ttbr1_el1,      x10
-       msr     tcr_el1,        x11
-       msr     esr_el1,        x12
-       msr     afsr0_el1,      x13
-       msr     afsr1_el1,      x14
-       msr     far_el1,        x15
-       msr     mair_el1,       x16
-       msr     vbar_el1,       x17
-       msr     contextidr_el1, x18
-       msr     tpidr_el0,      x19
-       msr     tpidrro_el0,    x20
-       msr     tpidr_el1,      x21
-       msr     amair_el1,      x22
-       msr     cntkctl_el1,    x23
-       msr     par_el1,        x24
-       msr     mdscr_el1,      x25
-.endm
-
-.macro restore_debug type
-       // x4: pointer to register set
-       // x5: number of registers to skip
-       // x6..x22 trashed
-
-       adr     x22, 1f
-       add     x22, x22, x5, lsl #2
-       br      x22
-1:
-       ldr     x21, [x4, #(15 * 8)]
-       ldr     x20, [x4, #(14 * 8)]
-       ldr     x19, [x4, #(13 * 8)]
-       ldr     x18, [x4, #(12 * 8)]
-       ldr     x17, [x4, #(11 * 8)]
-       ldr     x16, [x4, #(10 * 8)]
-       ldr     x15, [x4, #(9 * 8)]
-       ldr     x14, [x4, #(8 * 8)]
-       ldr     x13, [x4, #(7 * 8)]
-       ldr     x12, [x4, #(6 * 8)]
-       ldr     x11, [x4, #(5 * 8)]
-       ldr     x10, [x4, #(4 * 8)]
-       ldr     x9, [x4, #(3 * 8)]
-       ldr     x8, [x4, #(2 * 8)]
-       ldr     x7, [x4, #(1 * 8)]
-       ldr     x6, [x4, #(0 * 8)]
-
-       adr     x22, 1f
-       add     x22, x22, x5, lsl #2
-       br      x22
-1:
-       msr     \type\()15_el1, x21
-       msr     \type\()14_el1, x20
-       msr     \type\()13_el1, x19
-       msr     \type\()12_el1, x18
-       msr     \type\()11_el1, x17
-       msr     \type\()10_el1, x16
-       msr     \type\()9_el1, x15
-       msr     \type\()8_el1, x14
-       msr     \type\()7_el1, x13
-       msr     \type\()6_el1, x12
-       msr     \type\()5_el1, x11
-       msr     \type\()4_el1, x10
-       msr     \type\()3_el1, x9
-       msr     \type\()2_el1, x8
-       msr     \type\()1_el1, x7
-       msr     \type\()0_el1, x6
-.endm
-
-.macro skip_32bit_state tmp, target
-       // Skip 32bit state if not needed
-       mrs     \tmp, hcr_el2
-       tbnz    \tmp, #HCR_RW_SHIFT, \target
-.endm
-
-.macro skip_tee_state tmp, target
-       // Skip ThumbEE state if not needed
-       mrs     \tmp, id_pfr0_el1
-       tbz     \tmp, #12, \target
-.endm
-
-.macro skip_debug_state tmp, target
-       ldr     \tmp, [x0, #VCPU_DEBUG_FLAGS]
-       tbz     \tmp, #KVM_ARM64_DEBUG_DIRTY_SHIFT, \target
-.endm
-
-/*
- * Branch to target if CPTR_EL2.TFP bit is set (VFP/SIMD trapping enabled)
- */
-.macro skip_fpsimd_state tmp, target
-       mrs     \tmp, cptr_el2
-       tbnz    \tmp, #CPTR_EL2_TFP_SHIFT, \target
-.endm
-
-.macro compute_debug_state target
-       // Compute debug state: If any of KDE, MDE or KVM_ARM64_DEBUG_DIRTY
-       // is set, we do a full save/restore cycle and disable trapping.
-       add     x25, x0, #VCPU_CONTEXT
-
-       // Check the state of MDSCR_EL1
-       ldr     x25, [x25, #CPU_SYSREG_OFFSET(MDSCR_EL1)]
-       and     x26, x25, #DBG_MDSCR_KDE
-       and     x25, x25, #DBG_MDSCR_MDE
-       adds    xzr, x25, x26
-       b.eq    9998f           // Nothing to see there
-
-       // If any interesting bits was set, we must set the flag
-       mov     x26, #KVM_ARM64_DEBUG_DIRTY
-       str     x26, [x0, #VCPU_DEBUG_FLAGS]
-       b       9999f           // Don't skip restore
-
-9998:
-       // Otherwise load the flags from memory in case we recently
-       // trapped
-       skip_debug_state x25, \target
-9999:
-.endm
-
-.macro save_guest_32bit_state
-       skip_32bit_state x3, 1f
-
-       add     x3, x2, #CPU_SPSR_OFFSET(KVM_SPSR_ABT)
-       mrs     x4, spsr_abt
-       mrs     x5, spsr_und
-       mrs     x6, spsr_irq
-       mrs     x7, spsr_fiq
-       stp     x4, x5, [x3]
-       stp     x6, x7, [x3, #16]
-
-       add     x3, x2, #CPU_SYSREG_OFFSET(DACR32_EL2)
-       mrs     x4, dacr32_el2
-       mrs     x5, ifsr32_el2
-       stp     x4, x5, [x3]
-
-       skip_fpsimd_state x8, 2f
-       mrs     x6, fpexc32_el2
-       str     x6, [x3, #16]
-2:
-       skip_debug_state x8, 1f
-       mrs     x7, dbgvcr32_el2
-       str     x7, [x3, #24]
-1:
-.endm
-
-.macro restore_guest_32bit_state
-       skip_32bit_state x3, 1f
-
-       add     x3, x2, #CPU_SPSR_OFFSET(KVM_SPSR_ABT)
-       ldp     x4, x5, [x3]
-       ldp     x6, x7, [x3, #16]
-       msr     spsr_abt, x4
-       msr     spsr_und, x5
-       msr     spsr_irq, x6
-       msr     spsr_fiq, x7
-
-       add     x3, x2, #CPU_SYSREG_OFFSET(DACR32_EL2)
-       ldp     x4, x5, [x3]
-       msr     dacr32_el2, x4
-       msr     ifsr32_el2, x5
-
-       skip_debug_state x8, 1f
-       ldr     x7, [x3, #24]
-       msr     dbgvcr32_el2, x7
-1:
-.endm
-
-.macro activate_traps
-       ldr     x2, [x0, #VCPU_HCR_EL2]
-
-       /*
-        * We are about to set CPTR_EL2.TFP to trap all floating point
-        * register accesses to EL2, however, the ARM ARM clearly states that
-        * traps are only taken to EL2 if the operation would not otherwise
-        * trap to EL1.  Therefore, always make sure that for 32-bit guests,
-        * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
-        */
-       tbnz    x2, #HCR_RW_SHIFT, 99f // open code skip_32bit_state
-       mov     x3, #(1 << 30)
-       msr     fpexc32_el2, x3
-       isb
-99:
-       msr     hcr_el2, x2
-       mov     x2, #CPTR_EL2_TTA
-       orr     x2, x2, #CPTR_EL2_TFP
-       msr     cptr_el2, x2
-
-       mov     x2, #(1 << 15)  // Trap CP15 Cr=15
-       msr     hstr_el2, x2
-
-       // Monitor Debug Config - see kvm_arm_setup_debug()
-       ldr     x2, [x0, #VCPU_MDCR_EL2]
-       msr     mdcr_el2, x2
-.endm
-
-.macro deactivate_traps
-       mov     x2, #HCR_RW
-       msr     hcr_el2, x2
-       msr     hstr_el2, xzr
-
-       mrs     x2, mdcr_el2
-       and     x2, x2, #MDCR_EL2_HPMN_MASK
-       msr     mdcr_el2, x2
-.endm
-
-.macro activate_vm
-       ldr     x1, [x0, #VCPU_KVM]
-       kern_hyp_va     x1
-       ldr     x2, [x1, #KVM_VTTBR]
-       msr     vttbr_el2, x2
-.endm
-
-.macro deactivate_vm
-       msr     vttbr_el2, xzr
-.endm
-
-/*
- * Call into the vgic backend for state saving
- */
-.macro save_vgic_state
-alternative_if_not ARM64_HAS_SYSREG_GIC_CPUIF
-       bl      __save_vgic_v2_state
-alternative_else
-       bl      __save_vgic_v3_state
-alternative_endif
-       mrs     x24, hcr_el2
-       mov     x25, #HCR_INT_OVERRIDE
-       neg     x25, x25
-       and     x24, x24, x25
-       msr     hcr_el2, x24
-.endm
-
-/*
- * Call into the vgic backend for state restoring
- */
-.macro restore_vgic_state
-       mrs     x24, hcr_el2
-       ldr     x25, [x0, #VCPU_IRQ_LINES]
-       orr     x24, x24, #HCR_INT_OVERRIDE
-       orr     x24, x24, x25
-       msr     hcr_el2, x24
-alternative_if_not ARM64_HAS_SYSREG_GIC_CPUIF
-       bl      __restore_vgic_v2_state
-alternative_else
-       bl      __restore_vgic_v3_state
-alternative_endif
-.endm
-
-.macro save_timer_state
-       // x0: vcpu pointer
-       ldr     x2, [x0, #VCPU_KVM]
-       kern_hyp_va x2
-       ldr     w3, [x2, #KVM_TIMER_ENABLED]
-       cbz     w3, 1f
-
-       mrs     x3, cntv_ctl_el0
-       and     x3, x3, #3
-       str     w3, [x0, #VCPU_TIMER_CNTV_CTL]
-
-       isb
-
-       mrs     x3, cntv_cval_el0
-       str     x3, [x0, #VCPU_TIMER_CNTV_CVAL]
-
-1:
-       // Disable the virtual timer
-       msr     cntv_ctl_el0, xzr
-
-       // Allow physical timer/counter access for the host
-       mrs     x2, cnthctl_el2
-       orr     x2, x2, #3
-       msr     cnthctl_el2, x2
-
-       // Clear cntvoff for the host
-       msr     cntvoff_el2, xzr
-.endm
-
-.macro restore_timer_state
-       // x0: vcpu pointer
-       // Disallow physical timer access for the guest
-       // Physical counter access is allowed
-       mrs     x2, cnthctl_el2
-       orr     x2, x2, #1
-       bic     x2, x2, #2
-       msr     cnthctl_el2, x2
-
-       ldr     x2, [x0, #VCPU_KVM]
-       kern_hyp_va x2
-       ldr     w3, [x2, #KVM_TIMER_ENABLED]
-       cbz     w3, 1f
-
-       ldr     x3, [x2, #KVM_TIMER_CNTVOFF]
-       msr     cntvoff_el2, x3
-       ldr     x2, [x0, #VCPU_TIMER_CNTV_CVAL]
-       msr     cntv_cval_el0, x2
-       isb
-
-       ldr     w2, [x0, #VCPU_TIMER_CNTV_CTL]
-       and     x2, x2, #3
-       msr     cntv_ctl_el0, x2
-1:
-.endm
-
-__save_sysregs:
-       save_sysregs
-       ret
-
-__restore_sysregs:
-       restore_sysregs
-       ret
-
-/* Save debug state */
-__save_debug:
-       // x2: ptr to CPU context
-       // x3: ptr to debug reg struct
-       // x4/x5/x6-22/x24-26: trashed
-
-       mrs     x26, id_aa64dfr0_el1
-       ubfx    x24, x26, #12, #4       // Extract BRPs
-       ubfx    x25, x26, #20, #4       // Extract WRPs
-       mov     w26, #15
-       sub     w24, w26, w24           // How many BPs to skip
-       sub     w25, w26, w25           // How many WPs to skip
-
-       mov     x5, x24
-       add     x4, x3, #DEBUG_BCR
-       save_debug dbgbcr
-       add     x4, x3, #DEBUG_BVR
-       save_debug dbgbvr
-
-       mov     x5, x25
-       add     x4, x3, #DEBUG_WCR
-       save_debug dbgwcr
-       add     x4, x3, #DEBUG_WVR
-       save_debug dbgwvr
-
-       mrs     x21, mdccint_el1
-       str     x21, [x2, #CPU_SYSREG_OFFSET(MDCCINT_EL1)]
-       ret
-
-/* Restore debug state */
-__restore_debug:
-       // x2: ptr to CPU context
-       // x3: ptr to debug reg struct
-       // x4/x5/x6-22/x24-26: trashed
-
-       mrs     x26, id_aa64dfr0_el1
-       ubfx    x24, x26, #12, #4       // Extract BRPs
-       ubfx    x25, x26, #20, #4       // Extract WRPs
-       mov     w26, #15
-       sub     w24, w26, w24           // How many BPs to skip
-       sub     w25, w26, w25           // How many WPs to skip
-
-       mov     x5, x24
-       add     x4, x3, #DEBUG_BCR
-       restore_debug dbgbcr
-       add     x4, x3, #DEBUG_BVR
-       restore_debug dbgbvr
-
-       mov     x5, x25
-       add     x4, x3, #DEBUG_WCR
-       restore_debug dbgwcr
-       add     x4, x3, #DEBUG_WVR
-       restore_debug dbgwvr
-
-       ldr     x21, [x2, #CPU_SYSREG_OFFSET(MDCCINT_EL1)]
-       msr     mdccint_el1, x21
-
-       ret
-
-__save_fpsimd:
-       skip_fpsimd_state x3, 1f
-       save_fpsimd
-1:     ret
-
-__restore_fpsimd:
-       skip_fpsimd_state x3, 1f
-       restore_fpsimd
-1:     ret
-
-switch_to_guest_fpsimd:
-       push    x4, lr
-
-       mrs     x2, cptr_el2
-       bic     x2, x2, #CPTR_EL2_TFP
-       msr     cptr_el2, x2
-       isb
-
-       mrs     x0, tpidr_el2
-
-       ldr     x2, [x0, #VCPU_HOST_CONTEXT]
-       kern_hyp_va x2
-       bl __save_fpsimd
-
-       add     x2, x0, #VCPU_CONTEXT
-       bl __restore_fpsimd
-
-       skip_32bit_state x3, 1f
-       ldr     x4, [x2, #CPU_SYSREG_OFFSET(FPEXC32_EL2)]
-       msr     fpexc32_el2, x4
-1:
-       pop     x4, lr
-       pop     x2, x3
-       pop     x0, x1
-
-       eret
-
-/*
- * u64 __kvm_vcpu_run(struct kvm_vcpu *vcpu);
- *
- * This is the world switch. The first half of the function
- * deals with entering the guest, and anything from __kvm_vcpu_return
- * to the end of the function deals with reentering the host.
- * On the enter path, only x0 (vcpu pointer) must be preserved until
- * the last moment. On the exit path, x0 (vcpu pointer) and x1 (exception
- * code) must both be preserved until the epilogue.
- * In both cases, x2 points to the CPU context we're saving/restoring from/to.
- */
-ENTRY(__kvm_vcpu_run)
-       kern_hyp_va     x0
-       msr     tpidr_el2, x0   // Save the vcpu register
-
-       // Host context
-       ldr     x2, [x0, #VCPU_HOST_CONTEXT]
-       kern_hyp_va x2
-
-       save_host_regs
-       bl __save_sysregs
-
-       compute_debug_state 1f
-       add     x3, x0, #VCPU_HOST_DEBUG_STATE
-       bl      __save_debug
-1:
-       activate_traps
-       activate_vm
-
-       restore_vgic_state
-       restore_timer_state
-
-       // Guest context
-       add     x2, x0, #VCPU_CONTEXT
-
-       // We must restore the 32-bit state before the sysregs, thanks
-       // to Cortex-A57 erratum #852523.
-       restore_guest_32bit_state
-       bl __restore_sysregs
-
-       skip_debug_state x3, 1f
-       ldr     x3, [x0, #VCPU_DEBUG_PTR]
-       kern_hyp_va x3
-       bl      __restore_debug
-1:
-       restore_guest_regs
-
-       // That's it, no more messing around.
-       eret
-
-__kvm_vcpu_return:
-       // Assume x0 is the vcpu pointer, x1 the return code
-       // Guest's x0-x3 are on the stack
-
-       // Guest context
-       add     x2, x0, #VCPU_CONTEXT
-
-       save_guest_regs
-       bl __save_fpsimd
-       bl __save_sysregs
-
-       skip_debug_state x3, 1f
-       ldr     x3, [x0, #VCPU_DEBUG_PTR]
-       kern_hyp_va x3
-       bl      __save_debug
-1:
-       save_guest_32bit_state
-
-       save_timer_state
-       save_vgic_state
-
-       deactivate_traps
-       deactivate_vm
-
-       // Host context
-       ldr     x2, [x0, #VCPU_HOST_CONTEXT]
-       kern_hyp_va x2
-
-       bl __restore_sysregs
-       bl __restore_fpsimd
-       /* Clear FPSIMD and Trace trapping */
-       msr     cptr_el2, xzr
-
-       skip_debug_state x3, 1f
-       // Clear the dirty flag for the next run, as all the state has
-       // already been saved. Note that we nuke the whole 64bit word.
-       // If we ever add more flags, we'll have to be more careful...
-       str     xzr, [x0, #VCPU_DEBUG_FLAGS]
-       add     x3, x0, #VCPU_HOST_DEBUG_STATE
-       bl      __restore_debug
-1:
-       restore_host_regs
-
-       mov     x0, x1
-       ret
-END(__kvm_vcpu_run)
-
-// void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
-ENTRY(__kvm_tlb_flush_vmid_ipa)
-       dsb     ishst
-
-       kern_hyp_va     x0
-       ldr     x2, [x0, #KVM_VTTBR]
-       msr     vttbr_el2, x2
-       isb
-
-       /*
-        * We could do so much better if we had the VA as well.
-        * Instead, we invalidate Stage-2 for this IPA, and the
-        * whole of Stage-1. Weep...
-        */
-       lsr     x1, x1, #12
-       tlbi    ipas2e1is, x1
-       /*
-        * We have to ensure completion of the invalidation at Stage-2,
-        * since a table walk on another CPU could refill a TLB with a
-        * complete (S1 + S2) walk based on the old Stage-2 mapping if
-        * the Stage-1 invalidation happened first.
-        */
-       dsb     ish
-       tlbi    vmalle1is
-       dsb     ish
-       isb
-
-       msr     vttbr_el2, xzr
-       ret
-ENDPROC(__kvm_tlb_flush_vmid_ipa)
-
-/**
- * void __kvm_tlb_flush_vmid(struct kvm *kvm) - Flush per-VMID TLBs
- * @struct kvm *kvm - pointer to kvm structure
- *
- * Invalidates all Stage 1 and 2 TLB entries for current VMID.
- */
-ENTRY(__kvm_tlb_flush_vmid)
-       dsb     ishst
-
-       kern_hyp_va     x0
-       ldr     x2, [x0, #KVM_VTTBR]
-       msr     vttbr_el2, x2
-       isb
-
-       tlbi    vmalls12e1is
-       dsb     ish
-       isb
-
-       msr     vttbr_el2, xzr
-       ret
-ENDPROC(__kvm_tlb_flush_vmid)
-
-ENTRY(__kvm_flush_vm_context)
-       dsb     ishst
-       tlbi    alle1is
-       ic      ialluis
-       dsb     ish
-       ret
-ENDPROC(__kvm_flush_vm_context)
-
-__kvm_hyp_panic:
-       // Stash PAR_EL1 before corrupting it in __restore_sysregs
-       mrs     x0, par_el1
-       push    x0, xzr
-
-       // Guess the context by looking at VTTBR:
-       // If zero, then we're already a host.
-       // Otherwise restore a minimal host context before panicing.
-       mrs     x0, vttbr_el2
-       cbz     x0, 1f
-
-       mrs     x0, tpidr_el2
-
-       deactivate_traps
-       deactivate_vm
-
-       ldr     x2, [x0, #VCPU_HOST_CONTEXT]
-       kern_hyp_va x2
-
-       bl __restore_sysregs
-
-       /*
-        * Make sure we have a valid host stack, and don't leave junk in the
-        * frame pointer that will give us a misleading host stack unwinding.
-        */
-       ldr     x22, [x2, #CPU_GP_REG_OFFSET(CPU_SP_EL1)]
-       msr     sp_el1, x22
-       mov     x29, xzr
-
-1:     adr     x0, __hyp_panic_str
-       adr     x1, 2f
-       ldp     x2, x3, [x1]
-       sub     x0, x0, x2
-       add     x0, x0, x3
-       mrs     x1, spsr_el2
-       mrs     x2, elr_el2
-       mrs     x3, esr_el2
-       mrs     x4, far_el2
-       mrs     x5, hpfar_el2
-       pop     x6, xzr         // active context PAR_EL1
-       mrs     x7, tpidr_el2
-
-       mov     lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
-                     PSR_MODE_EL1h)
-       msr     spsr_el2, lr
-       ldr     lr, =panic
-       msr     elr_el2, lr
-       eret
-
-       .align  3
-2:     .quad   HYP_PAGE_OFFSET
-       .quad   PAGE_OFFSET
-ENDPROC(__kvm_hyp_panic)
-
-__hyp_panic_str:
-       .ascii  "HYP panic:\nPS:%08x PC:%016x ESR:%08x\nFAR:%016x HPFAR:%016x PAR:%016x\nVCPU:%p\n\0"
-
-       .align  2
 
 /*
  * u64 kvm_call_hyp(void *hypfn, ...);
@@ -934,7 +31,7 @@ __hyp_panic_str:
  * passed as x0, x1, and x2 (a maximum of 3 arguments in addition to the
  * function pointer can be passed).  The function being called must be mapped
  * in Hyp mode (see init_hyp_mode in arch/arm/kvm/arm.c).  Return values are
- * passed in r0 and r1.
+ * passed in x0.
  *
  * A function pointer with a value of 0 has a special meaning, and is
  * used to implement __hyp_get_vectors in the same way as in
@@ -944,179 +41,3 @@ ENTRY(kvm_call_hyp)
        hvc     #0
        ret
 ENDPROC(kvm_call_hyp)
-
-.macro invalid_vector  label, target
-       .align  2
-\label:
-       b \target
-ENDPROC(\label)
-.endm
-
-       /* None of these should ever happen */
-       invalid_vector  el2t_sync_invalid, __kvm_hyp_panic
-       invalid_vector  el2t_irq_invalid, __kvm_hyp_panic
-       invalid_vector  el2t_fiq_invalid, __kvm_hyp_panic
-       invalid_vector  el2t_error_invalid, __kvm_hyp_panic
-       invalid_vector  el2h_sync_invalid, __kvm_hyp_panic
-       invalid_vector  el2h_irq_invalid, __kvm_hyp_panic
-       invalid_vector  el2h_fiq_invalid, __kvm_hyp_panic
-       invalid_vector  el2h_error_invalid, __kvm_hyp_panic
-       invalid_vector  el1_sync_invalid, __kvm_hyp_panic
-       invalid_vector  el1_irq_invalid, __kvm_hyp_panic
-       invalid_vector  el1_fiq_invalid, __kvm_hyp_panic
-       invalid_vector  el1_error_invalid, __kvm_hyp_panic
-
-el1_sync:                                      // Guest trapped into EL2
-       push    x0, x1
-       push    x2, x3
-
-       mrs     x1, esr_el2
-       lsr     x2, x1, #ESR_ELx_EC_SHIFT
-
-       cmp     x2, #ESR_ELx_EC_HVC64
-       b.ne    el1_trap
-
-       mrs     x3, vttbr_el2                   // If vttbr is valid, the 64bit guest
-       cbnz    x3, el1_trap                    // called HVC
-
-       /* Here, we're pretty sure the host called HVC. */
-       pop     x2, x3
-       pop     x0, x1
-
-       /* Check for __hyp_get_vectors */
-       cbnz    x0, 1f
-       mrs     x0, vbar_el2
-       b       2f
-
-1:     push    lr, xzr
-
-       /*
-        * Compute the function address in EL2, and shuffle the parameters.
-        */
-       kern_hyp_va     x0
-       mov     lr, x0
-       mov     x0, x1
-       mov     x1, x2
-       mov     x2, x3
-       blr     lr
-
-       pop     lr, xzr
-2:     eret
-
-el1_trap:
-       /*
-        * x1: ESR
-        * x2: ESR_EC
-        */
-
-       /* Guest accessed VFP/SIMD registers, save host, restore Guest */
-       cmp     x2, #ESR_ELx_EC_FP_ASIMD
-       b.eq    switch_to_guest_fpsimd
-
-       cmp     x2, #ESR_ELx_EC_DABT_LOW
-       mov     x0, #ESR_ELx_EC_IABT_LOW
-       ccmp    x2, x0, #4, ne
-       b.ne    1f              // Not an abort we care about
-
-       /* This is an abort. Check for permission fault */
-alternative_if_not ARM64_WORKAROUND_834220
-       and     x2, x1, #ESR_ELx_FSC_TYPE
-       cmp     x2, #FSC_PERM
-       b.ne    1f              // Not a permission fault
-alternative_else
-       nop                     // Use the permission fault path to
-       nop                     // check for a valid S1 translation,
-       nop                     // regardless of the ESR value.
-alternative_endif
-
-       /*
-        * Check for Stage-1 page table walk, which is guaranteed
-        * to give a valid HPFAR_EL2.
-        */
-       tbnz    x1, #7, 1f      // S1PTW is set
-
-       /* Preserve PAR_EL1 */
-       mrs     x3, par_el1
-       push    x3, xzr
-
-       /*
-        * Permission fault, HPFAR_EL2 is invalid.
-        * Resolve the IPA the hard way using the guest VA.
-        * Stage-1 translation already validated the memory access rights.
-        * As such, we can use the EL1 translation regime, and don't have
-        * to distinguish between EL0 and EL1 access.
-        */
-       mrs     x2, far_el2
-       at      s1e1r, x2
-       isb
-
-       /* Read result */
-       mrs     x3, par_el1
-       pop     x0, xzr                 // Restore PAR_EL1 from the stack
-       msr     par_el1, x0
-       tbnz    x3, #0, 3f              // Bail out if we failed the translation
-       ubfx    x3, x3, #12, #36        // Extract IPA
-       lsl     x3, x3, #4              // and present it like HPFAR
-       b       2f
-
-1:     mrs     x3, hpfar_el2
-       mrs     x2, far_el2
-
-2:     mrs     x0, tpidr_el2
-       str     w1, [x0, #VCPU_ESR_EL2]
-       str     x2, [x0, #VCPU_FAR_EL2]
-       str     x3, [x0, #VCPU_HPFAR_EL2]
-
-       mov     x1, #ARM_EXCEPTION_TRAP
-       b       __kvm_vcpu_return
-
-       /*
-        * Translation failed. Just return to the guest and
-        * let it fault again. Another CPU is probably playing
-        * behind our back.
-        */
-3:     pop     x2, x3
-       pop     x0, x1
-
-       eret
-
-el1_irq:
-       push    x0, x1
-       push    x2, x3
-       mrs     x0, tpidr_el2
-       mov     x1, #ARM_EXCEPTION_IRQ
-       b       __kvm_vcpu_return
-
-       .ltorg
-
-       .align 11
-
-ENTRY(__kvm_hyp_vector)
-       ventry  el2t_sync_invalid               // Synchronous EL2t
-       ventry  el2t_irq_invalid                // IRQ EL2t
-       ventry  el2t_fiq_invalid                // FIQ EL2t
-       ventry  el2t_error_invalid              // Error EL2t
-
-       ventry  el2h_sync_invalid               // Synchronous EL2h
-       ventry  el2h_irq_invalid                // IRQ EL2h
-       ventry  el2h_fiq_invalid                // FIQ EL2h
-       ventry  el2h_error_invalid              // Error EL2h
-
-       ventry  el1_sync                        // Synchronous 64-bit EL1
-       ventry  el1_irq                         // IRQ 64-bit EL1
-       ventry  el1_fiq_invalid                 // FIQ 64-bit EL1
-       ventry  el1_error_invalid               // Error 64-bit EL1
-
-       ventry  el1_sync                        // Synchronous 32-bit EL1
-       ventry  el1_irq                         // IRQ 32-bit EL1
-       ventry  el1_fiq_invalid                 // FIQ 32-bit EL1
-       ventry  el1_error_invalid               // Error 32-bit EL1
-ENDPROC(__kvm_hyp_vector)
-
-
-ENTRY(__kvm_get_mdcr_el2)
-       mrs     x0, mdcr_el2
-       ret
-ENDPROC(__kvm_get_mdcr_el2)
-
-       .popsection
diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
new file mode 100644 (file)
index 0000000..826032b
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# Makefile for Kernel-based Virtual Machine module, HYP part
+#
+
+obj-$(CONFIG_KVM_ARM_HOST) += vgic-v2-sr.o
+obj-$(CONFIG_KVM_ARM_HOST) += vgic-v3-sr.o
+obj-$(CONFIG_KVM_ARM_HOST) += timer-sr.o
+obj-$(CONFIG_KVM_ARM_HOST) += sysreg-sr.o
+obj-$(CONFIG_KVM_ARM_HOST) += debug-sr.o
+obj-$(CONFIG_KVM_ARM_HOST) += entry.o
+obj-$(CONFIG_KVM_ARM_HOST) += switch.o
+obj-$(CONFIG_KVM_ARM_HOST) += fpsimd.o
+obj-$(CONFIG_KVM_ARM_HOST) += tlb.o
+obj-$(CONFIG_KVM_ARM_HOST) += hyp-entry.o
diff --git a/arch/arm64/kvm/hyp/debug-sr.c b/arch/arm64/kvm/hyp/debug-sr.c
new file mode 100644 (file)
index 0000000..c9c1e97
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.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.
+ *
+ * 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/compiler.h>
+#include <linux/kvm_host.h>
+
+#include <asm/kvm_asm.h>
+#include <asm/kvm_mmu.h>
+
+#include "hyp.h"
+
+#define read_debug(r,n)                read_sysreg(r##n##_el1)
+#define write_debug(v,r,n)     write_sysreg(v, r##n##_el1)
+
+#define save_debug(ptr,reg,nr)                                         \
+       switch (nr) {                                                   \
+       case 15:        ptr[15] = read_debug(reg, 15);                  \
+       case 14:        ptr[14] = read_debug(reg, 14);                  \
+       case 13:        ptr[13] = read_debug(reg, 13);                  \
+       case 12:        ptr[12] = read_debug(reg, 12);                  \
+       case 11:        ptr[11] = read_debug(reg, 11);                  \
+       case 10:        ptr[10] = read_debug(reg, 10);                  \
+       case 9:         ptr[9] = read_debug(reg, 9);                    \
+       case 8:         ptr[8] = read_debug(reg, 8);                    \
+       case 7:         ptr[7] = read_debug(reg, 7);                    \
+       case 6:         ptr[6] = read_debug(reg, 6);                    \
+       case 5:         ptr[5] = read_debug(reg, 5);                    \
+       case 4:         ptr[4] = read_debug(reg, 4);                    \
+       case 3:         ptr[3] = read_debug(reg, 3);                    \
+       case 2:         ptr[2] = read_debug(reg, 2);                    \
+       case 1:         ptr[1] = read_debug(reg, 1);                    \
+       default:        ptr[0] = read_debug(reg, 0);                    \
+       }
+
+#define restore_debug(ptr,reg,nr)                                      \
+       switch (nr) {                                                   \
+       case 15:        write_debug(ptr[15], reg, 15);                  \
+       case 14:        write_debug(ptr[14], reg, 14);                  \
+       case 13:        write_debug(ptr[13], reg, 13);                  \
+       case 12:        write_debug(ptr[12], reg, 12);                  \
+       case 11:        write_debug(ptr[11], reg, 11);                  \
+       case 10:        write_debug(ptr[10], reg, 10);                  \
+       case 9:         write_debug(ptr[9], reg, 9);                    \
+       case 8:         write_debug(ptr[8], reg, 8);                    \
+       case 7:         write_debug(ptr[7], reg, 7);                    \
+       case 6:         write_debug(ptr[6], reg, 6);                    \
+       case 5:         write_debug(ptr[5], reg, 5);                    \
+       case 4:         write_debug(ptr[4], reg, 4);                    \
+       case 3:         write_debug(ptr[3], reg, 3);                    \
+       case 2:         write_debug(ptr[2], reg, 2);                    \
+       case 1:         write_debug(ptr[1], reg, 1);                    \
+       default:        write_debug(ptr[0], reg, 0);                    \
+       }
+
+void __hyp_text __debug_save_state(struct kvm_vcpu *vcpu,
+                                  struct kvm_guest_debug_arch *dbg,
+                                  struct kvm_cpu_context *ctxt)
+{
+       u64 aa64dfr0;
+       int brps, wrps;
+
+       if (!(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY))
+               return;
+
+       aa64dfr0 = read_sysreg(id_aa64dfr0_el1);
+       brps = (aa64dfr0 >> 12) & 0xf;
+       wrps = (aa64dfr0 >> 20) & 0xf;
+
+       save_debug(dbg->dbg_bcr, dbgbcr, brps);
+       save_debug(dbg->dbg_bvr, dbgbvr, brps);
+       save_debug(dbg->dbg_wcr, dbgwcr, wrps);
+       save_debug(dbg->dbg_wvr, dbgwvr, wrps);
+
+       ctxt->sys_regs[MDCCINT_EL1] = read_sysreg(mdccint_el1);
+}
+
+void __hyp_text __debug_restore_state(struct kvm_vcpu *vcpu,
+                                     struct kvm_guest_debug_arch *dbg,
+                                     struct kvm_cpu_context *ctxt)
+{
+       u64 aa64dfr0;
+       int brps, wrps;
+
+       if (!(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY))
+               return;
+
+       aa64dfr0 = read_sysreg(id_aa64dfr0_el1);
+
+       brps = (aa64dfr0 >> 12) & 0xf;
+       wrps = (aa64dfr0 >> 20) & 0xf;
+
+       restore_debug(dbg->dbg_bcr, dbgbcr, brps);
+       restore_debug(dbg->dbg_bvr, dbgbvr, brps);
+       restore_debug(dbg->dbg_wcr, dbgwcr, wrps);
+       restore_debug(dbg->dbg_wvr, dbgwvr, wrps);
+
+       write_sysreg(ctxt->sys_regs[MDCCINT_EL1], mdccint_el1);
+}
+
+void __hyp_text __debug_cond_save_host_state(struct kvm_vcpu *vcpu)
+{
+       /* If any of KDE, MDE or KVM_ARM64_DEBUG_DIRTY is set, perform
+        * a full save/restore cycle. */
+       if ((vcpu->arch.ctxt.sys_regs[MDSCR_EL1] & DBG_MDSCR_KDE) ||
+           (vcpu->arch.ctxt.sys_regs[MDSCR_EL1] & DBG_MDSCR_MDE))
+               vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
+
+       __debug_save_state(vcpu, &vcpu->arch.host_debug_state,
+                          kern_hyp_va(vcpu->arch.host_cpu_context));
+}
+
+void __hyp_text __debug_cond_restore_host_state(struct kvm_vcpu *vcpu)
+{
+       __debug_restore_state(vcpu, &vcpu->arch.host_debug_state,
+                             kern_hyp_va(vcpu->arch.host_cpu_context));
+
+       if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
+               vcpu->arch.debug_flags &= ~KVM_ARM64_DEBUG_DIRTY;
+}
+
+static u32 __hyp_text __debug_read_mdcr_el2(void)
+{
+       return read_sysreg(mdcr_el2);
+}
+
+__alias(__debug_read_mdcr_el2) u32 __kvm_get_mdcr_el2(void);
diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
new file mode 100644 (file)
index 0000000..fd0fbe9
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.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.
+ *
+ * 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/linkage.h>
+
+#include <asm/asm-offsets.h>
+#include <asm/assembler.h>
+#include <asm/fpsimdmacros.h>
+#include <asm/kvm.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_mmu.h>
+
+#define CPU_GP_REG_OFFSET(x)   (CPU_GP_REGS + x)
+#define CPU_XREG_OFFSET(x)     CPU_GP_REG_OFFSET(CPU_USER_PT_REGS + 8*x)
+
+       .text
+       .pushsection    .hyp.text, "ax"
+
+.macro save_callee_saved_regs ctxt
+       stp     x19, x20, [\ctxt, #CPU_XREG_OFFSET(19)]
+       stp     x21, x22, [\ctxt, #CPU_XREG_OFFSET(21)]
+       stp     x23, x24, [\ctxt, #CPU_XREG_OFFSET(23)]
+       stp     x25, x26, [\ctxt, #CPU_XREG_OFFSET(25)]
+       stp     x27, x28, [\ctxt, #CPU_XREG_OFFSET(27)]
+       stp     x29, lr,  [\ctxt, #CPU_XREG_OFFSET(29)]
+.endm
+
+.macro restore_callee_saved_regs ctxt
+       ldp     x19, x20, [\ctxt, #CPU_XREG_OFFSET(19)]
+       ldp     x21, x22, [\ctxt, #CPU_XREG_OFFSET(21)]
+       ldp     x23, x24, [\ctxt, #CPU_XREG_OFFSET(23)]
+       ldp     x25, x26, [\ctxt, #CPU_XREG_OFFSET(25)]
+       ldp     x27, x28, [\ctxt, #CPU_XREG_OFFSET(27)]
+       ldp     x29, lr,  [\ctxt, #CPU_XREG_OFFSET(29)]
+.endm
+
+/*
+ * u64 __guest_enter(struct kvm_vcpu *vcpu,
+ *                  struct kvm_cpu_context *host_ctxt);
+ */
+ENTRY(__guest_enter)
+       // x0: vcpu
+       // x1: host/guest context
+       // x2-x18: clobbered by macros
+
+       // Store the host regs
+       save_callee_saved_regs x1
+
+       // Preserve vcpu & host_ctxt for use at exit time
+       stp     x0, x1, [sp, #-16]!
+
+       add     x1, x0, #VCPU_CONTEXT
+
+       // Prepare x0-x1 for later restore by pushing them onto the stack
+       ldp     x2, x3, [x1, #CPU_XREG_OFFSET(0)]
+       stp     x2, x3, [sp, #-16]!
+
+       // x2-x18
+       ldp     x2, x3,   [x1, #CPU_XREG_OFFSET(2)]
+       ldp     x4, x5,   [x1, #CPU_XREG_OFFSET(4)]
+       ldp     x6, x7,   [x1, #CPU_XREG_OFFSET(6)]
+       ldp     x8, x9,   [x1, #CPU_XREG_OFFSET(8)]
+       ldp     x10, x11, [x1, #CPU_XREG_OFFSET(10)]
+       ldp     x12, x13, [x1, #CPU_XREG_OFFSET(12)]
+       ldp     x14, x15, [x1, #CPU_XREG_OFFSET(14)]
+       ldp     x16, x17, [x1, #CPU_XREG_OFFSET(16)]
+       ldr     x18,      [x1, #CPU_XREG_OFFSET(18)]
+
+       // x19-x29, lr
+       restore_callee_saved_regs x1
+
+       // Last bits of the 64bit state
+       ldp     x0, x1, [sp], #16
+
+       // Do not touch any register after this!
+       eret
+ENDPROC(__guest_enter)
+
+ENTRY(__guest_exit)
+       // x0: vcpu
+       // x1: return code
+       // x2-x3: free
+       // x4-x29,lr: vcpu regs
+       // vcpu x0-x3 on the stack
+
+       add     x2, x0, #VCPU_CONTEXT
+
+       stp     x4, x5,   [x2, #CPU_XREG_OFFSET(4)]
+       stp     x6, x7,   [x2, #CPU_XREG_OFFSET(6)]
+       stp     x8, x9,   [x2, #CPU_XREG_OFFSET(8)]
+       stp     x10, x11, [x2, #CPU_XREG_OFFSET(10)]
+       stp     x12, x13, [x2, #CPU_XREG_OFFSET(12)]
+       stp     x14, x15, [x2, #CPU_XREG_OFFSET(14)]
+       stp     x16, x17, [x2, #CPU_XREG_OFFSET(16)]
+       str     x18,      [x2, #CPU_XREG_OFFSET(18)]
+
+       ldp     x6, x7, [sp], #16       // x2, x3
+       ldp     x4, x5, [sp], #16       // x0, x1
+
+       stp     x4, x5, [x2, #CPU_XREG_OFFSET(0)]
+       stp     x6, x7, [x2, #CPU_XREG_OFFSET(2)]
+
+       save_callee_saved_regs x2
+
+       // Restore vcpu & host_ctxt from the stack
+       // (preserving return code in x1)
+       ldp     x0, x2, [sp], #16
+       // Now restore the host regs
+       restore_callee_saved_regs x2
+
+       mov     x0, x1
+       ret
+ENDPROC(__guest_exit)
+
+ENTRY(__fpsimd_guest_restore)
+       stp     x4, lr, [sp, #-16]!
+
+       mrs     x2, cptr_el2
+       bic     x2, x2, #CPTR_EL2_TFP
+       msr     cptr_el2, x2
+       isb
+
+       mrs     x3, tpidr_el2
+
+       ldr     x0, [x3, #VCPU_HOST_CONTEXT]
+       kern_hyp_va x0
+       add     x0, x0, #CPU_GP_REG_OFFSET(CPU_FP_REGS)
+       bl      __fpsimd_save_state
+
+       add     x2, x3, #VCPU_CONTEXT
+       add     x0, x2, #CPU_GP_REG_OFFSET(CPU_FP_REGS)
+       bl      __fpsimd_restore_state
+
+       // Skip restoring fpexc32 for AArch64 guests
+       mrs     x1, hcr_el2
+       tbnz    x1, #HCR_RW_SHIFT, 1f
+       ldr     x4, [x3, #VCPU_FPEXC32_EL2]
+       msr     fpexc32_el2, x4
+1:
+       ldp     x4, lr, [sp], #16
+       ldp     x2, x3, [sp], #16
+       ldp     x0, x1, [sp], #16
+
+       eret
+ENDPROC(__fpsimd_guest_restore)
diff --git a/arch/arm64/kvm/hyp/fpsimd.S b/arch/arm64/kvm/hyp/fpsimd.S
new file mode 100644 (file)
index 0000000..da3f22c
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.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.
+ *
+ * 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/linkage.h>
+
+#include <asm/fpsimdmacros.h>
+
+       .text
+       .pushsection    .hyp.text, "ax"
+
+ENTRY(__fpsimd_save_state)
+       fpsimd_save     x0, 1
+       ret
+ENDPROC(__fpsimd_save_state)
+
+ENTRY(__fpsimd_restore_state)
+       fpsimd_restore  x0, 1
+       ret
+ENDPROC(__fpsimd_restore_state)
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
new file mode 100644 (file)
index 0000000..93e8d98
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.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.
+ *
+ * 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/linkage.h>
+
+#include <asm/alternative.h>
+#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+#include <asm/cpufeature.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_mmu.h>
+
+       .text
+       .pushsection    .hyp.text, "ax"
+
+.macro save_x0_to_x3
+       stp     x0, x1, [sp, #-16]!
+       stp     x2, x3, [sp, #-16]!
+.endm
+
+.macro restore_x0_to_x3
+       ldp     x2, x3, [sp], #16
+       ldp     x0, x1, [sp], #16
+.endm
+
+el1_sync:                              // Guest trapped into EL2
+       save_x0_to_x3
+
+       mrs     x1, esr_el2
+       lsr     x2, x1, #ESR_ELx_EC_SHIFT
+
+       cmp     x2, #ESR_ELx_EC_HVC64
+       b.ne    el1_trap
+
+       mrs     x3, vttbr_el2           // If vttbr is valid, the 64bit guest
+       cbnz    x3, el1_trap            // called HVC
+
+       /* Here, we're pretty sure the host called HVC. */
+       restore_x0_to_x3
+
+       /* Check for __hyp_get_vectors */
+       cbnz    x0, 1f
+       mrs     x0, vbar_el2
+       b       2f
+
+1:     stp     lr, xzr, [sp, #-16]!
+
+       /*
+        * Compute the function address in EL2, and shuffle the parameters.
+        */
+       kern_hyp_va     x0
+       mov     lr, x0
+       mov     x0, x1
+       mov     x1, x2
+       mov     x2, x3
+       blr     lr
+
+       ldp     lr, xzr, [sp], #16
+2:     eret
+
+el1_trap:
+       /*
+        * x1: ESR
+        * x2: ESR_EC
+        */
+
+       /* Guest accessed VFP/SIMD registers, save host, restore Guest */
+       cmp     x2, #ESR_ELx_EC_FP_ASIMD
+       b.eq    __fpsimd_guest_restore
+
+       cmp     x2, #ESR_ELx_EC_DABT_LOW
+       mov     x0, #ESR_ELx_EC_IABT_LOW
+       ccmp    x2, x0, #4, ne
+       b.ne    1f              // Not an abort we care about
+
+       /* This is an abort. Check for permission fault */
+alternative_if_not ARM64_WORKAROUND_834220
+       and     x2, x1, #ESR_ELx_FSC_TYPE
+       cmp     x2, #FSC_PERM
+       b.ne    1f              // Not a permission fault
+alternative_else
+       nop                     // Use the permission fault path to
+       nop                     // check for a valid S1 translation,
+       nop                     // regardless of the ESR value.
+alternative_endif
+
+       /*
+        * Check for Stage-1 page table walk, which is guaranteed
+        * to give a valid HPFAR_EL2.
+        */
+       tbnz    x1, #7, 1f      // S1PTW is set
+
+       /* Preserve PAR_EL1 */
+       mrs     x3, par_el1
+       stp     x3, xzr, [sp, #-16]!
+
+       /*
+        * Permission fault, HPFAR_EL2 is invalid.
+        * Resolve the IPA the hard way using the guest VA.
+        * Stage-1 translation already validated the memory access rights.
+        * As such, we can use the EL1 translation regime, and don't have
+        * to distinguish between EL0 and EL1 access.
+        */
+       mrs     x2, far_el2
+       at      s1e1r, x2
+       isb
+
+       /* Read result */
+       mrs     x3, par_el1
+       ldp     x0, xzr, [sp], #16      // Restore PAR_EL1 from the stack
+       msr     par_el1, x0
+       tbnz    x3, #0, 3f              // Bail out if we failed the translation
+       ubfx    x3, x3, #12, #36        // Extract IPA
+       lsl     x3, x3, #4              // and present it like HPFAR
+       b       2f
+
+1:     mrs     x3, hpfar_el2
+       mrs     x2, far_el2
+
+2:     mrs     x0, tpidr_el2
+       str     w1, [x0, #VCPU_ESR_EL2]
+       str     x2, [x0, #VCPU_FAR_EL2]
+       str     x3, [x0, #VCPU_HPFAR_EL2]
+
+       mov     x1, #ARM_EXCEPTION_TRAP
+       b       __guest_exit
+
+       /*
+        * Translation failed. Just return to the guest and
+        * let it fault again. Another CPU is probably playing
+        * behind our back.
+        */
+3:     restore_x0_to_x3
+
+       eret
+
+el1_irq:
+       save_x0_to_x3
+       mrs     x0, tpidr_el2
+       mov     x1, #ARM_EXCEPTION_IRQ
+       b       __guest_exit
+
+ENTRY(__hyp_do_panic)
+       mov     lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
+                     PSR_MODE_EL1h)
+       msr     spsr_el2, lr
+       ldr     lr, =panic
+       msr     elr_el2, lr
+       eret
+ENDPROC(__hyp_do_panic)
+
+.macro invalid_vector  label, target = __hyp_panic
+       .align  2
+\label:
+       b \target
+ENDPROC(\label)
+.endm
+
+       /* None of these should ever happen */
+       invalid_vector  el2t_sync_invalid
+       invalid_vector  el2t_irq_invalid
+       invalid_vector  el2t_fiq_invalid
+       invalid_vector  el2t_error_invalid
+       invalid_vector  el2h_sync_invalid
+       invalid_vector  el2h_irq_invalid
+       invalid_vector  el2h_fiq_invalid
+       invalid_vector  el2h_error_invalid
+       invalid_vector  el1_sync_invalid
+       invalid_vector  el1_irq_invalid
+       invalid_vector  el1_fiq_invalid
+       invalid_vector  el1_error_invalid
+
+       .ltorg
+
+       .align 11
+
+ENTRY(__kvm_hyp_vector)
+       ventry  el2t_sync_invalid               // Synchronous EL2t
+       ventry  el2t_irq_invalid                // IRQ EL2t
+       ventry  el2t_fiq_invalid                // FIQ EL2t
+       ventry  el2t_error_invalid              // Error EL2t
+
+       ventry  el2h_sync_invalid               // Synchronous EL2h
+       ventry  el2h_irq_invalid                // IRQ EL2h
+       ventry  el2h_fiq_invalid                // FIQ EL2h
+       ventry  el2h_error_invalid              // Error EL2h
+
+       ventry  el1_sync                        // Synchronous 64-bit EL1
+       ventry  el1_irq                         // IRQ 64-bit EL1
+       ventry  el1_fiq_invalid                 // FIQ 64-bit EL1
+       ventry  el1_error_invalid               // Error 64-bit EL1
+
+       ventry  el1_sync                        // Synchronous 32-bit EL1
+       ventry  el1_irq                         // IRQ 32-bit EL1
+       ventry  el1_fiq_invalid                 // FIQ 32-bit EL1
+       ventry  el1_error_invalid               // Error 32-bit EL1
+ENDPROC(__kvm_hyp_vector)
diff --git a/arch/arm64/kvm/hyp/hyp.h b/arch/arm64/kvm/hyp/hyp.h
new file mode 100644 (file)
index 0000000..fb27517
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.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.
+ *
+ * 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 __ARM64_KVM_HYP_H__
+#define __ARM64_KVM_HYP_H__
+
+#include <linux/compiler.h>
+#include <linux/kvm_host.h>
+#include <asm/kvm_mmu.h>
+#include <asm/sysreg.h>
+
+#define __hyp_text __section(.hyp.text) notrace
+
+#define kern_hyp_va(v) (typeof(v))((unsigned long)(v) & HYP_PAGE_OFFSET_MASK)
+#define hyp_kern_va(v) (typeof(v))((unsigned long)(v) - HYP_PAGE_OFFSET \
+                                                     + PAGE_OFFSET)
+
+/**
+ * hyp_alternate_select - Generates patchable code sequences that are
+ * used to switch between two implementations of a function, depending
+ * on the availability of a feature.
+ *
+ * @fname: a symbol name that will be defined as a function returning a
+ * function pointer whose type will match @orig and @alt
+ * @orig: A pointer to the default function, as returned by @fname when
+ * @cond doesn't hold
+ * @alt: A pointer to the alternate function, as returned by @fname
+ * when @cond holds
+ * @cond: a CPU feature (as described in asm/cpufeature.h)
+ */
+#define hyp_alternate_select(fname, orig, alt, cond)                   \
+typeof(orig) * __hyp_text fname(void)                                  \
+{                                                                      \
+       typeof(alt) *val = orig;                                        \
+       asm volatile(ALTERNATIVE("nop           \n",                    \
+                                "mov   %0, %1  \n",                    \
+                                cond)                                  \
+                    : "+r" (val) : "r" (alt));                         \
+       return val;                                                     \
+}
+
+void __vgic_v2_save_state(struct kvm_vcpu *vcpu);
+void __vgic_v2_restore_state(struct kvm_vcpu *vcpu);
+
+void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
+void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
+
+void __timer_save_state(struct kvm_vcpu *vcpu);
+void __timer_restore_state(struct kvm_vcpu *vcpu);
+
+void __sysreg_save_state(struct kvm_cpu_context *ctxt);
+void __sysreg_restore_state(struct kvm_cpu_context *ctxt);
+void __sysreg32_save_state(struct kvm_vcpu *vcpu);
+void __sysreg32_restore_state(struct kvm_vcpu *vcpu);
+
+void __debug_save_state(struct kvm_vcpu *vcpu,
+                       struct kvm_guest_debug_arch *dbg,
+                       struct kvm_cpu_context *ctxt);
+void __debug_restore_state(struct kvm_vcpu *vcpu,
+                          struct kvm_guest_debug_arch *dbg,
+                          struct kvm_cpu_context *ctxt);
+void __debug_cond_save_host_state(struct kvm_vcpu *vcpu);
+void __debug_cond_restore_host_state(struct kvm_vcpu *vcpu);
+
+void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
+void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
+static inline bool __fpsimd_enabled(void)
+{
+       return !(read_sysreg(cptr_el2) & CPTR_EL2_TFP);
+}
+
+u64 __guest_enter(struct kvm_vcpu *vcpu, struct kvm_cpu_context *host_ctxt);
+void __noreturn __hyp_do_panic(unsigned long, ...);
+
+#endif /* __ARM64_KVM_HYP_H__ */
+
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
new file mode 100644 (file)
index 0000000..ca8f5a5
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.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.
+ *
+ * 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 "hyp.h"
+
+static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
+{
+       u64 val;
+
+       /*
+        * We are about to set CPTR_EL2.TFP to trap all floating point
+        * register accesses to EL2, however, the ARM ARM clearly states that
+        * traps are only taken to EL2 if the operation would not otherwise
+        * trap to EL1.  Therefore, always make sure that for 32-bit guests,
+        * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
+        */
+       val = vcpu->arch.hcr_el2;
+       if (!(val & HCR_RW)) {
+               write_sysreg(1 << 30, fpexc32_el2);
+               isb();
+       }
+       write_sysreg(val, hcr_el2);
+       /* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
+       write_sysreg(1 << 15, hstr_el2);
+       write_sysreg(CPTR_EL2_TTA | CPTR_EL2_TFP, cptr_el2);
+       write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
+}
+
+static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
+{
+       write_sysreg(HCR_RW, hcr_el2);
+       write_sysreg(0, hstr_el2);
+       write_sysreg(read_sysreg(mdcr_el2) & MDCR_EL2_HPMN_MASK, mdcr_el2);
+       write_sysreg(0, cptr_el2);
+}
+
+static void __hyp_text __activate_vm(struct kvm_vcpu *vcpu)
+{
+       struct kvm *kvm = kern_hyp_va(vcpu->kvm);
+       write_sysreg(kvm->arch.vttbr, vttbr_el2);
+}
+
+static void __hyp_text __deactivate_vm(struct kvm_vcpu *vcpu)
+{
+       write_sysreg(0, vttbr_el2);
+}
+
+static hyp_alternate_select(__vgic_call_save_state,
+                           __vgic_v2_save_state, __vgic_v3_save_state,
+                           ARM64_HAS_SYSREG_GIC_CPUIF);
+
+static hyp_alternate_select(__vgic_call_restore_state,
+                           __vgic_v2_restore_state, __vgic_v3_restore_state,
+                           ARM64_HAS_SYSREG_GIC_CPUIF);
+
+static void __hyp_text __vgic_save_state(struct kvm_vcpu *vcpu)
+{
+       __vgic_call_save_state()(vcpu);
+       write_sysreg(read_sysreg(hcr_el2) & ~HCR_INT_OVERRIDE, hcr_el2);
+}
+
+static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
+{
+       u64 val;
+
+       val = read_sysreg(hcr_el2);
+       val |=  HCR_INT_OVERRIDE;
+       val |= vcpu->arch.irq_lines;
+       write_sysreg(val, hcr_el2);
+
+       __vgic_call_restore_state()(vcpu);
+}
+
+static int __hyp_text __guest_run(struct kvm_vcpu *vcpu)
+{
+       struct kvm_cpu_context *host_ctxt;
+       struct kvm_cpu_context *guest_ctxt;
+       bool fp_enabled;
+       u64 exit_code;
+
+       vcpu = kern_hyp_va(vcpu);
+       write_sysreg(vcpu, tpidr_el2);
+
+       host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+       guest_ctxt = &vcpu->arch.ctxt;
+
+       __sysreg_save_state(host_ctxt);
+       __debug_cond_save_host_state(vcpu);
+
+       __activate_traps(vcpu);
+       __activate_vm(vcpu);
+
+       __vgic_restore_state(vcpu);
+       __timer_restore_state(vcpu);
+
+       /*
+        * We must restore the 32-bit state before the sysregs, thanks
+        * to Cortex-A57 erratum #852523.
+        */
+       __sysreg32_restore_state(vcpu);
+       __sysreg_restore_state(guest_ctxt);
+       __debug_restore_state(vcpu, kern_hyp_va(vcpu->arch.debug_ptr), guest_ctxt);
+
+       /* Jump in the fire! */
+       exit_code = __guest_enter(vcpu, host_ctxt);
+       /* And we're baaack! */
+
+       fp_enabled = __fpsimd_enabled();
+
+       __sysreg_save_state(guest_ctxt);
+       __sysreg32_save_state(vcpu);
+       __timer_save_state(vcpu);
+       __vgic_save_state(vcpu);
+
+       __deactivate_traps(vcpu);
+       __deactivate_vm(vcpu);
+
+       __sysreg_restore_state(host_ctxt);
+
+       if (fp_enabled) {
+               __fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
+               __fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
+       }
+
+       __debug_save_state(vcpu, kern_hyp_va(vcpu->arch.debug_ptr), guest_ctxt);
+       __debug_cond_restore_host_state(vcpu);
+
+       return exit_code;
+}
+
+__alias(__guest_run) int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
+
+static const char __hyp_panic_string[] = "HYP panic:\nPS:%08llx PC:%016llx ESR:%08llx\nFAR:%016llx HPFAR:%016llx PAR:%016llx\nVCPU:%p\n";
+
+void __hyp_text __noreturn __hyp_panic(void)
+{
+       unsigned long str_va = (unsigned long)__hyp_panic_string;
+       u64 spsr = read_sysreg(spsr_el2);
+       u64 elr = read_sysreg(elr_el2);
+       u64 par = read_sysreg(par_el1);
+
+       if (read_sysreg(vttbr_el2)) {
+               struct kvm_vcpu *vcpu;
+               struct kvm_cpu_context *host_ctxt;
+
+               vcpu = (struct kvm_vcpu *)read_sysreg(tpidr_el2);
+               host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+               __deactivate_traps(vcpu);
+               __deactivate_vm(vcpu);
+               __sysreg_restore_state(host_ctxt);
+       }
+
+       /* Call panic for real */
+       __hyp_do_panic(hyp_kern_va(str_va),
+                      spsr,  elr,
+                      read_sysreg(esr_el2),   read_sysreg(far_el2),
+                      read_sysreg(hpfar_el2), par,
+                      (void *)read_sysreg(tpidr_el2));
+
+       unreachable();
+}
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
new file mode 100644 (file)
index 0000000..4256309
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2012-2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.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.
+ *
+ * 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/compiler.h>
+#include <linux/kvm_host.h>
+
+#include <asm/kvm_asm.h>
+#include <asm/kvm_mmu.h>
+
+#include "hyp.h"
+
+/* ctxt is already in the HYP VA space */
+void __hyp_text __sysreg_save_state(struct kvm_cpu_context *ctxt)
+{
+       ctxt->sys_regs[MPIDR_EL1]       = read_sysreg(vmpidr_el2);
+       ctxt->sys_regs[CSSELR_EL1]      = read_sysreg(csselr_el1);
+       ctxt->sys_regs[SCTLR_EL1]       = read_sysreg(sctlr_el1);
+       ctxt->sys_regs[ACTLR_EL1]       = read_sysreg(actlr_el1);
+       ctxt->sys_regs[CPACR_EL1]       = read_sysreg(cpacr_el1);
+       ctxt->sys_regs[TTBR0_EL1]       = read_sysreg(ttbr0_el1);
+       ctxt->sys_regs[TTBR1_EL1]       = read_sysreg(ttbr1_el1);
+       ctxt->sys_regs[TCR_EL1]         = read_sysreg(tcr_el1);
+       ctxt->sys_regs[ESR_EL1]         = read_sysreg(esr_el1);
+       ctxt->sys_regs[AFSR0_EL1]       = read_sysreg(afsr0_el1);
+       ctxt->sys_regs[AFSR1_EL1]       = read_sysreg(afsr1_el1);
+       ctxt->sys_regs[FAR_EL1]         = read_sysreg(far_el1);
+       ctxt->sys_regs[MAIR_EL1]        = read_sysreg(mair_el1);
+       ctxt->sys_regs[VBAR_EL1]        = read_sysreg(vbar_el1);
+       ctxt->sys_regs[CONTEXTIDR_EL1]  = read_sysreg(contextidr_el1);
+       ctxt->sys_regs[TPIDR_EL0]       = read_sysreg(tpidr_el0);
+       ctxt->sys_regs[TPIDRRO_EL0]     = read_sysreg(tpidrro_el0);
+       ctxt->sys_regs[TPIDR_EL1]       = read_sysreg(tpidr_el1);
+       ctxt->sys_regs[AMAIR_EL1]       = read_sysreg(amair_el1);
+       ctxt->sys_regs[CNTKCTL_EL1]     = read_sysreg(cntkctl_el1);
+       ctxt->sys_regs[PAR_EL1]         = read_sysreg(par_el1);
+       ctxt->sys_regs[MDSCR_EL1]       = read_sysreg(mdscr_el1);
+
+       ctxt->gp_regs.regs.sp           = read_sysreg(sp_el0);
+       ctxt->gp_regs.regs.pc           = read_sysreg(elr_el2);
+       ctxt->gp_regs.regs.pstate       = read_sysreg(spsr_el2);
+       ctxt->gp_regs.sp_el1            = read_sysreg(sp_el1);
+       ctxt->gp_regs.elr_el1           = read_sysreg(elr_el1);
+       ctxt->gp_regs.spsr[KVM_SPSR_EL1]= read_sysreg(spsr_el1);
+}
+
+void __hyp_text __sysreg_restore_state(struct kvm_cpu_context *ctxt)
+{
+       write_sysreg(ctxt->sys_regs[MPIDR_EL1],   vmpidr_el2);
+       write_sysreg(ctxt->sys_regs[CSSELR_EL1],  csselr_el1);
+       write_sysreg(ctxt->sys_regs[SCTLR_EL1],   sctlr_el1);
+       write_sysreg(ctxt->sys_regs[ACTLR_EL1],   actlr_el1);
+       write_sysreg(ctxt->sys_regs[CPACR_EL1],   cpacr_el1);
+       write_sysreg(ctxt->sys_regs[TTBR0_EL1],   ttbr0_el1);
+       write_sysreg(ctxt->sys_regs[TTBR1_EL1],   ttbr1_el1);
+       write_sysreg(ctxt->sys_regs[TCR_EL1],     tcr_el1);
+       write_sysreg(ctxt->sys_regs[ESR_EL1],     esr_el1);
+       write_sysreg(ctxt->sys_regs[AFSR0_EL1],   afsr0_el1);
+       write_sysreg(ctxt->sys_regs[AFSR1_EL1],   afsr1_el1);
+       write_sysreg(ctxt->sys_regs[FAR_EL1],     far_el1);
+       write_sysreg(ctxt->sys_regs[MAIR_EL1],    mair_el1);
+       write_sysreg(ctxt->sys_regs[VBAR_EL1],    vbar_el1);
+       write_sysreg(ctxt->sys_regs[CONTEXTIDR_EL1], contextidr_el1);
+       write_sysreg(ctxt->sys_regs[TPIDR_EL0],   tpidr_el0);
+       write_sysreg(ctxt->sys_regs[TPIDRRO_EL0], tpidrro_el0);
+       write_sysreg(ctxt->sys_regs[TPIDR_EL1],   tpidr_el1);
+       write_sysreg(ctxt->sys_regs[AMAIR_EL1],   amair_el1);
+       write_sysreg(ctxt->sys_regs[CNTKCTL_EL1], cntkctl_el1);
+       write_sysreg(ctxt->sys_regs[PAR_EL1],     par_el1);
+       write_sysreg(ctxt->sys_regs[MDSCR_EL1],   mdscr_el1);
+
+       write_sysreg(ctxt->gp_regs.regs.sp,     sp_el0);
+       write_sysreg(ctxt->gp_regs.regs.pc,     elr_el2);
+       write_sysreg(ctxt->gp_regs.regs.pstate, spsr_el2);
+       write_sysreg(ctxt->gp_regs.sp_el1,      sp_el1);
+       write_sysreg(ctxt->gp_regs.elr_el1,     elr_el1);
+       write_sysreg(ctxt->gp_regs.spsr[KVM_SPSR_EL1], spsr_el1);
+}
+
+void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
+{
+       u64 *spsr, *sysreg;
+
+       if (read_sysreg(hcr_el2) & HCR_RW)
+               return;
+
+       spsr = vcpu->arch.ctxt.gp_regs.spsr;
+       sysreg = vcpu->arch.ctxt.sys_regs;
+
+       spsr[KVM_SPSR_ABT] = read_sysreg(spsr_abt);
+       spsr[KVM_SPSR_UND] = read_sysreg(spsr_und);
+       spsr[KVM_SPSR_IRQ] = read_sysreg(spsr_irq);
+       spsr[KVM_SPSR_FIQ] = read_sysreg(spsr_fiq);
+
+       sysreg[DACR32_EL2] = read_sysreg(dacr32_el2);
+       sysreg[IFSR32_EL2] = read_sysreg(ifsr32_el2);
+
+       if (__fpsimd_enabled())
+               sysreg[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
+
+       if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
+               sysreg[DBGVCR32_EL2] = read_sysreg(dbgvcr32_el2);
+}
+
+void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
+{
+       u64 *spsr, *sysreg;
+
+       if (read_sysreg(hcr_el2) & HCR_RW)
+               return;
+
+       spsr = vcpu->arch.ctxt.gp_regs.spsr;
+       sysreg = vcpu->arch.ctxt.sys_regs;
+
+       write_sysreg(spsr[KVM_SPSR_ABT], spsr_abt);
+       write_sysreg(spsr[KVM_SPSR_UND], spsr_und);
+       write_sysreg(spsr[KVM_SPSR_IRQ], spsr_irq);
+       write_sysreg(spsr[KVM_SPSR_FIQ], spsr_fiq);
+
+       write_sysreg(sysreg[DACR32_EL2], dacr32_el2);
+       write_sysreg(sysreg[IFSR32_EL2], ifsr32_el2);
+
+       if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
+               write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
+}
diff --git a/arch/arm64/kvm/hyp/timer-sr.c b/arch/arm64/kvm/hyp/timer-sr.c
new file mode 100644 (file)
index 0000000..1051e5d
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2012-2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.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.
+ *
+ * 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 <clocksource/arm_arch_timer.h>
+#include <linux/compiler.h>
+#include <linux/kvm_host.h>
+
+#include <asm/kvm_mmu.h>
+
+#include "hyp.h"
+
+/* vcpu is already in the HYP VA space */
+void __hyp_text __timer_save_state(struct kvm_vcpu *vcpu)
+{
+       struct kvm *kvm = kern_hyp_va(vcpu->kvm);
+       struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+       u64 val;
+
+       if (kvm->arch.timer.enabled) {
+               timer->cntv_ctl = read_sysreg(cntv_ctl_el0);
+               timer->cntv_cval = read_sysreg(cntv_cval_el0);
+       }
+
+       /* Disable the virtual timer */
+       write_sysreg(0, cntv_ctl_el0);
+
+       /* Allow physical timer/counter access for the host */
+       val = read_sysreg(cnthctl_el2);
+       val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
+       write_sysreg(val, cnthctl_el2);
+
+       /* Clear cntvoff for the host */
+       write_sysreg(0, cntvoff_el2);
+}
+
+void __hyp_text __timer_restore_state(struct kvm_vcpu *vcpu)
+{
+       struct kvm *kvm = kern_hyp_va(vcpu->kvm);
+       struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+       u64 val;
+
+       /*
+        * Disallow physical timer access for the guest
+        * Physical counter access is allowed
+        */
+       val = read_sysreg(cnthctl_el2);
+       val &= ~CNTHCTL_EL1PCEN;
+       val |= CNTHCTL_EL1PCTEN;
+       write_sysreg(val, cnthctl_el2);
+
+       if (kvm->arch.timer.enabled) {
+               write_sysreg(kvm->arch.timer.cntvoff, cntvoff_el2);
+               write_sysreg(timer->cntv_cval, cntv_cval_el0);
+               isb();
+               write_sysreg(timer->cntv_ctl, cntv_ctl_el0);
+       }
+}
diff --git a/arch/arm64/kvm/hyp/tlb.c b/arch/arm64/kvm/hyp/tlb.c
new file mode 100644 (file)
index 0000000..2a7e0d8
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.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.
+ *
+ * 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 "hyp.h"
+
+static void __hyp_text __tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
+{
+       dsb(ishst);
+
+       /* Switch to requested VMID */
+       kvm = kern_hyp_va(kvm);
+       write_sysreg(kvm->arch.vttbr, vttbr_el2);
+       isb();
+
+       /*
+        * We could do so much better if we had the VA as well.
+        * Instead, we invalidate Stage-2 for this IPA, and the
+        * whole of Stage-1. Weep...
+        */
+       ipa >>= 12;
+       asm volatile("tlbi ipas2e1is, %0" : : "r" (ipa));
+
+       /*
+        * We have to ensure completion of the invalidation at Stage-2,
+        * since a table walk on another CPU could refill a TLB with a
+        * complete (S1 + S2) walk based on the old Stage-2 mapping if
+        * the Stage-1 invalidation happened first.
+        */
+       dsb(ish);
+       asm volatile("tlbi vmalle1is" : : );
+       dsb(ish);
+       isb();
+
+       write_sysreg(0, vttbr_el2);
+}
+
+__alias(__tlb_flush_vmid_ipa) void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm,
+                                                           phys_addr_t ipa);
+
+static void __hyp_text __tlb_flush_vmid(struct kvm *kvm)
+{
+       dsb(ishst);
+
+       /* Switch to requested VMID */
+       kvm = kern_hyp_va(kvm);
+       write_sysreg(kvm->arch.vttbr, vttbr_el2);
+       isb();
+
+       asm volatile("tlbi vmalls12e1is" : : );
+       dsb(ish);
+       isb();
+
+       write_sysreg(0, vttbr_el2);
+}
+
+__alias(__tlb_flush_vmid) void __kvm_tlb_flush_vmid(struct kvm *kvm);
+
+static void __hyp_text __tlb_flush_vm_context(void)
+{
+       dsb(ishst);
+       asm volatile("tlbi alle1is      \n"
+                    "ic ialluis          ": : );
+       dsb(ish);
+}
+
+__alias(__tlb_flush_vm_context) void __kvm_flush_vm_context(void);
diff --git a/arch/arm64/kvm/hyp/vgic-v2-sr.c b/arch/arm64/kvm/hyp/vgic-v2-sr.c
new file mode 100644 (file)
index 0000000..e717612
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2012-2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.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.
+ *
+ * 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/compiler.h>
+#include <linux/irqchip/arm-gic.h>
+#include <linux/kvm_host.h>
+
+#include <asm/kvm_mmu.h>
+
+#include "hyp.h"
+
+/* vcpu is already in the HYP VA space */
+void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
+{
+       struct kvm *kvm = kern_hyp_va(vcpu->kvm);
+       struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
+       struct vgic_dist *vgic = &kvm->arch.vgic;
+       void __iomem *base = kern_hyp_va(vgic->vctrl_base);
+       u32 eisr0, eisr1, elrsr0, elrsr1;
+       int i, nr_lr;
+
+       if (!base)
+               return;
+
+       nr_lr = vcpu->arch.vgic_cpu.nr_lr;
+       cpu_if->vgic_vmcr = readl_relaxed(base + GICH_VMCR);
+       cpu_if->vgic_misr = readl_relaxed(base + GICH_MISR);
+       eisr0  = readl_relaxed(base + GICH_EISR0);
+       elrsr0 = readl_relaxed(base + GICH_ELRSR0);
+       if (unlikely(nr_lr > 32)) {
+               eisr1  = readl_relaxed(base + GICH_EISR1);
+               elrsr1 = readl_relaxed(base + GICH_ELRSR1);
+       } else {
+               eisr1 = elrsr1 = 0;
+       }
+#ifdef CONFIG_CPU_BIG_ENDIAN
+       cpu_if->vgic_eisr  = ((u64)eisr0 << 32) | eisr1;
+       cpu_if->vgic_elrsr = ((u64)elrsr0 << 32) | elrsr1;
+#else
+       cpu_if->vgic_eisr  = ((u64)eisr1 << 32) | eisr0;
+       cpu_if->vgic_elrsr = ((u64)elrsr1 << 32) | elrsr0;
+#endif
+       cpu_if->vgic_apr    = readl_relaxed(base + GICH_APR);
+
+       writel_relaxed(0, base + GICH_HCR);
+
+       for (i = 0; i < nr_lr; i++)
+               cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4));
+}
+
+/* vcpu is already in the HYP VA space */
+void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
+{
+       struct kvm *kvm = kern_hyp_va(vcpu->kvm);
+       struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
+       struct vgic_dist *vgic = &kvm->arch.vgic;
+       void __iomem *base = kern_hyp_va(vgic->vctrl_base);
+       int i, nr_lr;
+
+       if (!base)
+               return;
+
+       writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
+       writel_relaxed(cpu_if->vgic_vmcr, base + GICH_VMCR);
+       writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
+
+       nr_lr = vcpu->arch.vgic_cpu.nr_lr;
+       for (i = 0; i < nr_lr; i++)
+               writel_relaxed(cpu_if->vgic_lr[i], base + GICH_LR0 + (i * 4));
+}
diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c
new file mode 100644 (file)
index 0000000..9142e08
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2012-2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.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.
+ *
+ * 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/compiler.h>
+#include <linux/irqchip/arm-gic-v3.h>
+#include <linux/kvm_host.h>
+
+#include <asm/kvm_mmu.h>
+
+#include "hyp.h"
+
+#define vtr_to_max_lr_idx(v)           ((v) & 0xf)
+#define vtr_to_nr_pri_bits(v)          (((u32)(v) >> 29) + 1)
+
+#define read_gicreg(r)                                                 \
+       ({                                                              \
+               u64 reg;                                                \
+               asm volatile("mrs_s %0, " __stringify(r) : "=r" (reg)); \
+               reg;                                                    \
+       })
+
+#define write_gicreg(v,r)                                              \
+       do {                                                            \
+               u64 __val = (v);                                        \
+               asm volatile("msr_s " __stringify(r) ", %0" : : "r" (__val));\
+       } while (0)
+
+/* vcpu is already in the HYP VA space */
+void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
+{
+       struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+       u64 val;
+       u32 max_lr_idx, nr_pri_bits;
+
+       /*
+        * Make sure stores to the GIC via the memory mapped interface
+        * are now visible to the system register interface.
+        */
+       dsb(st);
+
+       cpu_if->vgic_vmcr  = read_gicreg(ICH_VMCR_EL2);
+       cpu_if->vgic_misr  = read_gicreg(ICH_MISR_EL2);
+       cpu_if->vgic_eisr  = read_gicreg(ICH_EISR_EL2);
+       cpu_if->vgic_elrsr = read_gicreg(ICH_ELSR_EL2);
+
+       write_gicreg(0, ICH_HCR_EL2);
+       val = read_gicreg(ICH_VTR_EL2);
+       max_lr_idx = vtr_to_max_lr_idx(val);
+       nr_pri_bits = vtr_to_nr_pri_bits(val);
+
+       switch (max_lr_idx) {
+       case 15:
+               cpu_if->vgic_lr[VGIC_V3_LR_INDEX(15)] = read_gicreg(ICH_LR15_EL2);
+       case 14:
+               cpu_if->vgic_lr[VGIC_V3_LR_INDEX(14)] = read_gicreg(ICH_LR14_EL2);
+       case 13:
+               cpu_if->vgic_lr[VGIC_V3_LR_INDEX(13)] = read_gicreg(ICH_LR13_EL2);
+       case 12:
+               cpu_if->vgic_lr[VGIC_V3_LR_INDEX(12)] = read_gicreg(ICH_LR12_EL2);
+       case 11:
+               cpu_if->vgic_lr[VGIC_V3_LR_INDEX(11)] = read_gicreg(ICH_LR11_EL2);
+       case 10:
+               cpu_if->vgic_lr[VGIC_V3_LR_INDEX(10)] = read_gicreg(ICH_LR10_EL2);
+       case 9:
+               cpu_if->vgic_lr[VGIC_V3_LR_INDEX(9)] = read_gicreg(ICH_LR9_EL2);
+       case 8:
+               cpu_if->vgic_lr[VGIC_V3_LR_INDEX(8)] = read_gicreg(ICH_LR8_EL2);
+       case 7:
+               cpu_if->vgic_lr[VGIC_V3_LR_INDEX(7)] = read_gicreg(ICH_LR7_EL2);
+       case 6:
+               cpu_if->vgic_lr[VGIC_V3_LR_INDEX(6)] = read_gicreg(ICH_LR6_EL2);
+       case 5:
+               cpu_if->vgic_lr[VGIC_V3_LR_INDEX(5)] = read_gicreg(ICH_LR5_EL2);
+       case 4:
+               cpu_if->vgic_lr[VGIC_V3_LR_INDEX(4)] = read_gicreg(ICH_LR4_EL2);
+       case 3:
+               cpu_if->vgic_lr[VGIC_V3_LR_INDEX(3)] = read_gicreg(ICH_LR3_EL2);
+       case 2:
+               cpu_if->vgic_lr[VGIC_V3_LR_INDEX(2)] = read_gicreg(ICH_LR2_EL2);
+       case 1:
+               cpu_if->vgic_lr[VGIC_V3_LR_INDEX(1)] = read_gicreg(ICH_LR1_EL2);
+       case 0:
+               cpu_if->vgic_lr[VGIC_V3_LR_INDEX(0)] = read_gicreg(ICH_LR0_EL2);
+       }
+
+       switch (nr_pri_bits) {
+       case 7:
+               cpu_if->vgic_ap0r[3] = read_gicreg(ICH_AP0R3_EL2);
+               cpu_if->vgic_ap0r[2] = read_gicreg(ICH_AP0R2_EL2);
+       case 6:
+               cpu_if->vgic_ap0r[1] = read_gicreg(ICH_AP0R1_EL2);
+       default:
+               cpu_if->vgic_ap0r[0] = read_gicreg(ICH_AP0R0_EL2);
+       }
+
+       switch (nr_pri_bits) {
+       case 7:
+               cpu_if->vgic_ap1r[3] = read_gicreg(ICH_AP1R3_EL2);
+               cpu_if->vgic_ap1r[2] = read_gicreg(ICH_AP1R2_EL2);
+       case 6:
+               cpu_if->vgic_ap1r[1] = read_gicreg(ICH_AP1R1_EL2);
+       default:
+               cpu_if->vgic_ap1r[0] = read_gicreg(ICH_AP1R0_EL2);
+       }
+
+       val = read_gicreg(ICC_SRE_EL2);
+       write_gicreg(val | ICC_SRE_EL2_ENABLE, ICC_SRE_EL2);
+       isb(); /* Make sure ENABLE is set at EL2 before setting SRE at EL1 */
+       write_gicreg(1, ICC_SRE_EL1);
+}
+
+void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
+{
+       struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+       u64 val;
+       u32 max_lr_idx, nr_pri_bits;
+
+       /*
+        * VFIQEn is RES1 if ICC_SRE_EL1.SRE is 1. This causes a
+        * Group0 interrupt (as generated in GICv2 mode) to be
+        * delivered as a FIQ to the guest, with potentially fatal
+        * consequences. So we must make sure that ICC_SRE_EL1 has
+        * been actually programmed with the value we want before
+        * starting to mess with the rest of the GIC.
+        */
+       write_gicreg(cpu_if->vgic_sre, ICC_SRE_EL1);
+       isb();
+
+       write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
+       write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
+
+       val = read_gicreg(ICH_VTR_EL2);
+       max_lr_idx = vtr_to_max_lr_idx(val);
+       nr_pri_bits = vtr_to_nr_pri_bits(val);
+
+       switch (nr_pri_bits) {
+       case 7:
+                write_gicreg(cpu_if->vgic_ap1r[3], ICH_AP1R3_EL2);
+                write_gicreg(cpu_if->vgic_ap1r[2], ICH_AP1R2_EL2);
+       case 6:
+                write_gicreg(cpu_if->vgic_ap1r[1], ICH_AP1R1_EL2);
+       default:
+                write_gicreg(cpu_if->vgic_ap1r[0], ICH_AP1R0_EL2);
+       }                                          
+                                                  
+       switch (nr_pri_bits) {
+       case 7:
+                write_gicreg(cpu_if->vgic_ap0r[3], ICH_AP0R3_EL2);
+                write_gicreg(cpu_if->vgic_ap0r[2], ICH_AP0R2_EL2);
+       case 6:
+                write_gicreg(cpu_if->vgic_ap0r[1], ICH_AP0R1_EL2);
+       default:
+                write_gicreg(cpu_if->vgic_ap0r[0], ICH_AP0R0_EL2);
+       }
+
+       switch (max_lr_idx) {
+       case 15:
+               write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(15)], ICH_LR15_EL2);
+       case 14:
+               write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(14)], ICH_LR14_EL2);
+       case 13:
+               write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(13)], ICH_LR13_EL2);
+       case 12:
+               write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(12)], ICH_LR12_EL2);
+       case 11:
+               write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(11)], ICH_LR11_EL2);
+       case 10:
+               write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(10)], ICH_LR10_EL2);
+       case 9:
+               write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(9)], ICH_LR9_EL2);
+       case 8:
+               write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(8)], ICH_LR8_EL2);
+       case 7:
+               write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(7)], ICH_LR7_EL2);
+       case 6:
+               write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(6)], ICH_LR6_EL2);
+       case 5:
+               write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(5)], ICH_LR5_EL2);
+       case 4:
+               write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(4)], ICH_LR4_EL2);
+       case 3:
+               write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(3)], ICH_LR3_EL2);
+       case 2:
+               write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(2)], ICH_LR2_EL2);
+       case 1:
+               write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(1)], ICH_LR1_EL2);
+       case 0:
+               write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(0)], ICH_LR0_EL2);
+       }
+
+       /*
+        * Ensures that the above will have reached the
+        * (re)distributors. This ensure the guest will read the
+        * correct values from the memory-mapped interface.
+        */
+       isb();
+       dsb(sy);
+
+       /*
+        * Prevent the guest from touching the GIC system registers if
+        * SRE isn't enabled for GICv3 emulation.
+        */
+       if (!cpu_if->vgic_sre) {
+               write_gicreg(read_gicreg(ICC_SRE_EL2) & ~ICC_SRE_EL2_ENABLE,
+                            ICC_SRE_EL2);
+       }
+}
+
+static u64 __hyp_text __vgic_v3_read_ich_vtr_el2(void)
+{
+       return read_gicreg(ICH_VTR_EL2);
+}
+
+__alias(__vgic_v3_read_ich_vtr_el2) u64 __vgic_v3_get_ich_vtr_el2(void);
index d2650e84faf2f53f2afbdbd15e1f54d217e3fdb8..eec3598b4184077b83b5a1f24321891cb110f5bb 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/debug-monitors.h>
 #include <asm/esr.h>
 #include <asm/kvm_arm.h>
+#include <asm/kvm_asm.h>
 #include <asm/kvm_coproc.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_host.h>
@@ -219,9 +220,9 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
  * All writes will set the KVM_ARM64_DEBUG_DIRTY flag to ensure the
  * hyp.S code switches between host and guest values in future.
  */
-static inline void reg_to_dbg(struct kvm_vcpu *vcpu,
-                             struct sys_reg_params *p,
-                             u64 *dbg_reg)
+static void reg_to_dbg(struct kvm_vcpu *vcpu,
+                      struct sys_reg_params *p,
+                      u64 *dbg_reg)
 {
        u64 val = p->regval;
 
@@ -234,18 +235,18 @@ static inline void reg_to_dbg(struct kvm_vcpu *vcpu,
        vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
 }
 
-static inline void dbg_to_reg(struct kvm_vcpu *vcpu,
-                             struct sys_reg_params *p,
-                             u64 *dbg_reg)
+static void dbg_to_reg(struct kvm_vcpu *vcpu,
+                      struct sys_reg_params *p,
+                      u64 *dbg_reg)
 {
        p->regval = *dbg_reg;
        if (p->is_32bit)
                p->regval &= 0xffffffffUL;
 }
 
-static inline bool trap_bvr(struct kvm_vcpu *vcpu,
-                           struct sys_reg_params *p,
-                           const struct sys_reg_desc *rd)
+static bool trap_bvr(struct kvm_vcpu *vcpu,
+                    struct sys_reg_params *p,
+                    const struct sys_reg_desc *rd)
 {
        u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg];
 
@@ -279,15 +280,15 @@ static int get_bvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
        return 0;
 }
 
-static inline void reset_bvr(struct kvm_vcpu *vcpu,
-                            const struct sys_reg_desc *rd)
+static void reset_bvr(struct kvm_vcpu *vcpu,
+                     const struct sys_reg_desc *rd)
 {
        vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg] = rd->val;
 }
 
-static inline bool trap_bcr(struct kvm_vcpu *vcpu,
-                           struct sys_reg_params *p,
-                           const struct sys_reg_desc *rd)
+static bool trap_bcr(struct kvm_vcpu *vcpu,
+                    struct sys_reg_params *p,
+                    const struct sys_reg_desc *rd)
 {
        u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg];
 
@@ -322,15 +323,15 @@ static int get_bcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
        return 0;
 }
 
-static inline void reset_bcr(struct kvm_vcpu *vcpu,
-                            const struct sys_reg_desc *rd)
+static void reset_bcr(struct kvm_vcpu *vcpu,
+                     const struct sys_reg_desc *rd)
 {
        vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg] = rd->val;
 }
 
-static inline bool trap_wvr(struct kvm_vcpu *vcpu,
-                           struct sys_reg_params *p,
-                           const struct sys_reg_desc *rd)
+static bool trap_wvr(struct kvm_vcpu *vcpu,
+                    struct sys_reg_params *p,
+                    const struct sys_reg_desc *rd)
 {
        u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg];
 
@@ -365,15 +366,15 @@ static int get_wvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
        return 0;
 }
 
-static inline void reset_wvr(struct kvm_vcpu *vcpu,
-                            const struct sys_reg_desc *rd)
+static void reset_wvr(struct kvm_vcpu *vcpu,
+                     const struct sys_reg_desc *rd)
 {
        vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg] = rd->val;
 }
 
-static inline bool trap_wcr(struct kvm_vcpu *vcpu,
-                           struct sys_reg_params *p,
-                           const struct sys_reg_desc *rd)
+static bool trap_wcr(struct kvm_vcpu *vcpu,
+                    struct sys_reg_params *p,
+                    const struct sys_reg_desc *rd)
 {
        u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg];
 
@@ -407,8 +408,8 @@ static int get_wcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
        return 0;
 }
 
-static inline void reset_wcr(struct kvm_vcpu *vcpu,
-                            const struct sys_reg_desc *rd)
+static void reset_wcr(struct kvm_vcpu *vcpu,
+                     const struct sys_reg_desc *rd)
 {
        vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg] = rd->val;
 }
@@ -722,9 +723,9 @@ static bool trap_debug32(struct kvm_vcpu *vcpu,
  * system is in.
  */
 
-static inline bool trap_xvr(struct kvm_vcpu *vcpu,
-                           struct sys_reg_params *p,
-                           const struct sys_reg_desc *rd)
+static bool trap_xvr(struct kvm_vcpu *vcpu,
+                    struct sys_reg_params *p,
+                    const struct sys_reg_desc *rd)
 {
        u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg];
 
diff --git a/arch/arm64/kvm/vgic-v2-switch.S b/arch/arm64/kvm/vgic-v2-switch.S
deleted file mode 100644 (file)
index 3f00071..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2012,2013 - ARM Ltd
- * Author: Marc Zyngier <marc.zyngier@arm.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.
- *
- * 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/linkage.h>
-#include <linux/irqchip/arm-gic.h>
-
-#include <asm/assembler.h>
-#include <asm/memory.h>
-#include <asm/asm-offsets.h>
-#include <asm/kvm.h>
-#include <asm/kvm_asm.h>
-#include <asm/kvm_arm.h>
-#include <asm/kvm_mmu.h>
-
-       .text
-       .pushsection    .hyp.text, "ax"
-
-/*
- * Save the VGIC CPU state into memory
- * x0: Register pointing to VCPU struct
- * Do not corrupt x1!!!
- */
-ENTRY(__save_vgic_v2_state)
-__save_vgic_v2_state:
-       /* Get VGIC VCTRL base into x2 */
-       ldr     x2, [x0, #VCPU_KVM]
-       kern_hyp_va     x2
-       ldr     x2, [x2, #KVM_VGIC_VCTRL]
-       kern_hyp_va     x2
-       cbz     x2, 2f          // disabled
-
-       /* Compute the address of struct vgic_cpu */
-       add     x3, x0, #VCPU_VGIC_CPU
-
-       /* Save all interesting registers */
-       ldr     w5, [x2, #GICH_VMCR]
-       ldr     w6, [x2, #GICH_MISR]
-       ldr     w7, [x2, #GICH_EISR0]
-       ldr     w8, [x2, #GICH_EISR1]
-       ldr     w9, [x2, #GICH_ELRSR0]
-       ldr     w10, [x2, #GICH_ELRSR1]
-       ldr     w11, [x2, #GICH_APR]
-CPU_BE(        rev     w5,  w5  )
-CPU_BE(        rev     w6,  w6  )
-CPU_BE(        rev     w7,  w7  )
-CPU_BE(        rev     w8,  w8  )
-CPU_BE(        rev     w9,  w9  )
-CPU_BE(        rev     w10, w10 )
-CPU_BE(        rev     w11, w11 )
-
-       str     w5, [x3, #VGIC_V2_CPU_VMCR]
-       str     w6, [x3, #VGIC_V2_CPU_MISR]
-CPU_LE(        str     w7, [x3, #VGIC_V2_CPU_EISR] )
-CPU_LE(        str     w8, [x3, #(VGIC_V2_CPU_EISR + 4)] )
-CPU_LE(        str     w9, [x3, #VGIC_V2_CPU_ELRSR] )
-CPU_LE(        str     w10, [x3, #(VGIC_V2_CPU_ELRSR + 4)] )
-CPU_BE(        str     w7, [x3, #(VGIC_V2_CPU_EISR + 4)] )
-CPU_BE(        str     w8, [x3, #VGIC_V2_CPU_EISR] )
-CPU_BE(        str     w9, [x3, #(VGIC_V2_CPU_ELRSR + 4)] )
-CPU_BE(        str     w10, [x3, #VGIC_V2_CPU_ELRSR] )
-       str     w11, [x3, #VGIC_V2_CPU_APR]
-
-       /* Clear GICH_HCR */
-       str     wzr, [x2, #GICH_HCR]
-
-       /* Save list registers */
-       add     x2, x2, #GICH_LR0
-       ldr     w4, [x3, #VGIC_CPU_NR_LR]
-       add     x3, x3, #VGIC_V2_CPU_LR
-1:     ldr     w5, [x2], #4
-CPU_BE(        rev     w5, w5 )
-       str     w5, [x3], #4
-       sub     w4, w4, #1
-       cbnz    w4, 1b
-2:
-       ret
-ENDPROC(__save_vgic_v2_state)
-
-/*
- * Restore the VGIC CPU state from memory
- * x0: Register pointing to VCPU struct
- */
-ENTRY(__restore_vgic_v2_state)
-__restore_vgic_v2_state:
-       /* Get VGIC VCTRL base into x2 */
-       ldr     x2, [x0, #VCPU_KVM]
-       kern_hyp_va     x2
-       ldr     x2, [x2, #KVM_VGIC_VCTRL]
-       kern_hyp_va     x2
-       cbz     x2, 2f          // disabled
-
-       /* Compute the address of struct vgic_cpu */
-       add     x3, x0, #VCPU_VGIC_CPU
-
-       /* We only restore a minimal set of registers */
-       ldr     w4, [x3, #VGIC_V2_CPU_HCR]
-       ldr     w5, [x3, #VGIC_V2_CPU_VMCR]
-       ldr     w6, [x3, #VGIC_V2_CPU_APR]
-CPU_BE(        rev     w4, w4 )
-CPU_BE(        rev     w5, w5 )
-CPU_BE(        rev     w6, w6 )
-
-       str     w4, [x2, #GICH_HCR]
-       str     w5, [x2, #GICH_VMCR]
-       str     w6, [x2, #GICH_APR]
-
-       /* Restore list registers */
-       add     x2, x2, #GICH_LR0
-       ldr     w4, [x3, #VGIC_CPU_NR_LR]
-       add     x3, x3, #VGIC_V2_CPU_LR
-1:     ldr     w5, [x3], #4
-CPU_BE(        rev     w5, w5 )
-       str     w5, [x2], #4
-       sub     w4, w4, #1
-       cbnz    w4, 1b
-2:
-       ret
-ENDPROC(__restore_vgic_v2_state)
-
-       .popsection
diff --git a/arch/arm64/kvm/vgic-v3-switch.S b/arch/arm64/kvm/vgic-v3-switch.S
deleted file mode 100644 (file)
index 3c20730..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright (C) 2012,2013 - ARM Ltd
- * Author: Marc Zyngier <marc.zyngier@arm.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.
- *
- * 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/linkage.h>
-#include <linux/irqchip/arm-gic-v3.h>
-
-#include <asm/assembler.h>
-#include <asm/memory.h>
-#include <asm/asm-offsets.h>
-#include <asm/kvm.h>
-#include <asm/kvm_asm.h>
-#include <asm/kvm_arm.h>
-
-       .text
-       .pushsection    .hyp.text, "ax"
-
-/*
- * We store LRs in reverse order to let the CPU deal with streaming
- * access. Use this macro to make it look saner...
- */
-#define LR_OFFSET(n)   (VGIC_V3_CPU_LR + (15 - n) * 8)
-
-/*
- * Save the VGIC CPU state into memory
- * x0: Register pointing to VCPU struct
- * Do not corrupt x1!!!
- */
-.macro save_vgic_v3_state
-       // Compute the address of struct vgic_cpu
-       add     x3, x0, #VCPU_VGIC_CPU
-
-       // Make sure stores to the GIC via the memory mapped interface
-       // are now visible to the system register interface
-       dsb     st
-
-       // Save all interesting registers
-       mrs_s   x5, ICH_VMCR_EL2
-       mrs_s   x6, ICH_MISR_EL2
-       mrs_s   x7, ICH_EISR_EL2
-       mrs_s   x8, ICH_ELSR_EL2
-
-       str     w5, [x3, #VGIC_V3_CPU_VMCR]
-       str     w6, [x3, #VGIC_V3_CPU_MISR]
-       str     w7, [x3, #VGIC_V3_CPU_EISR]
-       str     w8, [x3, #VGIC_V3_CPU_ELRSR]
-
-       msr_s   ICH_HCR_EL2, xzr
-
-       mrs_s   x21, ICH_VTR_EL2
-       mvn     w22, w21
-       ubfiz   w23, w22, 2, 4  // w23 = (15 - ListRegs) * 4
-
-       adr     x24, 1f
-       add     x24, x24, x23
-       br      x24
-
-1:
-       mrs_s   x20, ICH_LR15_EL2
-       mrs_s   x19, ICH_LR14_EL2
-       mrs_s   x18, ICH_LR13_EL2
-       mrs_s   x17, ICH_LR12_EL2
-       mrs_s   x16, ICH_LR11_EL2
-       mrs_s   x15, ICH_LR10_EL2
-       mrs_s   x14, ICH_LR9_EL2
-       mrs_s   x13, ICH_LR8_EL2
-       mrs_s   x12, ICH_LR7_EL2
-       mrs_s   x11, ICH_LR6_EL2
-       mrs_s   x10, ICH_LR5_EL2
-       mrs_s   x9, ICH_LR4_EL2
-       mrs_s   x8, ICH_LR3_EL2
-       mrs_s   x7, ICH_LR2_EL2
-       mrs_s   x6, ICH_LR1_EL2
-       mrs_s   x5, ICH_LR0_EL2
-
-       adr     x24, 1f
-       add     x24, x24, x23
-       br      x24
-
-1:
-       str     x20, [x3, #LR_OFFSET(15)]
-       str     x19, [x3, #LR_OFFSET(14)]
-       str     x18, [x3, #LR_OFFSET(13)]
-       str     x17, [x3, #LR_OFFSET(12)]
-       str     x16, [x3, #LR_OFFSET(11)]
-       str     x15, [x3, #LR_OFFSET(10)]
-       str     x14, [x3, #LR_OFFSET(9)]
-       str     x13, [x3, #LR_OFFSET(8)]
-       str     x12, [x3, #LR_OFFSET(7)]
-       str     x11, [x3, #LR_OFFSET(6)]
-       str     x10, [x3, #LR_OFFSET(5)]
-       str     x9, [x3, #LR_OFFSET(4)]
-       str     x8, [x3, #LR_OFFSET(3)]
-       str     x7, [x3, #LR_OFFSET(2)]
-       str     x6, [x3, #LR_OFFSET(1)]
-       str     x5, [x3, #LR_OFFSET(0)]
-
-       tbnz    w21, #29, 6f    // 6 bits
-       tbz     w21, #30, 5f    // 5 bits
-                               // 7 bits
-       mrs_s   x20, ICH_AP0R3_EL2
-       str     w20, [x3, #(VGIC_V3_CPU_AP0R + 3*4)]
-       mrs_s   x19, ICH_AP0R2_EL2
-       str     w19, [x3, #(VGIC_V3_CPU_AP0R + 2*4)]
-6:     mrs_s   x18, ICH_AP0R1_EL2
-       str     w18, [x3, #(VGIC_V3_CPU_AP0R + 1*4)]
-5:     mrs_s   x17, ICH_AP0R0_EL2
-       str     w17, [x3, #VGIC_V3_CPU_AP0R]
-
-       tbnz    w21, #29, 6f    // 6 bits
-       tbz     w21, #30, 5f    // 5 bits
-                               // 7 bits
-       mrs_s   x20, ICH_AP1R3_EL2
-       str     w20, [x3, #(VGIC_V3_CPU_AP1R + 3*4)]
-       mrs_s   x19, ICH_AP1R2_EL2
-       str     w19, [x3, #(VGIC_V3_CPU_AP1R + 2*4)]
-6:     mrs_s   x18, ICH_AP1R1_EL2
-       str     w18, [x3, #(VGIC_V3_CPU_AP1R + 1*4)]
-5:     mrs_s   x17, ICH_AP1R0_EL2
-       str     w17, [x3, #VGIC_V3_CPU_AP1R]
-
-       // Restore SRE_EL1 access and re-enable SRE at EL1.
-       mrs_s   x5, ICC_SRE_EL2
-       orr     x5, x5, #ICC_SRE_EL2_ENABLE
-       msr_s   ICC_SRE_EL2, x5
-       isb
-       mov     x5, #1
-       msr_s   ICC_SRE_EL1, x5
-.endm
-
-/*
- * Restore the VGIC CPU state from memory
- * x0: Register pointing to VCPU struct
- */
-.macro restore_vgic_v3_state
-       // Compute the address of struct vgic_cpu
-       add     x3, x0, #VCPU_VGIC_CPU
-
-       // Restore all interesting registers
-       ldr     w4, [x3, #VGIC_V3_CPU_HCR]
-       ldr     w5, [x3, #VGIC_V3_CPU_VMCR]
-       ldr     w25, [x3, #VGIC_V3_CPU_SRE]
-
-       msr_s   ICC_SRE_EL1, x25
-
-       // make sure SRE is valid before writing the other registers
-       isb
-
-       msr_s   ICH_HCR_EL2, x4
-       msr_s   ICH_VMCR_EL2, x5
-
-       mrs_s   x21, ICH_VTR_EL2
-
-       tbnz    w21, #29, 6f    // 6 bits
-       tbz     w21, #30, 5f    // 5 bits
-                               // 7 bits
-       ldr     w20, [x3, #(VGIC_V3_CPU_AP1R + 3*4)]
-       msr_s   ICH_AP1R3_EL2, x20
-       ldr     w19, [x3, #(VGIC_V3_CPU_AP1R + 2*4)]
-       msr_s   ICH_AP1R2_EL2, x19
-6:     ldr     w18, [x3, #(VGIC_V3_CPU_AP1R + 1*4)]
-       msr_s   ICH_AP1R1_EL2, x18
-5:     ldr     w17, [x3, #VGIC_V3_CPU_AP1R]
-       msr_s   ICH_AP1R0_EL2, x17
-
-       tbnz    w21, #29, 6f    // 6 bits
-       tbz     w21, #30, 5f    // 5 bits
-                               // 7 bits
-       ldr     w20, [x3, #(VGIC_V3_CPU_AP0R + 3*4)]
-       msr_s   ICH_AP0R3_EL2, x20
-       ldr     w19, [x3, #(VGIC_V3_CPU_AP0R + 2*4)]
-       msr_s   ICH_AP0R2_EL2, x19
-6:     ldr     w18, [x3, #(VGIC_V3_CPU_AP0R + 1*4)]
-       msr_s   ICH_AP0R1_EL2, x18
-5:     ldr     w17, [x3, #VGIC_V3_CPU_AP0R]
-       msr_s   ICH_AP0R0_EL2, x17
-
-       and     w22, w21, #0xf
-       mvn     w22, w21
-       ubfiz   w23, w22, 2, 4  // w23 = (15 - ListRegs) * 4
-
-       adr     x24, 1f
-       add     x24, x24, x23
-       br      x24
-
-1:
-       ldr     x20, [x3, #LR_OFFSET(15)]
-       ldr     x19, [x3, #LR_OFFSET(14)]
-       ldr     x18, [x3, #LR_OFFSET(13)]
-       ldr     x17, [x3, #LR_OFFSET(12)]
-       ldr     x16, [x3, #LR_OFFSET(11)]
-       ldr     x15, [x3, #LR_OFFSET(10)]
-       ldr     x14, [x3, #LR_OFFSET(9)]
-       ldr     x13, [x3, #LR_OFFSET(8)]
-       ldr     x12, [x3, #LR_OFFSET(7)]
-       ldr     x11, [x3, #LR_OFFSET(6)]
-       ldr     x10, [x3, #LR_OFFSET(5)]
-       ldr     x9, [x3, #LR_OFFSET(4)]
-       ldr     x8, [x3, #LR_OFFSET(3)]
-       ldr     x7, [x3, #LR_OFFSET(2)]
-       ldr     x6, [x3, #LR_OFFSET(1)]
-       ldr     x5, [x3, #LR_OFFSET(0)]
-
-       adr     x24, 1f
-       add     x24, x24, x23
-       br      x24
-
-1:
-       msr_s   ICH_LR15_EL2, x20
-       msr_s   ICH_LR14_EL2, x19
-       msr_s   ICH_LR13_EL2, x18
-       msr_s   ICH_LR12_EL2, x17
-       msr_s   ICH_LR11_EL2, x16
-       msr_s   ICH_LR10_EL2, x15
-       msr_s   ICH_LR9_EL2,  x14
-       msr_s   ICH_LR8_EL2,  x13
-       msr_s   ICH_LR7_EL2,  x12
-       msr_s   ICH_LR6_EL2,  x11
-       msr_s   ICH_LR5_EL2,  x10
-       msr_s   ICH_LR4_EL2,   x9
-       msr_s   ICH_LR3_EL2,   x8
-       msr_s   ICH_LR2_EL2,   x7
-       msr_s   ICH_LR1_EL2,   x6
-       msr_s   ICH_LR0_EL2,   x5
-
-       // Ensure that the above will have reached the
-       // (re)distributors. This ensure the guest will read
-       // the correct values from the memory-mapped interface.
-       isb
-       dsb     sy
-
-       // Prevent the guest from touching the GIC system registers
-       // if SRE isn't enabled for GICv3 emulation
-       cbnz    x25, 1f
-       mrs_s   x5, ICC_SRE_EL2
-       and     x5, x5, #~ICC_SRE_EL2_ENABLE
-       msr_s   ICC_SRE_EL2, x5
-1:
-.endm
-
-ENTRY(__save_vgic_v3_state)
-       save_vgic_v3_state
-       ret
-ENDPROC(__save_vgic_v3_state)
-
-ENTRY(__restore_vgic_v3_state)
-       restore_vgic_v3_state
-       ret
-ENDPROC(__restore_vgic_v3_state)
-
-ENTRY(__vgic_v3_get_ich_vtr_el2)
-       mrs_s   x0, ICH_VTR_EL2
-       ret
-ENDPROC(__vgic_v3_get_ich_vtr_el2)
-
-       .popsection
index cfa44a6adc0ad5ec29f78228196b7e834b65df40..6df07069a0253013e254dbb1206debaa939a3526 100644 (file)
@@ -81,25 +81,31 @@ ENDPROC(__flush_cache_user_range)
 /*
  *     __flush_dcache_area(kaddr, size)
  *
- *     Ensure that the data held in the page kaddr is written back to the
- *     page in question.
+ *     Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
+ *     are cleaned and invalidated to the PoC.
  *
  *     - kaddr   - kernel address
  *     - size    - size in question
  */
 ENTRY(__flush_dcache_area)
-       dcache_line_size x2, x3
-       add     x1, x0, x1
-       sub     x3, x2, #1
-       bic     x0, x0, x3
-1:     dc      civac, x0                       // clean & invalidate D line / unified line
-       add     x0, x0, x2
-       cmp     x0, x1
-       b.lo    1b
-       dsb     sy
+       dcache_by_line_op civac, sy, x0, x1, x2, x3
        ret
 ENDPIPROC(__flush_dcache_area)
 
+/*
+ *     __clean_dcache_area_pou(kaddr, size)
+ *
+ *     Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
+ *     are cleaned to the PoU.
+ *
+ *     - kaddr   - kernel address
+ *     - size    - size in question
+ */
+ENTRY(__clean_dcache_area_pou)
+       dcache_by_line_op cvau, ish, x0, x1, x2, x3
+       ret
+ENDPROC(__clean_dcache_area_pou)
+
 /*
  *     __inval_cache_range(start, end)
  *     - start   - start address of region
index 13bbc3be6f5ab31a24d6d0a03b8f368ea6923ed8..22e4cb4d6f538baa43f7071ad1729dec01216d23 100644 (file)
@@ -24,8 +24,9 @@
 
 void __cpu_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr)
 {
+       struct page *page = virt_to_page(kto);
        copy_page(kto, kfrom);
-       __flush_dcache_area(kto, PAGE_SIZE);
+       flush_dcache_page(page);
 }
 EXPORT_SYMBOL_GPL(__cpu_copy_user_page);
 
index 7963aa4b5d2869b70dfd9a2f3d0ef501a033480b..331c4ca6205c4e7211d4bc7bc4832891d26080cc 100644 (file)
@@ -40,7 +40,7 @@ static pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot,
 static struct gen_pool *atomic_pool;
 
 #define DEFAULT_DMA_COHERENT_POOL_SIZE  SZ_256K
-static size_t atomic_pool_size = DEFAULT_DMA_COHERENT_POOL_SIZE;
+static size_t atomic_pool_size __initdata = DEFAULT_DMA_COHERENT_POOL_SIZE;
 
 static int __init early_coherent_pool(char *p)
 {
@@ -896,7 +896,7 @@ static int __iommu_attach_notifier(struct notifier_block *nb,
        return 0;
 }
 
-static int register_iommu_dma_ops_notifier(struct bus_type *bus)
+static int __init register_iommu_dma_ops_notifier(struct bus_type *bus)
 {
        struct notifier_block *nb = kzalloc(sizeof(*nb), GFP_KERNEL);
        int ret;
index c26b804015e80c46e1380d0a1af7f8f439c55405..46649d6e6c5a5608caa84015d3ce4f09d3d47eee 100644 (file)
@@ -34,19 +34,24 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
                __flush_icache_all();
 }
 
+static void sync_icache_aliases(void *kaddr, unsigned long len)
+{
+       unsigned long addr = (unsigned long)kaddr;
+
+       if (icache_is_aliasing()) {
+               __clean_dcache_area_pou(kaddr, len);
+               __flush_icache_all();
+       } else {
+               flush_icache_range(addr, addr + len);
+       }
+}
+
 static void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
                                unsigned long uaddr, void *kaddr,
                                unsigned long len)
 {
-       if (vma->vm_flags & VM_EXEC) {
-               unsigned long addr = (unsigned long)kaddr;
-               if (icache_is_aliasing()) {
-                       __flush_dcache_area(kaddr, len);
-                       __flush_icache_all();
-               } else {
-                       flush_icache_range(addr, addr + len);
-               }
-       }
+       if (vma->vm_flags & VM_EXEC)
+               sync_icache_aliases(kaddr, len);
 }
 
 /*
@@ -74,13 +79,11 @@ void __sync_icache_dcache(pte_t pte, unsigned long addr)
        if (!page_mapping(page))
                return;
 
-       if (!test_and_set_bit(PG_dcache_clean, &page->flags)) {
-               __flush_dcache_area(page_address(page),
-                               PAGE_SIZE << compound_order(page));
+       if (!test_and_set_bit(PG_dcache_clean, &page->flags))
+               sync_icache_aliases(page_address(page),
+                                   PAGE_SIZE << compound_order(page));
+       else if (icache_is_aivivt())
                __flush_icache_all();
-       } else if (icache_is_aivivt()) {
-               __flush_icache_all();
-       }
 }
 
 /*
index 383b03ff38f850a0b0a000ee4e6450fd6649c7db..82d607c3614ed8454d19f2da5d44a6cc914ee0b3 100644 (file)
@@ -41,17 +41,289 @@ int pud_huge(pud_t pud)
 #endif
 }
 
+static int find_num_contig(struct mm_struct *mm, unsigned long addr,
+                          pte_t *ptep, pte_t pte, size_t *pgsize)
+{
+       pgd_t *pgd = pgd_offset(mm, addr);
+       pud_t *pud;
+       pmd_t *pmd;
+
+       *pgsize = PAGE_SIZE;
+       if (!pte_cont(pte))
+               return 1;
+       if (!pgd_present(*pgd)) {
+               VM_BUG_ON(!pgd_present(*pgd));
+               return 1;
+       }
+       pud = pud_offset(pgd, addr);
+       if (!pud_present(*pud)) {
+               VM_BUG_ON(!pud_present(*pud));
+               return 1;
+       }
+       pmd = pmd_offset(pud, addr);
+       if (!pmd_present(*pmd)) {
+               VM_BUG_ON(!pmd_present(*pmd));
+               return 1;
+       }
+       if ((pte_t *)pmd == ptep) {
+               *pgsize = PMD_SIZE;
+               return CONT_PMDS;
+       }
+       return CONT_PTES;
+}
+
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+                           pte_t *ptep, pte_t pte)
+{
+       size_t pgsize;
+       int i;
+       int ncontig = find_num_contig(mm, addr, ptep, pte, &pgsize);
+       unsigned long pfn;
+       pgprot_t hugeprot;
+
+       if (ncontig == 1) {
+               set_pte_at(mm, addr, ptep, pte);
+               return;
+       }
+
+       pfn = pte_pfn(pte);
+       hugeprot = __pgprot(pte_val(pfn_pte(pfn, __pgprot(0))) ^ pte_val(pte));
+       for (i = 0; i < ncontig; i++) {
+               pr_debug("%s: set pte %p to 0x%llx\n", __func__, ptep,
+                        pte_val(pfn_pte(pfn, hugeprot)));
+               set_pte_at(mm, addr, ptep, pfn_pte(pfn, hugeprot));
+               ptep++;
+               pfn += pgsize >> PAGE_SHIFT;
+               addr += pgsize;
+       }
+}
+
+pte_t *huge_pte_alloc(struct mm_struct *mm,
+                     unsigned long addr, unsigned long sz)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pte_t *pte = NULL;
+
+       pr_debug("%s: addr:0x%lx sz:0x%lx\n", __func__, addr, sz);
+       pgd = pgd_offset(mm, addr);
+       pud = pud_alloc(mm, pgd, addr);
+       if (!pud)
+               return NULL;
+
+       if (sz == PUD_SIZE) {
+               pte = (pte_t *)pud;
+       } else if (sz == (PAGE_SIZE * CONT_PTES)) {
+               pmd_t *pmd = pmd_alloc(mm, pud, addr);
+
+               WARN_ON(addr & (sz - 1));
+               /*
+                * Note that if this code were ever ported to the
+                * 32-bit arm platform then it will cause trouble in
+                * the case where CONFIG_HIGHPTE is set, since there
+                * will be no pte_unmap() to correspond with this
+                * pte_alloc_map().
+                */
+               pte = pte_alloc_map(mm, NULL, pmd, addr);
+       } else if (sz == PMD_SIZE) {
+               if (IS_ENABLED(CONFIG_ARCH_WANT_HUGE_PMD_SHARE) &&
+                   pud_none(*pud))
+                       pte = huge_pmd_share(mm, addr, pud);
+               else
+                       pte = (pte_t *)pmd_alloc(mm, pud, addr);
+       } else if (sz == (PMD_SIZE * CONT_PMDS)) {
+               pmd_t *pmd;
+
+               pmd = pmd_alloc(mm, pud, addr);
+               WARN_ON(addr & (sz - 1));
+               return (pte_t *)pmd;
+       }
+
+       pr_debug("%s: addr:0x%lx sz:0x%lx ret pte=%p/0x%llx\n", __func__, addr,
+              sz, pte, pte_val(*pte));
+       return pte;
+}
+
+pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd = NULL;
+       pte_t *pte = NULL;
+
+       pgd = pgd_offset(mm, addr);
+       pr_debug("%s: addr:0x%lx pgd:%p\n", __func__, addr, pgd);
+       if (!pgd_present(*pgd))
+               return NULL;
+       pud = pud_offset(pgd, addr);
+       if (!pud_present(*pud))
+               return NULL;
+
+       if (pud_huge(*pud))
+               return (pte_t *)pud;
+       pmd = pmd_offset(pud, addr);
+       if (!pmd_present(*pmd))
+               return NULL;
+
+       if (pte_cont(pmd_pte(*pmd))) {
+               pmd = pmd_offset(
+                       pud, (addr & CONT_PMD_MASK));
+               return (pte_t *)pmd;
+       }
+       if (pmd_huge(*pmd))
+               return (pte_t *)pmd;
+       pte = pte_offset_kernel(pmd, addr);
+       if (pte_present(*pte) && pte_cont(*pte)) {
+               pte = pte_offset_kernel(
+                       pmd, (addr & CONT_PTE_MASK));
+               return pte;
+       }
+       return NULL;
+}
+
+pte_t arch_make_huge_pte(pte_t entry, struct vm_area_struct *vma,
+                        struct page *page, int writable)
+{
+       size_t pagesize = huge_page_size(hstate_vma(vma));
+
+       if (pagesize == CONT_PTE_SIZE) {
+               entry = pte_mkcont(entry);
+       } else if (pagesize == CONT_PMD_SIZE) {
+               entry = pmd_pte(pmd_mkcont(pte_pmd(entry)));
+       } else if (pagesize != PUD_SIZE && pagesize != PMD_SIZE) {
+               pr_warn("%s: unrecognized huge page size 0x%lx\n",
+                       __func__, pagesize);
+       }
+       return entry;
+}
+
+pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
+                             unsigned long addr, pte_t *ptep)
+{
+       pte_t pte;
+
+       if (pte_cont(*ptep)) {
+               int ncontig, i;
+               size_t pgsize;
+               pte_t *cpte;
+               bool is_dirty = false;
+
+               cpte = huge_pte_offset(mm, addr);
+               ncontig = find_num_contig(mm, addr, cpte, *cpte, &pgsize);
+               /* save the 1st pte to return */
+               pte = ptep_get_and_clear(mm, addr, cpte);
+               for (i = 1; i < ncontig; ++i) {
+                       /*
+                        * If HW_AFDBM is enabled, then the HW could
+                        * turn on the dirty bit for any of the page
+                        * in the set, so check them all.
+                        */
+                       ++cpte;
+                       if (pte_dirty(ptep_get_and_clear(mm, addr, cpte)))
+                               is_dirty = true;
+               }
+               if (is_dirty)
+                       return pte_mkdirty(pte);
+               else
+                       return pte;
+       } else {
+               return ptep_get_and_clear(mm, addr, ptep);
+       }
+}
+
+int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+                              unsigned long addr, pte_t *ptep,
+                              pte_t pte, int dirty)
+{
+       pte_t *cpte;
+
+       if (pte_cont(pte)) {
+               int ncontig, i, changed = 0;
+               size_t pgsize = 0;
+               unsigned long pfn = pte_pfn(pte);
+               /* Select all bits except the pfn */
+               pgprot_t hugeprot =
+                       __pgprot(pte_val(pfn_pte(pfn, __pgprot(0))) ^
+                                pte_val(pte));
+
+               cpte = huge_pte_offset(vma->vm_mm, addr);
+               pfn = pte_pfn(*cpte);
+               ncontig = find_num_contig(vma->vm_mm, addr, cpte,
+                                         *cpte, &pgsize);
+               for (i = 0; i < ncontig; ++i, ++cpte) {
+                       changed = ptep_set_access_flags(vma, addr, cpte,
+                                                       pfn_pte(pfn,
+                                                               hugeprot),
+                                                       dirty);
+                       pfn += pgsize >> PAGE_SHIFT;
+               }
+               return changed;
+       } else {
+               return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
+       }
+}
+
+void huge_ptep_set_wrprotect(struct mm_struct *mm,
+                            unsigned long addr, pte_t *ptep)
+{
+       if (pte_cont(*ptep)) {
+               int ncontig, i;
+               pte_t *cpte;
+               size_t pgsize = 0;
+
+               cpte = huge_pte_offset(mm, addr);
+               ncontig = find_num_contig(mm, addr, cpte, *cpte, &pgsize);
+               for (i = 0; i < ncontig; ++i, ++cpte)
+                       ptep_set_wrprotect(mm, addr, cpte);
+       } else {
+               ptep_set_wrprotect(mm, addr, ptep);
+       }
+}
+
+void huge_ptep_clear_flush(struct vm_area_struct *vma,
+                          unsigned long addr, pte_t *ptep)
+{
+       if (pte_cont(*ptep)) {
+               int ncontig, i;
+               pte_t *cpte;
+               size_t pgsize = 0;
+
+               cpte = huge_pte_offset(vma->vm_mm, addr);
+               ncontig = find_num_contig(vma->vm_mm, addr, cpte,
+                                         *cpte, &pgsize);
+               for (i = 0; i < ncontig; ++i, ++cpte)
+                       ptep_clear_flush(vma, addr, cpte);
+       } else {
+               ptep_clear_flush(vma, addr, ptep);
+       }
+}
+
 static __init int setup_hugepagesz(char *opt)
 {
        unsigned long ps = memparse(opt, &opt);
+
        if (ps == PMD_SIZE) {
                hugetlb_add_hstate(PMD_SHIFT - PAGE_SHIFT);
        } else if (ps == PUD_SIZE) {
                hugetlb_add_hstate(PUD_SHIFT - PAGE_SHIFT);
+       } else if (ps == (PAGE_SIZE * CONT_PTES)) {
+               hugetlb_add_hstate(CONT_PTE_SHIFT);
+       } else if (ps == (PMD_SIZE * CONT_PMDS)) {
+               hugetlb_add_hstate((PMD_SHIFT + CONT_PMD_SHIFT) - PAGE_SHIFT);
        } else {
-               pr_err("hugepagesz: Unsupported page size %lu M\n", ps >> 20);
+               pr_err("hugepagesz: Unsupported page size %lu K\n", ps >> 10);
                return 0;
        }
        return 1;
 }
 __setup("hugepagesz=", setup_hugepagesz);
+
+#ifdef CONFIG_ARM64_64K_PAGES
+static __init int add_default_hugepagesz(void)
+{
+       if (size_to_hstate(CONT_PTES * PAGE_SIZE) == NULL)
+               hugetlb_add_hstate(CONT_PMD_SHIFT);
+       return 0;
+}
+arch_initcall(add_default_hugepagesz);
+#endif
index 17bf39ac83ba073109118817c3ab72346ae3824b..f3b061e67bfe0f4565d5df29322eeaef38a9bcc3 100644 (file)
@@ -71,7 +71,7 @@ early_param("initrd", early_initrd);
  * currently assumes that for memory starting above 4G, 32-bit devices will
  * use a DMA offset.
  */
-static phys_addr_t max_zone_dma_phys(void)
+static phys_addr_t __init max_zone_dma_phys(void)
 {
        phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32);
        return min(offset + (1ULL << 32), memblock_end_of_DRAM());
@@ -120,17 +120,17 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
 #ifdef CONFIG_HAVE_ARCH_PFN_VALID
 int pfn_valid(unsigned long pfn)
 {
-       return memblock_is_memory(pfn << PAGE_SHIFT);
+       return memblock_is_map_memory(pfn << PAGE_SHIFT);
 }
 EXPORT_SYMBOL(pfn_valid);
 #endif
 
 #ifndef CONFIG_SPARSEMEM
-static void arm64_memory_present(void)
+static void __init arm64_memory_present(void)
 {
 }
 #else
-static void arm64_memory_present(void)
+static void __init arm64_memory_present(void)
 {
        struct memblock_region *reg;
 
@@ -360,7 +360,6 @@ void free_initmem(void)
 {
        fixup_init();
        free_initmem_default(0);
-       free_alternatives_memory();
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
index 873e363048c6c661eda620bbd4f826ba568c5ba7..58faeaa7fbdc6c73a73319e15c18bbd2a0948f06 100644 (file)
@@ -251,6 +251,14 @@ static void  __create_mapping(struct mm_struct *mm, pgd_t *pgd,
 {
        unsigned long addr, length, end, next;
 
+       /*
+        * If the virtual and physical address don't have the same offset
+        * within a page, we cannot map the region as the caller expects.
+        */
+       if (WARN_ON((phys ^ virt) & ~PAGE_MASK))
+               return;
+
+       phys &= PAGE_MASK;
        addr = virt & PAGE_MASK;
        length = PAGE_ALIGN(size + (virt & ~PAGE_MASK));
 
@@ -280,7 +288,7 @@ static void __init create_mapping(phys_addr_t phys, unsigned long virt,
                        &phys, virt);
                return;
        }
-       __create_mapping(&init_mm, pgd_offset_k(virt & PAGE_MASK), phys, virt,
+       __create_mapping(&init_mm, pgd_offset_k(virt), phys, virt,
                         size, prot, early_alloc);
 }
 
@@ -301,7 +309,7 @@ static void create_mapping_late(phys_addr_t phys, unsigned long virt,
                return;
        }
 
-       return __create_mapping(&init_mm, pgd_offset_k(virt & PAGE_MASK),
+       return __create_mapping(&init_mm, pgd_offset_k(virt),
                                phys, virt, size, prot, late_alloc);
 }
 
@@ -372,6 +380,8 @@ static void __init map_mem(void)
 
                if (start >= end)
                        break;
+               if (memblock_is_nomap(reg))
+                       continue;
 
                if (ARM64_SWAPPER_USES_SECTION_MAPS) {
                        /*
@@ -456,6 +466,9 @@ void __init paging_init(void)
 
        empty_zero_page = virt_to_page(zero_page);
 
+       /* Ensure the zero page is visible to the page table walker */
+       dsb(ishst);
+
        /*
         * TTBR0 is only used for the identity mapping at this stage. Make it
         * point to zero page to avoid speculatively fetching new entries.
index cb3ba1b812e74dcd1acbc167756d60da331d105f..ae11d4e03d0e68d7f0fe621f1c9d313fcab09127 100644 (file)
@@ -46,14 +46,14 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd)
                kmem_cache_free(pgd_cache, pgd);
 }
 
-static int __init pgd_cache_init(void)
+void __init pgd_cache_init(void)
 {
+       if (PGD_SIZE == PAGE_SIZE)
+               return;
+
        /*
         * Naturally aligned pgds required by the architecture.
         */
-       if (PGD_SIZE != PAGE_SIZE)
-               pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_SIZE,
-                                             SLAB_PANIC, NULL);
-       return 0;
+       pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_SIZE,
+                                     SLAB_PANIC, NULL);
 }
-core_initcall(pgd_cache_init);
index 4c4d93c4bf65b154fd0df25c4b8165593ff044be..146bd99a7532bcc6f53ad509a839561640eeaf3e 100644 (file)
        bfi     \valreg, \tmpreg, #TCR_T0SZ_OFFSET, #TCR_TxSZ_WIDTH
 #endif
        .endm
+
+/*
+ * Macro to perform a data cache maintenance for the interval
+ * [kaddr, kaddr + size)
+ *
+ *     op:             operation passed to dc instruction
+ *     domain:         domain used in dsb instruciton
+ *     kaddr:          starting virtual address of the region
+ *     size:           size of the region
+ *     Corrupts:       kaddr, size, tmp1, tmp2
+ */
+       .macro dcache_by_line_op op, domain, kaddr, size, tmp1, tmp2
+       dcache_line_size \tmp1, \tmp2
+       add     \size, \kaddr, \size
+       sub     \tmp2, \tmp1, #1
+       bic     \kaddr, \kaddr, \tmp2
+9998:  dc      \op, \kaddr
+       add     \kaddr, \kaddr, \tmp1
+       cmp     \kaddr, \size
+       b.lo    9998b
+       dsb     \domain
+       .endm
index cacecc4ad3e5bafc07ed0f6de5b2eda8da84a00c..a3d867e723b4f0c5c23283c89264d4a2f7f51561 100644 (file)
@@ -117,6 +117,7 @@ ENTRY(cpu_do_resume)
         */
        ubfx    x11, x11, #1, #1
        msr     oslar_el1, x11
+       msr     pmuserenr_el0, xzr              // Disable PMU access from EL0
        mov     x0, x12
        dsb     nsh             // Make sure local tlb invalidation completed
        isb
@@ -139,8 +140,6 @@ ENTRY(cpu_do_switch_mm)
        ret
 ENDPROC(cpu_do_switch_mm)
 
-       .section ".text.init", #alloc, #execinstr
-
 /*
  *     __cpu_setup
  *
@@ -155,6 +154,7 @@ ENTRY(__cpu_setup)
        msr     cpacr_el1, x0                   // Enable FP/ASIMD
        mov     x0, #1 << 12                    // Reset mdscr_el1 and disable
        msr     mdscr_el1, x0                   // access to the DCC from EL0
+       msr     pmuserenr_el0, xzr              // Disable PMU access from EL0
        /*
         * Memory region attributes for LPAE:
         *
index 8bbe9401f4f011d3239adcd2d6f5251d5fe37ff0..70df80e8da2c422258781b4e6f4e20328bf5c514 100644 (file)
@@ -80,6 +80,7 @@ HYPERCALL2(memory_op);
 HYPERCALL2(physdev_op);
 HYPERCALL3(vcpu_op);
 HYPERCALL1(tmem_op);
+HYPERCALL1(platform_op_raw);
 HYPERCALL2(multicall);
 
 ENTRY(privcmd_call)
index c05868cc61c1aacc290ecfacfebb048cf032bc6f..253928854299f2c5c1f9c18e269c78869f4c626e 100644 (file)
@@ -128,6 +128,5 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
 #endif /* !CONFIG_SMP */
 
 #define xchg(ptr, x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
-#define tas(ptr) ((void)xchg((ptr), 1))
 
 #endif /* __ARCH_BLACKFIN_CMPXCHG__ */
index 2de71e8c104b1e2233c7eba47c42ad28d2ab60c9..f35525b5581991689f0e4b178c5672a2dadbe060 100644 (file)
@@ -443,7 +443,7 @@ static const struct ppi_info ppi_info = {
 };
 
 #if IS_ENABLED(CONFIG_VIDEO_ADV7183)
-#include <media/adv7183.h>
+#include <media/i2c/adv7183.h>
 static struct v4l2_input adv7183_inputs[] = {
        {
                .index = 0,
index 2c61fc0c98f94eb9d1692f6d1508086f8e092318..c7928d8ebb828bccea1a133aef8feb129a38775a 100644 (file)
@@ -933,7 +933,7 @@ static struct bfin_capture_config bfin_capture_data = {
 #endif
 
 #if IS_ENABLED(CONFIG_VIDEO_ADV7842)
-#include <media/adv7842.h>
+#include <media/i2c/adv7842.h>
 
 static struct v4l2_input adv7842_inputs[] = {
        {
@@ -1084,7 +1084,7 @@ static const struct ppi_info ppi_info = {
 };
 
 #if IS_ENABLED(CONFIG_VIDEO_ADV7511)
-#include <media/adv7511.h>
+#include <media/i2c/adv7511.h>
 
 static struct v4l2_output adv7511_outputs[] = {
        {
@@ -1125,7 +1125,7 @@ static struct bfin_display_config bfin_display_data = {
 #endif
 
 #if IS_ENABLED(CONFIG_VIDEO_ADV7343)
-#include <media/adv7343.h>
+#include <media/i2c/adv7343.h>
 
 static struct v4l2_output adv7343_outputs[] = {
        {
index 945544ec603ee12408928c0abd4db19cfbc784d9..64465e7e224593a2e808f77f0fb6c735219d12a4 100644 (file)
@@ -4,6 +4,7 @@ generic-y += auxvec.h
 generic-y += barrier.h
 generic-y += bitsperlong.h
 generic-y += bugs.h
+generic-y += clkdev.h
 generic-y += cputime.h
 generic-y += current.h
 generic-y += device.h
diff --git a/arch/c6x/include/asm/clkdev.h b/arch/c6x/include/asm/clkdev.h
deleted file mode 100644 (file)
index 76a070b..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef _ASM_CLKDEV_H
-#define _ASM_CLKDEV_H
-
-#include <linux/slab.h>
-
-struct clk;
-
-static inline int __clk_get(struct clk *clk)
-{
-       return 1;
-}
-
-static inline void __clk_put(struct clk *clk)
-{
-}
-
-static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size)
-{
-       return kzalloc(size, GFP_KERNEL);
-}
-
-#endif /* _ASM_CLKDEV_H */
index b27c8cefb8c3e92fb6a6e9b3055a6394bfe22f79..93d0a5a047a282b67ea2d62f984ce2707db46b13 100644 (file)
@@ -47,8 +47,6 @@ static inline unsigned int __xchg(unsigned int x, volatile void *ptr, int size)
 #define xchg(ptr, x) \
        ((__typeof__(*(ptr)))__xchg((unsigned int)(x), (void *) (ptr), \
                                    sizeof(*(ptr))))
-#define tas(ptr)    xchg((ptr), 1)
-
 
 #include <asm-generic/cmpxchg-local.h>
 
index 5b04dd0aecab8871d815eb9a59b1a6c35f2a60f6..a899765102ea47ac47c0c64f74df12c73d6b672a 100644 (file)
@@ -69,8 +69,6 @@ extern uint32_t __xchg_32(uint32_t i, volatile void *v);
 
 #endif
 
-#define tas(ptr) (xchg((ptr), 1))
-
 /*****************************************************************************/
 /*
  * compare and conditionally exchange value with memory
index dd3ac75776ad982973d0ae2f5f2ccd0e58a53c7e..2e20333cbce90b947f13f5a11182bedef82a4d3c 100644 (file)
@@ -17,6 +17,7 @@ config H8300
        select HAVE_MEMBLOCK
        select HAVE_DMA_ATTRS
        select CLKSRC_OF
+       select H8300_TMR8
 
 config RWSEM_GENERIC_SPINLOCK
        def_bool y
index bb837cded268446bbd67d7610daf374807d502bb..f0e14f3a800d8d4eb65f2ac970543cc66375bcfe 100644 (file)
@@ -3,40 +3,45 @@
 
 #ifdef __KERNEL__
 
-#include <asm-generic/io.h>
-
 /* H8/300 internal I/O functions */
-static inline unsigned char ctrl_inb(unsigned long addr)
+
+#define __raw_readb __raw_readb
+static inline u8 __raw_readb(const volatile void __iomem *addr)
 {
-       return *(volatile unsigned char *)addr;
+       return *(volatile u8 *)addr;
 }
 
-static inline unsigned short ctrl_inw(unsigned long addr)
+#define __raw_readw __raw_readw
+static inline u16 __raw_readw(const volatile void __iomem *addr)
 {
-       return *(volatile unsigned short *)addr;
+       return *(volatile u16 *)addr;
 }
 
-static inline unsigned long ctrl_inl(unsigned long addr)
+#define __raw_readl __raw_readl
+static inline u32  __raw_readl(const volatile void __iomem *addr)
 {
-       return *(volatile unsigned long *)addr;
+       return *(volatile u32 *)addr;
 }
 
-static inline void ctrl_outb(unsigned char b, unsigned long addr)
+#define __raw_writeb __raw_writeb
+static inline void __raw_writeb(u8 b, const volatile void __iomem *addr)
 {
-       *(volatile unsigned char *)addr = b;
+       *(volatile u8 *)addr = b;
 }
 
-static inline void ctrl_outw(unsigned short b, unsigned long addr)
+#define __raw_writew __raw_writew
+static inline void __raw_writew(u16 b, const volatile void __iomem *addr)
 {
-       *(volatile unsigned short *)addr = b;
+       *(volatile u16 *)addr = b;
 }
 
-static inline void ctrl_outl(unsigned long b, unsigned long addr)
+#define __raw_writel __raw_writel
+static inline void __raw_writel(u32 b, const volatile void __iomem *addr)
 {
-       *(volatile unsigned long *)addr = b;
+       *(volatile u32 *)addr = b;
 }
 
-static inline void ctrl_bclr(int b, unsigned char *addr)
+static inline void ctrl_bclr(int b, void __iomem *addr)
 {
        if (__builtin_constant_p(b))
                __asm__("bclr %1,%0" : "+WU"(*addr): "i"(b));
@@ -44,7 +49,7 @@ static inline void ctrl_bclr(int b, unsigned char *addr)
                __asm__("bclr %w1,%0" : "+WU"(*addr): "r"(b));
 }
 
-static inline void ctrl_bset(int b, unsigned char *addr)
+static inline void ctrl_bset(int b, void __iomem *addr)
 {
        if (__builtin_constant_p(b))
                __asm__("bset %1,%0" : "+WU"(*addr): "i"(b));
@@ -52,6 +57,8 @@ static inline void ctrl_bset(int b, unsigned char *addr)
                __asm__("bset %w1,%0" : "+WU"(*addr): "r"(b));
 }
 
+#include <asm-generic/io.h>
+
 #endif /* __KERNEL__ */
 
 #endif /* _H8300_IO_H */
index c772abe6d19ce0d4ff06f12c8d5fb004905c26c5..e4985dfa91dc853e1c227759808814b2e5e2ea97 100644 (file)
@@ -207,14 +207,14 @@ device_initcall(device_probe);
 #define get_wait(base, addr) ({                \
        int baddr;                      \
        baddr = ((addr) / 0x200000 * 2);                             \
-       w *= (ctrl_inw((unsigned long)(base) + 2) & (3 << baddr)) + 1;  \
+       w *= (readw((base) + 2) & (3 << baddr)) + 1;                 \
        })
 #endif
 #if defined(CONFIG_CPU_H8S)
 #define get_wait(base, addr) ({                \
        int baddr;                      \
        baddr = ((addr) / 0x200000 * 16);                            \
-       w *= (ctrl_inl((unsigned long)(base) + 2) & (7 << baddr)) + 1;  \
+       w *= (readl((base) + 2) & (7 << baddr)) + 1;    \
        })
 #endif
 
@@ -228,8 +228,8 @@ static __init int access_timing(void)
 
        bsc = of_find_compatible_node(NULL, NULL, "renesas,h8300-bsc");
        base = of_iomap(bsc, 0);
-       w = (ctrl_inb((unsigned long)base + 0) & bit)?2:1;
-       if (ctrl_inb((unsigned long)base + 1) & bit)
+       w = (readb(base + 0) & bit)?2:1;
+       if (readb(base + 1) & bit)
                w *= get_wait(base, addr);
        else
                w *= 2;
index df896a1c41d348e60641bb0f89aece2d5ba95f93..209c4b817c958e25eea0298afe121fc225f1e9e3 100644 (file)
@@ -77,7 +77,7 @@ do {                                                                  \
        ___p1;                                                          \
 })
 
-#define smp_store_mb(var, value)       do { WRITE_ONCE(var, value); mb(); } while (0)
+#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); smp_mb(); } while (0)
 
 /*
  * The group barrier in front of the rsm & ssm are necessary to ensure
index 0ec484d2dcbcad7c175b2510871b10c63644108a..b9295793a5e24b3f7aa6c4df05b8228977d9c35c 100644 (file)
@@ -6,8 +6,6 @@
  *     David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
-#define PERCPU_ENOUGH_ROOM PERCPU_PAGE_SIZE
-
 #ifdef __ASSEMBLY__
 # define THIS_CPU(var) (var)  /* use this to mark accesses to per-CPU variables... */
 #else /* !__ASSEMBLY__ */
index fd104bd221ced1dff2c9485bdcb1be520171df7f..860e440611c98f7e0c2a9882c18dc73cf166f35e 100644 (file)
@@ -3,6 +3,7 @@ generic-y += clkdev.h
 generic-y += cputime.h
 generic-y += exec.h
 generic-y += irq_work.h
+generic-y += kvm_para.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
 generic-y += module.h
index 61b8931bc19250df3af7b42b4e667749332b6be1..4b0f5e001d4d5ab2a545e62dcc276b9815df5821 100644 (file)
@@ -168,13 +168,21 @@ static inline void _writel(unsigned long l, unsigned long addr)
 #define writew_relaxed writew
 #define writel_relaxed writel
 
-#define ioread8 read
+#define ioread8 readb
 #define ioread16 readw
 #define ioread32 readl
 #define iowrite8 writeb
 #define iowrite16 writew
 #define iowrite32 writel
 
+#define ioread8_rep(p, dst, count) insb((unsigned long)(p), (dst), (count))
+#define ioread16_rep(p, dst, count) insw((unsigned long)(p), (dst), (count))
+#define ioread32_rep(p, dst, count) insl((unsigned long)(p), (dst), (count))
+
+#define iowrite8_rep(p, src, count) outsb((unsigned long)(p), (src), (count))
+#define iowrite16_rep(p, src, count) outsw((unsigned long)(p), (src), (count))
+#define iowrite32_rep(p, src, count) outsl((unsigned long)(p), (src), (count))
+
 #define ioread16be(addr)       be16_to_cpu(readw(addr))
 #define ioread32be(addr)       be32_to_cpu(readl(addr))
 #define iowrite16be(v, addr)   writew(cpu_to_be16(v), (addr))
index 192b00f098f4367c74bdbcec5717077d22d32589..cbd5991fd49aa875fb189931d9afc27f720b0c71 100644 (file)
@@ -858,7 +858,7 @@ static struct platform_device *atari_netusbee_devices[] __initdata = {
 };
 #endif /* CONFIG_ATARI_ETHERNEC */
 
-#ifdef CONFIG_ATARI_SCSI
+#if IS_ENABLED(CONFIG_ATARI_SCSI)
 static const struct resource atari_scsi_st_rsrc[] __initconst = {
        {
                .flags = IORESOURCE_IRQ,
@@ -910,7 +910,7 @@ int __init atari_platform_init(void)
        }
 #endif
 
-#ifdef CONFIG_ATARI_SCSI
+#if IS_ENABLED(CONFIG_ATARI_SCSI)
        if (ATARIHW_PRESENT(ST_SCSI))
                platform_device_register_simple("atari_scsi", -1,
                        atari_scsi_st_rsrc, ARRAY_SIZE(atari_scsi_st_rsrc));
index e7e428681ec56b3c32866264cc95eba1df4ac099..37a83e27c7a6c8ea15c6c885ae71ca59c7c7ad8d 100644 (file)
@@ -121,7 +121,7 @@ static int mcfgpio_direction_input(struct gpio_chip *chip, unsigned offset)
 
 static int mcfgpio_get_value(struct gpio_chip *chip, unsigned offset)
 {
-       return __mcfgpio_get_value(offset);
+       return !!__mcfgpio_get_value(offset);
 }
 
 static int mcfgpio_direction_output(struct gpio_chip *chip, unsigned offset,
index 5b4ec541ba7c99936d8f5072dc5716a778751235..fc96e814188e57aa9dee8ed516c62200c543ad56 100644 (file)
@@ -276,6 +276,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
 # CONFIG_WIRELESS is not set
 # CONFIG_UEVENT_HELPER is not set
 CONFIG_DEVTMPFS=y
@@ -532,11 +533,13 @@ CONFIG_NLS_MAC_INUIT=m
 CONFIG_NLS_MAC_ROMANIAN=m
 CONFIG_NLS_MAC_TURKISH=m
 CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
 CONFIG_TEST_STRING_HELPERS=m
 CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
 CONFIG_TEST_RHASHTABLE=m
 CONFIG_TEST_LKM=m
 CONFIG_TEST_USER_COPY=m
@@ -559,6 +562,7 @@ CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index 6e5198e2c124f89b86d6b5267280f5596448cc0a..05c904f08d9d496fb7455df0d1506fb8d8c9bc23 100644 (file)
@@ -274,6 +274,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
 # CONFIG_WIRELESS is not set
 # CONFIG_UEVENT_HELPER is not set
 CONFIG_DEVTMPFS=y
@@ -372,6 +373,7 @@ CONFIG_INPUT_EVDEV=m
 # CONFIG_MOUSE_PS2 is not set
 CONFIG_MOUSE_SERIAL=m
 CONFIG_SERIO=m
+CONFIG_USERIO=m
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_DEVKMEM is not set
 # CONFIG_HW_RANDOM is not set
@@ -490,11 +492,13 @@ CONFIG_NLS_MAC_INUIT=m
 CONFIG_NLS_MAC_ROMANIAN=m
 CONFIG_NLS_MAC_TURKISH=m
 CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
 CONFIG_TEST_STRING_HELPERS=m
 CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
 CONFIG_TEST_RHASHTABLE=m
 CONFIG_TEST_LKM=m
 CONFIG_TEST_USER_COPY=m
@@ -517,6 +521,7 @@ CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index f75600b0ca23f78ec028948babb81b5b2c02b3ed..d572b731c510fdb2dc60616ee1ff0ce7e10516ce 100644 (file)
@@ -274,6 +274,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
 # CONFIG_WIRELESS is not set
 # CONFIG_UEVENT_HELPER is not set
 CONFIG_DEVTMPFS=y
@@ -512,11 +513,13 @@ CONFIG_NLS_MAC_INUIT=m
 CONFIG_NLS_MAC_ROMANIAN=m
 CONFIG_NLS_MAC_TURKISH=m
 CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
 CONFIG_TEST_STRING_HELPERS=m
 CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
 CONFIG_TEST_RHASHTABLE=m
 CONFIG_TEST_LKM=m
 CONFIG_TEST_USER_COPY=m
@@ -539,6 +542,7 @@ CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index a42d91c389a6fbba1c2c8f27069acb53332dd56f..11a30c65ad44cb52347929d51f80301c8aca648b 100644 (file)
@@ -272,6 +272,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
 # CONFIG_WIRELESS is not set
 # CONFIG_UEVENT_HELPER is not set
 CONFIG_DEVTMPFS=y
@@ -483,11 +484,13 @@ CONFIG_NLS_MAC_INUIT=m
 CONFIG_NLS_MAC_ROMANIAN=m
 CONFIG_NLS_MAC_TURKISH=m
 CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
 CONFIG_TEST_STRING_HELPERS=m
 CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
 CONFIG_TEST_RHASHTABLE=m
 CONFIG_TEST_LKM=m
 CONFIG_TEST_USER_COPY=m
@@ -510,6 +513,7 @@ CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index 77f4a11083e9964050022f4ff22625b69b8672dd..6630a5154b9d797ebea93cdbe70886bc673f60cd 100644 (file)
@@ -274,6 +274,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
 # CONFIG_WIRELESS is not set
 # CONFIG_UEVENT_HELPER is not set
 CONFIG_DEVTMPFS=y
@@ -375,6 +376,7 @@ CONFIG_MOUSE_SERIAL=m
 CONFIG_INPUT_MISC=y
 CONFIG_HP_SDC_RTC=m
 CONFIG_SERIO_SERPORT=m
+CONFIG_USERIO=m
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_DEVKMEM is not set
 # CONFIG_HW_RANDOM is not set
@@ -492,11 +494,13 @@ CONFIG_NLS_MAC_INUIT=m
 CONFIG_NLS_MAC_ROMANIAN=m
 CONFIG_NLS_MAC_TURKISH=m
 CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
 CONFIG_TEST_STRING_HELPERS=m
 CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
 CONFIG_TEST_RHASHTABLE=m
 CONFIG_TEST_LKM=m
 CONFIG_TEST_USER_COPY=m
@@ -519,6 +523,7 @@ CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index 5a329f77329b155ed5a4dc0f06ca6973c82aae94..1d90b71d09038da90cfad0cab267d60dae0fd752 100644 (file)
@@ -276,6 +276,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
 # CONFIG_WIRELESS is not set
 # CONFIG_UEVENT_HELPER is not set
 CONFIG_DEVTMPFS=y
@@ -394,6 +395,7 @@ CONFIG_MOUSE_SERIAL=m
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_M68K_BEEP=m
 CONFIG_SERIO=m
+CONFIG_USERIO=m
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_DEVKMEM is not set
 CONFIG_SERIAL_PMACZILOG=y
@@ -514,11 +516,13 @@ CONFIG_NLS_MAC_INUIT=m
 CONFIG_NLS_MAC_ROMANIAN=m
 CONFIG_NLS_MAC_TURKISH=m
 CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
 CONFIG_TEST_STRING_HELPERS=m
 CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
 CONFIG_TEST_RHASHTABLE=m
 CONFIG_TEST_LKM=m
 CONFIG_TEST_USER_COPY=m
@@ -541,6 +545,7 @@ CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index 83c80d2030ec96aa4740615101422e1fca1884e5..1fd21c1ca87fd8da85ace8c64930cfeed4383370 100644 (file)
@@ -286,6 +286,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
 # CONFIG_WIRELESS is not set
 # CONFIG_UEVENT_HELPER is not set
 CONFIG_DEVTMPFS=y
@@ -449,6 +450,7 @@ CONFIG_INPUT_MISC=y
 CONFIG_INPUT_M68K_BEEP=m
 CONFIG_HP_SDC_RTC=m
 CONFIG_SERIO_Q40KBD=y
+CONFIG_USERIO=m
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_DEVKMEM is not set
 CONFIG_SERIAL_PMACZILOG=y
@@ -594,11 +596,13 @@ CONFIG_NLS_MAC_INUIT=m
 CONFIG_NLS_MAC_ROMANIAN=m
 CONFIG_NLS_MAC_TURKISH=m
 CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
 CONFIG_TEST_STRING_HELPERS=m
 CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
 CONFIG_TEST_RHASHTABLE=m
 CONFIG_TEST_LKM=m
 CONFIG_TEST_USER_COPY=m
@@ -621,6 +625,7 @@ CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index 6cb42c3bf5a280d1a537d515396a463049d4a250..74e10f79d7b1f9475574d422451314b7bcc1af64 100644 (file)
@@ -271,6 +271,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
 # CONFIG_WIRELESS is not set
 # CONFIG_UEVENT_HELPER is not set
 CONFIG_DEVTMPFS=y
@@ -483,11 +484,13 @@ CONFIG_NLS_MAC_INUIT=m
 CONFIG_NLS_MAC_ROMANIAN=m
 CONFIG_NLS_MAC_TURKISH=m
 CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
 CONFIG_TEST_STRING_HELPERS=m
 CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
 CONFIG_TEST_RHASHTABLE=m
 CONFIG_TEST_LKM=m
 CONFIG_TEST_USER_COPY=m
@@ -510,6 +513,7 @@ CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index c7508c30330c43ee32c0f75d7c7c8112f16cdc35..7034e716f166be8f869f872b12f9cbf960054029 100644 (file)
@@ -272,6 +272,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
 # CONFIG_WIRELESS is not set
 # CONFIG_UEVENT_HELPER is not set
 CONFIG_DEVTMPFS=y
@@ -483,11 +484,13 @@ CONFIG_NLS_MAC_INUIT=m
 CONFIG_NLS_MAC_ROMANIAN=m
 CONFIG_NLS_MAC_TURKISH=m
 CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
 CONFIG_TEST_STRING_HELPERS=m
 CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
 CONFIG_TEST_RHASHTABLE=m
 CONFIG_TEST_LKM=m
 CONFIG_TEST_USER_COPY=m
@@ -510,6 +513,7 @@ CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index 64b71664a3036aa2827984f34005fc2cd044de44..f7deb5f702a6484dda646577f48ade90b902bf18 100644 (file)
@@ -272,6 +272,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
 # CONFIG_WIRELESS is not set
 # CONFIG_UEVENT_HELPER is not set
 CONFIG_DEVTMPFS=y
@@ -385,6 +386,7 @@ CONFIG_MOUSE_SERIAL=m
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_M68K_BEEP=m
 CONFIG_SERIO_Q40KBD=y
+CONFIG_USERIO=m
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_DEVKMEM is not set
 CONFIG_PRINTER=m
@@ -505,11 +507,13 @@ CONFIG_NLS_MAC_INUIT=m
 CONFIG_NLS_MAC_ROMANIAN=m
 CONFIG_NLS_MAC_TURKISH=m
 CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
 CONFIG_TEST_STRING_HELPERS=m
 CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
 CONFIG_TEST_RHASHTABLE=m
 CONFIG_TEST_LKM=m
 CONFIG_TEST_USER_COPY=m
@@ -532,6 +536,7 @@ CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index 9a4cab78a2ea82ce3043be9c8a5582328774f21b..0ce79eb0d80503140d928c3c6c77061a2ead34d9 100644 (file)
@@ -269,6 +269,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
 # CONFIG_WIRELESS is not set
 # CONFIG_UEVENT_HELPER is not set
 CONFIG_DEVTMPFS=y
@@ -369,6 +370,7 @@ CONFIG_INPUT_EVDEV=m
 CONFIG_KEYBOARD_SUNKBD=y
 # CONFIG_MOUSE_PS2 is not set
 CONFIG_MOUSE_SERIAL=m
+CONFIG_USERIO=m
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_DEVKMEM is not set
 # CONFIG_HW_RANDOM is not set
@@ -484,11 +486,13 @@ CONFIG_NLS_MAC_INUIT=m
 CONFIG_NLS_MAC_ROMANIAN=m
 CONFIG_NLS_MAC_TURKISH=m
 CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
 CONFIG_TEST_STRING_HELPERS=m
 CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
 CONFIG_TEST_RHASHTABLE=m
 CONFIG_TEST_LKM=m
 CONFIG_TEST_USER_COPY=m
@@ -510,6 +514,7 @@ CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index 1a2eaac13dbdd540f223aea5c67c660723e3cf54..4cb787e4991fcfd02646b1144999419b40454f83 100644 (file)
@@ -269,6 +269,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
 # CONFIG_WIRELESS is not set
 # CONFIG_UEVENT_HELPER is not set
 CONFIG_DEVTMPFS=y
@@ -369,6 +370,7 @@ CONFIG_INPUT_EVDEV=m
 CONFIG_KEYBOARD_SUNKBD=y
 # CONFIG_MOUSE_PS2 is not set
 CONFIG_MOUSE_SERIAL=m
+CONFIG_USERIO=m
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_DEVKMEM is not set
 # CONFIG_HW_RANDOM is not set
@@ -484,11 +486,13 @@ CONFIG_NLS_MAC_INUIT=m
 CONFIG_NLS_MAC_ROMANIAN=m
 CONFIG_NLS_MAC_TURKISH=m
 CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
 CONFIG_TEST_STRING_HELPERS=m
 CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
 CONFIG_TEST_RHASHTABLE=m
 CONFIG_TEST_LKM=m
 CONFIG_TEST_USER_COPY=m
@@ -511,6 +515,7 @@ CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index e5c0d71d154324bf39fcb2e038de4d78bd8526de..923305117a69ad5b947129da664aa97a96daf7c5 100644 (file)
 #ifndef __ASSEMBLY__
 
 extern volatile __u8 *psc;
-extern int psc_present;
 
 extern void psc_register_interrupts(void);
 extern void psc_irq_enable(int);
index 38b024a0b0451ba7a934ea5d4f5563411d406b6d..430d4d54c88383a9620e053c356a71b8cde92e63 100644 (file)
@@ -48,6 +48,9 @@ extern unsigned long _ramend;
 #include <asm/page_no.h>
 #endif
 
+#define __phys_to_pfn(paddr)   ((unsigned long)((paddr) >> PAGE_SHIFT))
+#define __pfn_to_phys(pfn)     PFN_PHYS(pfn)
+
 #define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
                                 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
index 5c1a6b2ff0afc131e7ef49f048c94a1e7f9512e8..9f98c08719010e272aa2f6f2464bc5b53f3a1427 100644 (file)
@@ -174,7 +174,7 @@ void __init mac_init_IRQ(void)
                oss_register_interrupts();
        else
                via_register_interrupts();
-       if (psc_present)
+       if (psc)
                psc_register_interrupts();
        if (baboon_present)
                baboon_register_interrupts();
@@ -212,7 +212,7 @@ void mac_irq_enable(struct irq_data *data)
        case 4:
        case 5:
        case 6:
-               if (psc_present)
+               if (psc)
                        psc_irq_enable(irq);
                else if (oss_present)
                        oss_irq_enable(irq);
@@ -242,7 +242,7 @@ void mac_irq_disable(struct irq_data *data)
        case 4:
        case 5:
        case 6:
-               if (psc_present)
+               if (psc)
                        psc_irq_disable(irq);
                else if (oss_present)
                        oss_irq_disable(irq);
index 2290c0cae48beb8ab9fb22a74327bf94306c9df0..cb2b1a3a2b62d97fb12aa14993749cab1de85544 100644 (file)
@@ -27,7 +27,6 @@
 
 #define DEBUG_PSC
 
-int psc_present;
 volatile __u8 *psc;
 EXPORT_SYMBOL_GPL(psc);
 
@@ -39,7 +38,9 @@ static void psc_debug_dump(void)
 {
        int     i;
 
-       if (!psc_present) return;
+       if (!psc)
+               return;
+
        for (i = 0x30 ; i < 0x70 ; i += 0x10) {
                printk("PSC #%d:  IFR = 0x%02X IER = 0x%02X\n",
                        i >> 4,
@@ -81,7 +82,6 @@ void __init psc_init(void)
         && macintosh_config->ident != MAC_MODEL_Q840)
        {
                psc = NULL;
-               psc_present = 0;
                return;
        }
 
@@ -91,7 +91,6 @@ void __init psc_init(void)
         */
 
        psc = (void *) PSC_BASE;
-       psc_present = 1;
 
        printk("PSC detected at %p\n", psc);
 
index 2a5f43a68ae3d73d22dd822a4da4996208543e7c..71884bf01d7200e6f77dc3d27731c1b6e97b9081 100644 (file)
@@ -171,7 +171,7 @@ static void __init sun3_sched_init(irq_handler_t timer_routine)
         intersil_clear();
 }
 
-#ifdef CONFIG_SUN3_SCSI
+#if IS_ENABLED(CONFIG_SUN3_SCSI)
 
 static const struct resource sun3_scsi_vme_rsrc[] __initconst = {
        {
index 41891c1e58bda2554595d76a7b2c0261a11e2990..d52ce3d07f16dee81c5982212fe69f8cddc015d0 100644 (file)
@@ -73,7 +73,6 @@
                timer: timer@10000040 {
                        compatible = "syscon";
                        reg = <0x10000040 0x2c>;
-                       little-endian;
                };
 
                reboot {
index 1a7efa883c5e3fd2e046b554485270036193b382..4fc7ecee273c105027ff20cea02f2bd5cf86c9fe 100644 (file)
@@ -98,7 +98,6 @@
                sun_top_ctrl: syscon@404000 {
                        compatible = "brcm,bcm7125-sun-top-ctrl", "syscon";
                        reg = <0x404000 0x60c>;
-                       little-endian;
                };
 
                reboot {
index d4bf52cfcf170ee8ac84daa874495e0a6420e542..a3039bb53477d40a426fec1d1318f3156ede8be3 100644 (file)
                sun_top_ctrl: syscon@404000 {
                        compatible = "brcm,bcm7346-sun-top-ctrl", "syscon";
                        reg = <0x404000 0x51c>;
-                       little-endian;
                };
 
                reboot {
index 8e2501694d03fbd93827aeda79ef22f7cfd5d094..4274ff41ec2122ac0bfd52d814aee8432c26553e 100644 (file)
                sun_top_ctrl: syscon@404000 {
                        compatible = "brcm,bcm7358-sun-top-ctrl", "syscon";
                        reg = <0x404000 0x51c>;
-                       little-endian;
                };
 
                reboot {
index 7e5f76040fb898b19a4bbc301c8a20f3b9368aa4..0dcc9163c27bdd0022e5b66f3ffd65da7fd6ce31 100644 (file)
                sun_top_ctrl: syscon@404000 {
                        compatible = "brcm,bcm7360-sun-top-ctrl", "syscon";
                        reg = <0x404000 0x51c>;
-                       little-endian;
                };
 
                reboot {
index c739ea77acb0dfe17363ec52cf390cace407e54c..2f3f9fc2c478df36ef57c5990dd81f6757240e3a 100644 (file)
                sun_top_ctrl: syscon@404000 {
                        compatible = "brcm,bcm7362-sun-top-ctrl", "syscon";
                        reg = <0x404000 0x51c>;
-                       little-endian;
                };
 
                reboot {
index 5f55d0a50a28622614ec6142eb0ff19746dfaade..bee221b3b56857c8d84dac3e2fa9bfe8b3c54a85 100644 (file)
@@ -99,7 +99,6 @@
                sun_top_ctrl: syscon@404000 {
                        compatible = "brcm,bcm7420-sun-top-ctrl", "syscon";
                        reg = <0x404000 0x60c>;
-                       little-endian;
                };
 
                reboot {
index e24d41ab4e30f9163605180d78605fc02a477db6..571f30f52e3ff5780ec4fd72e18e72737e51537d 100644 (file)
                sun_top_ctrl: syscon@404000 {
                        compatible = "brcm,bcm7425-sun-top-ctrl", "syscon";
                        reg = <0x404000 0x51c>;
-                       little-endian;
                };
 
                reboot {
index 8b9432cc062bc7e89898f2f1f2213926193389f8..614ee211f71a89356dd1eb814a38ec3071885747 100644 (file)
                sun_top_ctrl: syscon@404000 {
                        compatible = "brcm,bcm7425-sun-top-ctrl", "syscon";
                        reg = <0x404000 0x51c>;
-                       little-endian;
                };
 
                reboot {
index 77cb27309db27f781ec9862037074d39e928401a..1a8c96035716a2dfb76f724b6190b33954bee8c8 100644 (file)
@@ -521,19 +521,6 @@ static inline u16 align_sp(unsigned int num)
        return num;
 }
 
-static bool is_load_to_a(u16 inst)
-{
-       switch (inst) {
-       case BPF_LD | BPF_W | BPF_LEN:
-       case BPF_LD | BPF_W | BPF_ABS:
-       case BPF_LD | BPF_H | BPF_ABS:
-       case BPF_LD | BPF_B | BPF_ABS:
-               return true;
-       default:
-               return false;
-       }
-}
-
 static void save_bpf_jit_regs(struct jit_ctx *ctx, unsigned offset)
 {
        int i = 0, real_off = 0;
@@ -614,7 +601,6 @@ static unsigned int get_stack_depth(struct jit_ctx *ctx)
 
 static void build_prologue(struct jit_ctx *ctx)
 {
-       u16 first_inst = ctx->skf->insns[0].code;
        int sp_off;
 
        /* Calculate the total offset for the stack pointer */
@@ -641,7 +627,7 @@ static void build_prologue(struct jit_ctx *ctx)
                emit_jit_reg_move(r_X, r_zero, ctx);
 
        /* Do not leak kernel data to userspace */
-       if ((first_inst != (BPF_RET | BPF_K)) && !(is_load_to_a(first_inst)))
+       if (bpf_needs_clear_a(&ctx->skf->insns[0]))
                emit_jit_reg_move(r_A, r_zero, ctx);
 }
 
index 018f8c7b94f2ac9f7db90646317dc07e7c9d3d48..ee3617c0c5e2eb9388d01c1ae6e92846f86bc2a1 100644 (file)
@@ -26,7 +26,7 @@ aflags-vdso := $(ccflags-vdso) \
 # the comments on that file.
 #
 ifndef CONFIG_CPU_MIPSR6
-  ifeq ($(call ld-ifversion, -lt, 22500000, y),)
+  ifeq ($(call ld-ifversion, -lt, 225000000, y),y)
     $(warning MIPS VDSO requires binutils >= 2.25)
     obj-vdso-y := $(filter-out gettimeofday.o, $(obj-vdso-y))
     ccflags-vdso += -DDISABLE_MIPS_VDSO
index 0eca6efc0631d52adcdd3bd66ad88bb7d33f830d..a7af5fb7b91476148e9ee2ce44d4d93ed3ad70fd 100644 (file)
@@ -34,7 +34,7 @@
 #define rmb()  __asm__ __volatile__ ("sync" : : : "memory")
 #define wmb()  __asm__ __volatile__ ("sync" : : : "memory")
 
-#define smp_store_mb(var, value)       do { WRITE_ONCE(var, value); mb(); } while (0)
+#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); smp_mb(); } while (0)
 
 #ifdef __SUBARCH_HAS_LWSYNC
 #    define SMPWMB      LWSYNC
index cfa758c6b4f6b639c686026966d73a4b4dcaff3b..271fefbbe521badbc1a232b8f3583fb10833388b 100644 (file)
 #define KVM_NR_IRQCHIPS          1
 #define KVM_IRQCHIP_NUM_PINS     256
 
+/* PPC-specific vcpu->requests bit members */
+#define KVM_REQ_WATCHDOG           8
+#define KVM_REQ_EPR_EXIT           9
+
 #include <linux/mmu_notifier.h>
 
 #define KVM_ARCH_WANT_MMU_NOTIFIER
index a7352b59e6f9b5c74f37556e6858c9ac9c5bb30b..6b352691b8c99cb8c46ba7cc0f80798edeff457d 100644 (file)
@@ -314,16 +314,10 @@ static void kvmppc_dump_regs(struct kvm_vcpu *vcpu)
 
 static struct kvm_vcpu *kvmppc_find_vcpu(struct kvm *kvm, int id)
 {
-       int r;
-       struct kvm_vcpu *v, *ret = NULL;
+       struct kvm_vcpu *ret;
 
        mutex_lock(&kvm->lock);
-       kvm_for_each_vcpu(r, v, kvm) {
-               if (v->vcpu_id == id) {
-                       ret = v;
-                       break;
-               }
-       }
+       ret = kvm_get_vcpu_by_id(kvm, id);
        mutex_unlock(&kvm->lock);
        return ret;
 }
index 64891b081ad54f57bbaa603d3315bf32b48368c8..70fb08da416dd60a7c52a10521b766c3733888fe 100644 (file)
@@ -512,7 +512,7 @@ static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte)
        put_page(hpage);
 }
 
-static int kvmppc_visible_gpa(struct kvm_vcpu *vcpu, gpa_t gpa)
+static bool kvmppc_visible_gpa(struct kvm_vcpu *vcpu, gpa_t gpa)
 {
        ulong mp_pa = vcpu->arch.magic_page_pa;
 
@@ -521,7 +521,7 @@ static int kvmppc_visible_gpa(struct kvm_vcpu *vcpu, gpa_t gpa)
 
        gpa &= ~0xFFFULL;
        if (unlikely(mp_pa) && unlikely((mp_pa & KVM_PAM) == (gpa & KVM_PAM))) {
-               return 1;
+               return true;
        }
 
        return kvm_is_visible_gfn(vcpu->kvm, gpa >> PAGE_SHIFT);
index 04782164ee67d8a570bcb4b4ee166dc6809753de..2d66a8446198dfcf48849c61a561cf7527f79e56 100644 (file)
@@ -78,18 +78,9 @@ static void bpf_jit_build_prologue(struct bpf_prog *fp, u32 *image,
                PPC_LI(r_X, 0);
        }
 
-       switch (filter[0].code) {
-       case BPF_RET | BPF_K:
-       case BPF_LD | BPF_W | BPF_LEN:
-       case BPF_LD | BPF_W | BPF_ABS:
-       case BPF_LD | BPF_H | BPF_ABS:
-       case BPF_LD | BPF_B | BPF_ABS:
-               /* first instruction sets A register (or is RET 'constant') */
-               break;
-       default:
-               /* make sure we dont leak kernel information to user */
+       /* make sure we dont leak kernel information to user */
+       if (bpf_needs_clear_a(&filter[0]))
                PPC_LI(r_A, 0);
-       }
 }
 
 static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)
index 610f472f91d14c25cef49a118ecc7f1d9eaf73b1..a1ac80b3041a9519523480a470c121d6db4cd3ca 100644 (file)
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/string.h>
+#include <linux/fsl/edac.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/memblock.h>
 #include <linux/log2.h>
+#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/suspend.h>
 #include <linux/syscore_ops.h>
@@ -1255,6 +1257,25 @@ void fsl_pcibios_fixup_phb(struct pci_controller *phb)
 #endif
 }
 
+static int add_err_dev(struct platform_device *pdev)
+{
+       struct platform_device *errdev;
+       struct mpc85xx_edac_pci_plat_data pd = {
+               .of_node = pdev->dev.of_node
+       };
+
+       errdev = platform_device_register_resndata(&pdev->dev,
+                                                  "mpc85xx-pci-edac",
+                                                  PLATFORM_DEVID_AUTO,
+                                                  pdev->resource,
+                                                  pdev->num_resources,
+                                                  &pd, sizeof(pd));
+       if (IS_ERR(errdev))
+               return PTR_ERR(errdev);
+
+       return 0;
+}
+
 static int fsl_pci_probe(struct platform_device *pdev)
 {
        struct device_node *node;
@@ -1262,8 +1283,13 @@ static int fsl_pci_probe(struct platform_device *pdev)
 
        node = pdev->dev.of_node;
        ret = fsl_add_bridge(pdev, fsl_pci_primary == node);
+       if (ret)
+               return ret;
 
-       mpc85xx_pci_err_probe(pdev);
+       ret = add_err_dev(pdev);
+       if (ret)
+               dev_err(&pdev->dev, "couldn't register error device: %d\n",
+                       ret);
 
        return 0;
 }
index c1cec771d5eae2f7f81381782dbff1193d21db46..151588530b0650f0454c43a4a8e90b079546f915 100644 (file)
@@ -130,15 +130,6 @@ void fsl_pci_assign_primary(void);
 static inline void fsl_pci_assign_primary(void) {}
 #endif
 
-#ifdef CONFIG_EDAC_MPC85XX
-int mpc85xx_pci_err_probe(struct platform_device *op);
-#else
-static inline int mpc85xx_pci_err_probe(struct platform_device *op)
-{
-       return -ENOTSUPP;
-}
-#endif
-
 #ifdef CONFIG_FSL_PCI
 extern int fsl_pci_mcheck_exception(struct pt_regs *);
 #else
index d68e11e0df5eada7e600f58529e8cbe60fab41c7..7ffd0b19135c8d46770f1f37ca6d4da19e352de0 100644 (file)
@@ -36,7 +36,7 @@
 #define smp_mb__before_atomic()                smp_mb()
 #define smp_mb__after_atomic()         smp_mb()
 
-#define smp_store_mb(var, value)               do { WRITE_ONCE(var, value); mb(); } while (0)
+#define smp_store_mb(var, value)       do { WRITE_ONCE(var, value); smp_mb(); } while (0)
 
 #define smp_store_release(p, v)                                                \
 do {                                                                   \
index bab6739a1154e1fd9827ff8dfb5c152ef52f3930..08e34a5dc909a82025094eda1f0261abceec18ba 100644 (file)
 #define HWCAP_S390_TE          1024
 #define HWCAP_S390_VXRS                2048
 
+/* Internal bits, not exposed via elf */
+#define HWCAP_INT_SIE          1UL
+
 /*
  * These are used to set parameters in the core dumps.
  */
@@ -169,6 +172,10 @@ extern unsigned int vdso_enabled;
 extern unsigned long elf_hwcap;
 #define ELF_HWCAP (elf_hwcap)
 
+/* Internal hardware capabilities, not exposed via elf */
+
+extern unsigned long int_hwcap;
+
 /* This yields a string that ld.so will use to load implementation
    specific libraries for optimization.  This is more specific in
    intent than poking at uname or /proc/cpuinfo.
index efaac2c3bb77a028a748de19820cd40ee528c0a0..6742414dbd6f30b66451f04602cb55de0d20f41c 100644 (file)
@@ -25,7 +25,9 @@
 #include <asm/fpu/api.h>
 #include <asm/isc.h>
 
-#define KVM_MAX_VCPUS 64
+#define KVM_S390_BSCA_CPU_SLOTS 64
+#define KVM_S390_ESCA_CPU_SLOTS 248
+#define KVM_MAX_VCPUS KVM_S390_ESCA_CPU_SLOTS
 #define KVM_USER_MEM_SLOTS 32
 
 /*
 #define KVM_IRQCHIP_NUM_PINS 4096
 #define KVM_HALT_POLL_NS_DEFAULT 0
 
+/* s390-specific vcpu->requests bit members */
+#define KVM_REQ_ENABLE_IBS         8
+#define KVM_REQ_DISABLE_IBS        9
+
 #define SIGP_CTRL_C            0x80
 #define SIGP_CTRL_SCN_MASK     0x3f
 
-struct sca_entry {
+union bsca_sigp_ctrl {
+       __u8 value;
+       struct {
+               __u8 c : 1;
+               __u8 r : 1;
+               __u8 scn : 6;
+       };
+} __packed;
+
+union esca_sigp_ctrl {
+       __u16 value;
+       struct {
+               __u8 c : 1;
+               __u8 reserved: 7;
+               __u8 scn;
+       };
+} __packed;
+
+struct esca_entry {
+       union esca_sigp_ctrl sigp_ctrl;
+       __u16   reserved1[3];
+       __u64   sda;
+       __u64   reserved2[6];
+} __packed;
+
+struct bsca_entry {
        __u8    reserved0;
-       __u8    sigp_ctrl;
+       union bsca_sigp_ctrl    sigp_ctrl;
        __u16   reserved[3];
        __u64   sda;
        __u64   reserved2[2];
@@ -57,14 +88,22 @@ union ipte_control {
        };
 };
 
-struct sca_block {
+struct bsca_block {
        union ipte_control ipte_control;
        __u64   reserved[5];
        __u64   mcn;
        __u64   reserved2;
-       struct sca_entry cpu[64];
+       struct bsca_entry cpu[KVM_S390_BSCA_CPU_SLOTS];
 } __attribute__((packed));
 
+struct esca_block {
+       union ipte_control ipte_control;
+       __u64   reserved1[7];
+       __u64   mcn[4];
+       __u64   reserved2[20];
+       struct esca_entry cpu[KVM_S390_ESCA_CPU_SLOTS];
+} __packed;
+
 #define CPUSTAT_STOPPED    0x80000000
 #define CPUSTAT_WAIT       0x10000000
 #define CPUSTAT_ECALL_PEND 0x08000000
@@ -182,7 +221,8 @@ struct kvm_s390_sie_block {
        __u64   pp;                     /* 0x01de */
        __u8    reserved1e6[2];         /* 0x01e6 */
        __u64   itdba;                  /* 0x01e8 */
-       __u8    reserved1f0[16];        /* 0x01f0 */
+       __u64   riccbd;                 /* 0x01f0 */
+       __u8    reserved1f8[8];         /* 0x01f8 */
 } __attribute__((packed));
 
 struct kvm_s390_itdb {
@@ -585,11 +625,14 @@ struct kvm_s390_crypto_cb {
 };
 
 struct kvm_arch{
-       struct sca_block *sca;
+       void *sca;
+       int use_esca;
+       rwlock_t sca_lock;
        debug_info_t *dbf;
        struct kvm_s390_float_interrupt float_int;
        struct kvm_device *flic;
        struct gmap *gmap;
+       unsigned long mem_limit;
        int css_support;
        int use_irqchip;
        int use_cmma;
index 821dde5f425d0b3e97fbe32f5496fe968e4899fd..dea883f85d66ae59edf460320ca2db07e5be4523 100644 (file)
@@ -29,7 +29,10 @@ struct sclp_ipl_info {
 
 struct sclp_core_entry {
        u8 core_id;
-       u8 reserved0[2];
+       u8 reserved0;
+       u8 : 4;
+       u8 sief2 : 1;
+       u8 : 3;
        u8 : 3;
        u8 siif : 1;
        u8 sigpif : 1;
@@ -53,6 +56,9 @@ struct sclp_info {
        unsigned char has_sigpif : 1;
        unsigned char has_core_type : 1;
        unsigned char has_sprp : 1;
+       unsigned char has_hvs : 1;
+       unsigned char has_esca : 1;
+       unsigned char has_sief2 : 1;
        unsigned int ibc;
        unsigned int mtid;
        unsigned int mtid_cp;
index ef1a5fcc6c66bbf5705173b41371378c4b541483..fe84bd5fe7ce05a44c4b75630a7f35405d075ec7 100644 (file)
@@ -66,6 +66,8 @@ struct kvm_s390_io_adapter_req {
 #define KVM_S390_VM_MEM_CLR_CMMA       1
 #define KVM_S390_VM_MEM_LIMIT_SIZE     2
 
+#define KVM_S390_NO_MEM_LIMIT          U64_MAX
+
 /* kvm attributes for KVM_S390_VM_TOD */
 #define KVM_S390_VM_TOD_LOW            0
 #define KVM_S390_VM_TOD_HIGH           1
@@ -151,6 +153,7 @@ struct kvm_guest_debug_arch {
 #define KVM_SYNC_ARCH0  (1UL << 4)
 #define KVM_SYNC_PFAULT (1UL << 5)
 #define KVM_SYNC_VRS    (1UL << 6)
+#define KVM_SYNC_RICCB  (1UL << 7)
 /* definition of registers in kvm_run */
 struct kvm_sync_regs {
        __u64 prefix;   /* prefix register */
@@ -168,6 +171,8 @@ struct kvm_sync_regs {
        __u64 vrs[32][2];       /* vector registers */
        __u8  reserved[512];    /* for future vector expansion */
        __u32 fpc;      /* only valid with vector registers */
+       __u8 padding[52];       /* riccb needs to be 64byte aligned */
+       __u8 riccb[64];         /* runtime instrumentation controls block */
 };
 
 #define KVM_REG_S390_TODPR     (KVM_REG_S390 | KVM_REG_SIZE_U32 | 0x1)
index 7ce00e7a709a946058b4bdeaadecba16f969d326..647128d5b9839bad0d939493908c0d83780a7c45 100644 (file)
@@ -61,6 +61,9 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp",
                "edat", "etf3eh", "highgprs", "te", "vx"
        };
+       static const char * const int_hwcap_str[] = {
+               "sie"
+       };
        unsigned long n = (unsigned long) v - 1;
        int i;
 
@@ -75,6 +78,9 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                for (i = 0; i < ARRAY_SIZE(hwcap_str); i++)
                        if (hwcap_str[i] && (elf_hwcap & (1UL << i)))
                                seq_printf(m, "%s ", hwcap_str[i]);
+               for (i = 0; i < ARRAY_SIZE(int_hwcap_str); i++)
+                       if (int_hwcap_str[i] && (int_hwcap & (1UL << i)))
+                               seq_printf(m, "%s ", int_hwcap_str[i]);
                seq_puts(m, "\n");
                show_cacheinfo(m);
        }
index c837bcacf2188460a50754f3a75d1b485c25f671..dc83ae66a730983fe0ef6206e501b0571e2ef5c2 100644 (file)
@@ -80,6 +80,8 @@ EXPORT_SYMBOL(console_irq);
 unsigned long elf_hwcap __read_mostly = 0;
 char elf_platform[ELF_PLATFORM_SIZE];
 
+unsigned long int_hwcap = 0;
+
 int __initdata memory_end_set;
 unsigned long __initdata memory_end;
 unsigned long __initdata max_physmem_end;
@@ -793,6 +795,13 @@ static int __init setup_hwcaps(void)
                strcpy(elf_platform, "z13");
                break;
        }
+
+       /*
+        * Virtualization support HWCAP_INT_SIE is bit 0.
+        */
+       if (sclp.has_sief2)
+               int_hwcap |= HWCAP_INT_SIE;
+
        return 0;
 }
 arch_initcall(setup_hwcaps);
index 5fbfb88f847731db6ef4cb1ab87b32cf601703df..05f7de9869a9f1786a8b996edd10fcdb280bd7c0 100644 (file)
@@ -155,10 +155,8 @@ static int __diag_time_slice_end(struct kvm_vcpu *vcpu)
 
 static int __diag_time_slice_end_directed(struct kvm_vcpu *vcpu)
 {
-       struct kvm *kvm = vcpu->kvm;
        struct kvm_vcpu *tcpu;
        int tid;
-       int i;
 
        tid = vcpu->run->s.regs.gprs[(vcpu->arch.sie_block->ipa & 0xf0) >> 4];
        vcpu->stat.diagnose_9c++;
@@ -167,12 +165,9 @@ static int __diag_time_slice_end_directed(struct kvm_vcpu *vcpu)
        if (tid == vcpu->vcpu_id)
                return 0;
 
-       kvm_for_each_vcpu(i, tcpu, kvm)
-               if (tcpu->vcpu_id == tid) {
-                       kvm_vcpu_yield_to(tcpu);
-                       break;
-               }
-
+       tcpu = kvm_get_vcpu_by_id(vcpu->kvm, tid);
+       if (tcpu)
+               kvm_vcpu_yield_to(tcpu);
        return 0;
 }
 
index a7559f7207df3a0ac62d0fc16b199f3b4c6b6dac..d30db40437dc0d03943a1c98f79dbb7dfce8e863 100644 (file)
@@ -259,10 +259,14 @@ struct aste {
 
 int ipte_lock_held(struct kvm_vcpu *vcpu)
 {
-       union ipte_control *ic = &vcpu->kvm->arch.sca->ipte_control;
+       if (vcpu->arch.sie_block->eca & 1) {
+               int rc;
 
-       if (vcpu->arch.sie_block->eca & 1)
-               return ic->kh != 0;
+               read_lock(&vcpu->kvm->arch.sca_lock);
+               rc = kvm_s390_get_ipte_control(vcpu->kvm)->kh != 0;
+               read_unlock(&vcpu->kvm->arch.sca_lock);
+               return rc;
+       }
        return vcpu->kvm->arch.ipte_lock_count != 0;
 }
 
@@ -274,16 +278,20 @@ static void ipte_lock_simple(struct kvm_vcpu *vcpu)
        vcpu->kvm->arch.ipte_lock_count++;
        if (vcpu->kvm->arch.ipte_lock_count > 1)
                goto out;
-       ic = &vcpu->kvm->arch.sca->ipte_control;
+retry:
+       read_lock(&vcpu->kvm->arch.sca_lock);
+       ic = kvm_s390_get_ipte_control(vcpu->kvm);
        do {
                old = READ_ONCE(*ic);
-               while (old.k) {
+               if (old.k) {
+                       read_unlock(&vcpu->kvm->arch.sca_lock);
                        cond_resched();
-                       old = READ_ONCE(*ic);
+                       goto retry;
                }
                new = old;
                new.k = 1;
        } while (cmpxchg(&ic->val, old.val, new.val) != old.val);
+       read_unlock(&vcpu->kvm->arch.sca_lock);
 out:
        mutex_unlock(&vcpu->kvm->arch.ipte_mutex);
 }
@@ -296,12 +304,14 @@ static void ipte_unlock_simple(struct kvm_vcpu *vcpu)
        vcpu->kvm->arch.ipte_lock_count--;
        if (vcpu->kvm->arch.ipte_lock_count)
                goto out;
-       ic = &vcpu->kvm->arch.sca->ipte_control;
+       read_lock(&vcpu->kvm->arch.sca_lock);
+       ic = kvm_s390_get_ipte_control(vcpu->kvm);
        do {
                old = READ_ONCE(*ic);
                new = old;
                new.k = 0;
        } while (cmpxchg(&ic->val, old.val, new.val) != old.val);
+       read_unlock(&vcpu->kvm->arch.sca_lock);
        wake_up(&vcpu->kvm->arch.ipte_wq);
 out:
        mutex_unlock(&vcpu->kvm->arch.ipte_mutex);
@@ -311,24 +321,29 @@ static void ipte_lock_siif(struct kvm_vcpu *vcpu)
 {
        union ipte_control old, new, *ic;
 
-       ic = &vcpu->kvm->arch.sca->ipte_control;
+retry:
+       read_lock(&vcpu->kvm->arch.sca_lock);
+       ic = kvm_s390_get_ipte_control(vcpu->kvm);
        do {
                old = READ_ONCE(*ic);
-               while (old.kg) {
+               if (old.kg) {
+                       read_unlock(&vcpu->kvm->arch.sca_lock);
                        cond_resched();
-                       old = READ_ONCE(*ic);
+                       goto retry;
                }
                new = old;
                new.k = 1;
                new.kh++;
        } while (cmpxchg(&ic->val, old.val, new.val) != old.val);
+       read_unlock(&vcpu->kvm->arch.sca_lock);
 }
 
 static void ipte_unlock_siif(struct kvm_vcpu *vcpu)
 {
        union ipte_control old, new, *ic;
 
-       ic = &vcpu->kvm->arch.sca->ipte_control;
+       read_lock(&vcpu->kvm->arch.sca_lock);
+       ic = kvm_s390_get_ipte_control(vcpu->kvm);
        do {
                old = READ_ONCE(*ic);
                new = old;
@@ -336,6 +351,7 @@ static void ipte_unlock_siif(struct kvm_vcpu *vcpu)
                if (!new.kh)
                        new.k = 0;
        } while (cmpxchg(&ic->val, old.val, new.val) != old.val);
+       read_unlock(&vcpu->kvm->arch.sca_lock);
        if (!new.kh)
                wake_up(&vcpu->kvm->arch.ipte_wq);
 }
index b4a5aa110cec0b7ea62a534769812a2782b8cc35..d53c10753c466b47b6fcb4813ec9e3445ca47a04 100644 (file)
@@ -54,9 +54,6 @@ void kvm_s390_rewind_psw(struct kvm_vcpu *vcpu, int ilc)
 static int handle_noop(struct kvm_vcpu *vcpu)
 {
        switch (vcpu->arch.sie_block->icptcode) {
-       case 0x0:
-               vcpu->stat.exit_null++;
-               break;
        case 0x10:
                vcpu->stat.exit_external_request++;
                break;
@@ -338,8 +335,10 @@ static int handle_partial_execution(struct kvm_vcpu *vcpu)
 
 int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu)
 {
+       if (kvm_is_ucontrol(vcpu->kvm))
+               return -EOPNOTSUPP;
+
        switch (vcpu->arch.sie_block->icptcode) {
-       case 0x00:
        case 0x10:
        case 0x18:
                return handle_noop(vcpu);
index 6a75352f453c1a46775112c2749b8cff31d62ed1..62ec925aa196d061d2fd7acc35d6542d6d5c188c 100644 (file)
 #define PFAULT_DONE 0x0680
 #define VIRTIO_PARAM 0x0d00
 
+/* handle external calls via sigp interpretation facility */
+static int sca_ext_call_pending(struct kvm_vcpu *vcpu, int *src_id)
+{
+       int c, scn;
+
+       if (!(atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_ECALL_PEND))
+               return 0;
+
+       read_lock(&vcpu->kvm->arch.sca_lock);
+       if (vcpu->kvm->arch.use_esca) {
+               struct esca_block *sca = vcpu->kvm->arch.sca;
+               union esca_sigp_ctrl sigp_ctrl =
+                       sca->cpu[vcpu->vcpu_id].sigp_ctrl;
+
+               c = sigp_ctrl.c;
+               scn = sigp_ctrl.scn;
+       } else {
+               struct bsca_block *sca = vcpu->kvm->arch.sca;
+               union bsca_sigp_ctrl sigp_ctrl =
+                       sca->cpu[vcpu->vcpu_id].sigp_ctrl;
+
+               c = sigp_ctrl.c;
+               scn = sigp_ctrl.scn;
+       }
+       read_unlock(&vcpu->kvm->arch.sca_lock);
+
+       if (src_id)
+               *src_id = scn;
+
+       return c;
+}
+
+static int sca_inject_ext_call(struct kvm_vcpu *vcpu, int src_id)
+{
+       int expect, rc;
+
+       read_lock(&vcpu->kvm->arch.sca_lock);
+       if (vcpu->kvm->arch.use_esca) {
+               struct esca_block *sca = vcpu->kvm->arch.sca;
+               union esca_sigp_ctrl *sigp_ctrl =
+                       &(sca->cpu[vcpu->vcpu_id].sigp_ctrl);
+               union esca_sigp_ctrl new_val = {0}, old_val = *sigp_ctrl;
+
+               new_val.scn = src_id;
+               new_val.c = 1;
+               old_val.c = 0;
+
+               expect = old_val.value;
+               rc = cmpxchg(&sigp_ctrl->value, old_val.value, new_val.value);
+       } else {
+               struct bsca_block *sca = vcpu->kvm->arch.sca;
+               union bsca_sigp_ctrl *sigp_ctrl =
+                       &(sca->cpu[vcpu->vcpu_id].sigp_ctrl);
+               union bsca_sigp_ctrl new_val = {0}, old_val = *sigp_ctrl;
+
+               new_val.scn = src_id;
+               new_val.c = 1;
+               old_val.c = 0;
+
+               expect = old_val.value;
+               rc = cmpxchg(&sigp_ctrl->value, old_val.value, new_val.value);
+       }
+       read_unlock(&vcpu->kvm->arch.sca_lock);
+
+       if (rc != expect) {
+               /* another external call is pending */
+               return -EBUSY;
+       }
+       atomic_or(CPUSTAT_ECALL_PEND, &vcpu->arch.sie_block->cpuflags);
+       return 0;
+}
+
+static void sca_clear_ext_call(struct kvm_vcpu *vcpu)
+{
+       struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+       int rc, expect;
+
+       atomic_andnot(CPUSTAT_ECALL_PEND, li->cpuflags);
+       read_lock(&vcpu->kvm->arch.sca_lock);
+       if (vcpu->kvm->arch.use_esca) {
+               struct esca_block *sca = vcpu->kvm->arch.sca;
+               union esca_sigp_ctrl *sigp_ctrl =
+                       &(sca->cpu[vcpu->vcpu_id].sigp_ctrl);
+               union esca_sigp_ctrl old = *sigp_ctrl;
+
+               expect = old.value;
+               rc = cmpxchg(&sigp_ctrl->value, old.value, 0);
+       } else {
+               struct bsca_block *sca = vcpu->kvm->arch.sca;
+               union bsca_sigp_ctrl *sigp_ctrl =
+                       &(sca->cpu[vcpu->vcpu_id].sigp_ctrl);
+               union bsca_sigp_ctrl old = *sigp_ctrl;
+
+               expect = old.value;
+               rc = cmpxchg(&sigp_ctrl->value, old.value, 0);
+       }
+       read_unlock(&vcpu->kvm->arch.sca_lock);
+       WARN_ON(rc != expect); /* cannot clear? */
+}
+
 int psw_extint_disabled(struct kvm_vcpu *vcpu)
 {
        return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT);
@@ -792,13 +892,11 @@ static const deliver_irq_t deliver_irq_funcs[] = {
 int kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu)
 {
        struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
-       uint8_t sigp_ctrl = vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl;
 
        if (!sclp.has_sigpif)
                return test_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs);
 
-       return (sigp_ctrl & SIGP_CTRL_C) &&
-              (atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_ECALL_PEND);
+       return sca_ext_call_pending(vcpu, NULL);
 }
 
 int kvm_s390_vcpu_has_irq(struct kvm_vcpu *vcpu, int exclude_stop)
@@ -909,9 +1007,7 @@ void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu)
        memset(&li->irq, 0, sizeof(li->irq));
        spin_unlock(&li->lock);
 
-       /* clear pending external calls set by sigp interpretation facility */
-       atomic_andnot(CPUSTAT_ECALL_PEND, li->cpuflags);
-       vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl = 0;
+       sca_clear_ext_call(vcpu);
 }
 
 int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
@@ -1003,21 +1099,6 @@ static int __inject_pfault_init(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
        return 0;
 }
 
-static int __inject_extcall_sigpif(struct kvm_vcpu *vcpu, uint16_t src_id)
-{
-       unsigned char new_val, old_val;
-       uint8_t *sigp_ctrl = &vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl;
-
-       new_val = SIGP_CTRL_C | (src_id & SIGP_CTRL_SCN_MASK);
-       old_val = *sigp_ctrl & ~SIGP_CTRL_C;
-       if (cmpxchg(sigp_ctrl, old_val, new_val) != old_val) {
-               /* another external call is pending */
-               return -EBUSY;
-       }
-       atomic_or(CPUSTAT_ECALL_PEND, &vcpu->arch.sie_block->cpuflags);
-       return 0;
-}
-
 static int __inject_extcall(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
 {
        struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
@@ -1034,7 +1115,7 @@ static int __inject_extcall(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
                return -EINVAL;
 
        if (sclp.has_sigpif)
-               return __inject_extcall_sigpif(vcpu, src_id);
+               return sca_inject_ext_call(vcpu, src_id);
 
        if (test_and_set_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs))
                return -EBUSY;
@@ -2203,7 +2284,7 @@ static void store_local_irq(struct kvm_s390_local_interrupt *li,
 
 int kvm_s390_get_irq_state(struct kvm_vcpu *vcpu, __u8 __user *buf, int len)
 {
-       uint8_t sigp_ctrl = vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl;
+       int scn;
        unsigned long sigp_emerg_pending[BITS_TO_LONGS(KVM_MAX_VCPUS)];
        struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
        unsigned long pending_irqs;
@@ -2243,14 +2324,12 @@ int kvm_s390_get_irq_state(struct kvm_vcpu *vcpu, __u8 __user *buf, int len)
                }
        }
 
-       if ((sigp_ctrl & SIGP_CTRL_C) &&
-           (atomic_read(&vcpu->arch.sie_block->cpuflags) &
-            CPUSTAT_ECALL_PEND)) {
+       if (sca_ext_call_pending(vcpu, &scn)) {
                if (n + sizeof(irq) > len)
                        return -ENOBUFS;
                memset(&irq, 0, sizeof(irq));
                irq.type = KVM_S390_INT_EXTERNAL_CALL;
-               irq.u.extcall.code = sigp_ctrl & SIGP_CTRL_SCN_MASK;
+               irq.u.extcall.code = scn;
                if (copy_to_user(&buf[n], &irq, sizeof(irq)))
                        return -EFAULT;
                n += sizeof(irq);
index 846589281b046f414837cbd3f7ab9f4d0c675a51..5927c61d322a94e490fef6c77d31f3be848c71d2 100644 (file)
@@ -246,7 +246,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
                break;
        case KVM_CAP_NR_VCPUS:
        case KVM_CAP_MAX_VCPUS:
-               r = KVM_MAX_VCPUS;
+               r = sclp.has_esca ? KVM_S390_ESCA_CPU_SLOTS
+                                 : KVM_S390_BSCA_CPU_SLOTS;
                break;
        case KVM_CAP_NR_MEMSLOTS:
                r = KVM_USER_MEM_SLOTS;
@@ -257,6 +258,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_S390_VECTOR_REGISTERS:
                r = MACHINE_HAS_VX;
                break;
+       case KVM_CAP_S390_RI:
+               r = test_facility(64);
+               break;
        default:
                r = 0;
        }
@@ -283,6 +287,8 @@ static void kvm_s390_sync_dirty_log(struct kvm *kvm,
 }
 
 /* Section: vm related */
+static void sca_del_vcpu(struct kvm_vcpu *vcpu);
+
 /*
  * Get (and clear) the dirty memory log for a memory slot.
  */
@@ -355,6 +361,20 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
                VM_EVENT(kvm, 3, "ENABLE: CAP_S390_VECTOR_REGISTERS %s",
                         r ? "(not available)" : "(success)");
                break;
+       case KVM_CAP_S390_RI:
+               r = -EINVAL;
+               mutex_lock(&kvm->lock);
+               if (atomic_read(&kvm->online_vcpus)) {
+                       r = -EBUSY;
+               } else if (test_facility(64)) {
+                       set_kvm_facility(kvm->arch.model.fac->mask, 64);
+                       set_kvm_facility(kvm->arch.model.fac->list, 64);
+                       r = 0;
+               }
+               mutex_unlock(&kvm->lock);
+               VM_EVENT(kvm, 3, "ENABLE: CAP_S390_RI %s",
+                        r ? "(not available)" : "(success)");
+               break;
        case KVM_CAP_S390_USER_STSI:
                VM_EVENT(kvm, 3, "%s", "ENABLE: CAP_S390_USER_STSI");
                kvm->arch.user_stsi = 1;
@@ -375,8 +395,8 @@ static int kvm_s390_get_mem_control(struct kvm *kvm, struct kvm_device_attr *att
        case KVM_S390_VM_MEM_LIMIT_SIZE:
                ret = 0;
                VM_EVENT(kvm, 3, "QUERY: max guest memory: %lu bytes",
-                        kvm->arch.gmap->asce_end);
-               if (put_user(kvm->arch.gmap->asce_end, (u64 __user *)attr->addr))
+                        kvm->arch.mem_limit);
+               if (put_user(kvm->arch.mem_limit, (u64 __user *)attr->addr))
                        ret = -EFAULT;
                break;
        default:
@@ -428,9 +448,17 @@ static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *att
                if (get_user(new_limit, (u64 __user *)attr->addr))
                        return -EFAULT;
 
-               if (new_limit > kvm->arch.gmap->asce_end)
+               if (kvm->arch.mem_limit != KVM_S390_NO_MEM_LIMIT &&
+                   new_limit > kvm->arch.mem_limit)
                        return -E2BIG;
 
+               if (!new_limit)
+                       return -EINVAL;
+
+               /* gmap_alloc takes last usable address */
+               if (new_limit != KVM_S390_NO_MEM_LIMIT)
+                       new_limit -= 1;
+
                ret = -EBUSY;
                mutex_lock(&kvm->lock);
                if (atomic_read(&kvm->online_vcpus) == 0) {
@@ -447,7 +475,9 @@ static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *att
                        }
                }
                mutex_unlock(&kvm->lock);
-               VM_EVENT(kvm, 3, "SET: max guest memory: %lu bytes", new_limit);
+               VM_EVENT(kvm, 3, "SET: max guest address: %lu", new_limit);
+               VM_EVENT(kvm, 3, "New guest asce: 0x%pK",
+                        (void *) kvm->arch.gmap->asce);
                break;
        }
        default:
@@ -1024,7 +1054,7 @@ static int kvm_s390_apxa_installed(void)
        u8 config[128];
        int cc;
 
-       if (test_facility(2) && test_facility(12)) {
+       if (test_facility(12)) {
                cc = kvm_s390_query_ap_config(config);
 
                if (cc)
@@ -1075,6 +1105,15 @@ static int kvm_s390_crypto_init(struct kvm *kvm)
        return 0;
 }
 
+static void sca_dispose(struct kvm *kvm)
+{
+       if (kvm->arch.use_esca)
+               free_pages_exact(kvm->arch.sca, sizeof(struct esca_block));
+       else
+               free_page((unsigned long)(kvm->arch.sca));
+       kvm->arch.sca = NULL;
+}
+
 int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 {
        int i, rc;
@@ -1098,14 +1137,17 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 
        rc = -ENOMEM;
 
-       kvm->arch.sca = (struct sca_block *) get_zeroed_page(GFP_KERNEL);
+       kvm->arch.use_esca = 0; /* start with basic SCA */
+       rwlock_init(&kvm->arch.sca_lock);
+       kvm->arch.sca = (struct bsca_block *) get_zeroed_page(GFP_KERNEL);
        if (!kvm->arch.sca)
                goto out_err;
        spin_lock(&kvm_lock);
        sca_offset += 16;
-       if (sca_offset + sizeof(struct sca_block) > PAGE_SIZE)
+       if (sca_offset + sizeof(struct bsca_block) > PAGE_SIZE)
                sca_offset = 0;
-       kvm->arch.sca = (struct sca_block *) ((char *) kvm->arch.sca + sca_offset);
+       kvm->arch.sca = (struct bsca_block *)
+                       ((char *) kvm->arch.sca + sca_offset);
        spin_unlock(&kvm_lock);
 
        sprintf(debug_name, "kvm-%u", current->pid);
@@ -1157,8 +1199,14 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 
        if (type & KVM_VM_S390_UCONTROL) {
                kvm->arch.gmap = NULL;
+               kvm->arch.mem_limit = KVM_S390_NO_MEM_LIMIT;
        } else {
-               kvm->arch.gmap = gmap_alloc(current->mm, (1UL << 44) - 1);
+               if (sclp.hamax == U64_MAX)
+                       kvm->arch.mem_limit = TASK_MAX_SIZE;
+               else
+                       kvm->arch.mem_limit = min_t(unsigned long, TASK_MAX_SIZE,
+                                                   sclp.hamax + 1);
+               kvm->arch.gmap = gmap_alloc(current->mm, kvm->arch.mem_limit - 1);
                if (!kvm->arch.gmap)
                        goto out_err;
                kvm->arch.gmap->private = kvm;
@@ -1170,14 +1218,14 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
        kvm->arch.epoch = 0;
 
        spin_lock_init(&kvm->arch.start_stop_lock);
-       KVM_EVENT(3, "vm 0x%p created by pid %u", kvm, current->pid);
+       KVM_EVENT(3, "vm 0x%pK created by pid %u", kvm, current->pid);
 
        return 0;
 out_err:
        kfree(kvm->arch.crypto.crycb);
        free_page((unsigned long)kvm->arch.model.fac);
        debug_unregister(kvm->arch.dbf);
-       free_page((unsigned long)(kvm->arch.sca));
+       sca_dispose(kvm);
        KVM_EVENT(3, "creation of vm failed: %d", rc);
        return rc;
 }
@@ -1188,14 +1236,8 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
        trace_kvm_s390_destroy_vcpu(vcpu->vcpu_id);
        kvm_s390_clear_local_irqs(vcpu);
        kvm_clear_async_pf_completion_queue(vcpu);
-       if (!kvm_is_ucontrol(vcpu->kvm)) {
-               clear_bit(63 - vcpu->vcpu_id,
-                         (unsigned long *) &vcpu->kvm->arch.sca->mcn);
-               if (vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda ==
-                   (__u64) vcpu->arch.sie_block)
-                       vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda = 0;
-       }
-       smp_mb();
+       if (!kvm_is_ucontrol(vcpu->kvm))
+               sca_del_vcpu(vcpu);
 
        if (kvm_is_ucontrol(vcpu->kvm))
                gmap_free(vcpu->arch.gmap);
@@ -1228,14 +1270,14 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
 {
        kvm_free_vcpus(kvm);
        free_page((unsigned long)kvm->arch.model.fac);
-       free_page((unsigned long)(kvm->arch.sca));
+       sca_dispose(kvm);
        debug_unregister(kvm->arch.dbf);
        kfree(kvm->arch.crypto.crycb);
        if (!kvm_is_ucontrol(kvm))
                gmap_free(kvm->arch.gmap);
        kvm_s390_destroy_adapters(kvm);
        kvm_s390_clear_float_irqs(kvm);
-       KVM_EVENT(3, "vm 0x%p destroyed", kvm);
+       KVM_EVENT(3, "vm 0x%pK destroyed", kvm);
 }
 
 /* Section: vcpu related */
@@ -1249,6 +1291,117 @@ static int __kvm_ucontrol_vcpu_init(struct kvm_vcpu *vcpu)
        return 0;
 }
 
+static void sca_del_vcpu(struct kvm_vcpu *vcpu)
+{
+       read_lock(&vcpu->kvm->arch.sca_lock);
+       if (vcpu->kvm->arch.use_esca) {
+               struct esca_block *sca = vcpu->kvm->arch.sca;
+
+               clear_bit_inv(vcpu->vcpu_id, (unsigned long *) sca->mcn);
+               sca->cpu[vcpu->vcpu_id].sda = 0;
+       } else {
+               struct bsca_block *sca = vcpu->kvm->arch.sca;
+
+               clear_bit_inv(vcpu->vcpu_id, (unsigned long *) &sca->mcn);
+               sca->cpu[vcpu->vcpu_id].sda = 0;
+       }
+       read_unlock(&vcpu->kvm->arch.sca_lock);
+}
+
+static void sca_add_vcpu(struct kvm_vcpu *vcpu)
+{
+       read_lock(&vcpu->kvm->arch.sca_lock);
+       if (vcpu->kvm->arch.use_esca) {
+               struct esca_block *sca = vcpu->kvm->arch.sca;
+
+               sca->cpu[vcpu->vcpu_id].sda = (__u64) vcpu->arch.sie_block;
+               vcpu->arch.sie_block->scaoh = (__u32)(((__u64)sca) >> 32);
+               vcpu->arch.sie_block->scaol = (__u32)(__u64)sca & ~0x3fU;
+               vcpu->arch.sie_block->ecb2 |= 0x04U;
+               set_bit_inv(vcpu->vcpu_id, (unsigned long *) sca->mcn);
+       } else {
+               struct bsca_block *sca = vcpu->kvm->arch.sca;
+
+               sca->cpu[vcpu->vcpu_id].sda = (__u64) vcpu->arch.sie_block;
+               vcpu->arch.sie_block->scaoh = (__u32)(((__u64)sca) >> 32);
+               vcpu->arch.sie_block->scaol = (__u32)(__u64)sca;
+               set_bit_inv(vcpu->vcpu_id, (unsigned long *) &sca->mcn);
+       }
+       read_unlock(&vcpu->kvm->arch.sca_lock);
+}
+
+/* Basic SCA to Extended SCA data copy routines */
+static inline void sca_copy_entry(struct esca_entry *d, struct bsca_entry *s)
+{
+       d->sda = s->sda;
+       d->sigp_ctrl.c = s->sigp_ctrl.c;
+       d->sigp_ctrl.scn = s->sigp_ctrl.scn;
+}
+
+static void sca_copy_b_to_e(struct esca_block *d, struct bsca_block *s)
+{
+       int i;
+
+       d->ipte_control = s->ipte_control;
+       d->mcn[0] = s->mcn;
+       for (i = 0; i < KVM_S390_BSCA_CPU_SLOTS; i++)
+               sca_copy_entry(&d->cpu[i], &s->cpu[i]);
+}
+
+static int sca_switch_to_extended(struct kvm *kvm)
+{
+       struct bsca_block *old_sca = kvm->arch.sca;
+       struct esca_block *new_sca;
+       struct kvm_vcpu *vcpu;
+       unsigned int vcpu_idx;
+       u32 scaol, scaoh;
+
+       new_sca = alloc_pages_exact(sizeof(*new_sca), GFP_KERNEL|__GFP_ZERO);
+       if (!new_sca)
+               return -ENOMEM;
+
+       scaoh = (u32)((u64)(new_sca) >> 32);
+       scaol = (u32)(u64)(new_sca) & ~0x3fU;
+
+       kvm_s390_vcpu_block_all(kvm);
+       write_lock(&kvm->arch.sca_lock);
+
+       sca_copy_b_to_e(new_sca, old_sca);
+
+       kvm_for_each_vcpu(vcpu_idx, vcpu, kvm) {
+               vcpu->arch.sie_block->scaoh = scaoh;
+               vcpu->arch.sie_block->scaol = scaol;
+               vcpu->arch.sie_block->ecb2 |= 0x04U;
+       }
+       kvm->arch.sca = new_sca;
+       kvm->arch.use_esca = 1;
+
+       write_unlock(&kvm->arch.sca_lock);
+       kvm_s390_vcpu_unblock_all(kvm);
+
+       free_page((unsigned long)old_sca);
+
+       VM_EVENT(kvm, 2, "Switched to ESCA (0x%pK -> 0x%pK)",
+                old_sca, kvm->arch.sca);
+       return 0;
+}
+
+static int sca_can_add_vcpu(struct kvm *kvm, unsigned int id)
+{
+       int rc;
+
+       if (id < KVM_S390_BSCA_CPU_SLOTS)
+               return true;
+       if (!sclp.has_esca)
+               return false;
+
+       mutex_lock(&kvm->lock);
+       rc = kvm->arch.use_esca ? 0 : sca_switch_to_extended(kvm);
+       mutex_unlock(&kvm->lock);
+
+       return rc == 0 && id < KVM_S390_ESCA_CPU_SLOTS;
+}
+
 int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 {
        vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
@@ -1259,6 +1412,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
                                    KVM_SYNC_CRS |
                                    KVM_SYNC_ARCH0 |
                                    KVM_SYNC_PFAULT;
+       if (test_kvm_facility(vcpu->kvm, 64))
+               vcpu->run->kvm_valid_regs |= KVM_SYNC_RICCB;
        if (test_kvm_facility(vcpu->kvm, 129))
                vcpu->run->kvm_valid_regs |= KVM_SYNC_VRS;
 
@@ -1369,8 +1524,11 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
        vcpu->arch.sie_block->epoch = vcpu->kvm->arch.epoch;
        preempt_enable();
        mutex_unlock(&vcpu->kvm->lock);
-       if (!kvm_is_ucontrol(vcpu->kvm))
+       if (!kvm_is_ucontrol(vcpu->kvm)) {
                vcpu->arch.gmap = vcpu->kvm->arch.gmap;
+               sca_add_vcpu(vcpu);
+       }
+
 }
 
 static void kvm_s390_vcpu_crypto_setup(struct kvm_vcpu *vcpu)
@@ -1439,10 +1597,13 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
                vcpu->arch.sie_block->eca |= 1;
        if (sclp.has_sigpif)
                vcpu->arch.sie_block->eca |= 0x10000000U;
+       if (test_kvm_facility(vcpu->kvm, 64))
+               vcpu->arch.sie_block->ecb3 |= 0x01;
        if (test_kvm_facility(vcpu->kvm, 129)) {
                vcpu->arch.sie_block->eca |= 0x00020000;
                vcpu->arch.sie_block->ecd |= 0x20000000;
        }
+       vcpu->arch.sie_block->riccbd = (unsigned long) &vcpu->run->s.regs.riccb;
        vcpu->arch.sie_block->ictl |= ICTL_ISKE | ICTL_SSKE | ICTL_RRBE;
 
        if (vcpu->kvm->arch.use_cmma) {
@@ -1465,7 +1626,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
        struct sie_page *sie_page;
        int rc = -EINVAL;
 
-       if (id >= KVM_MAX_VCPUS)
+       if (!kvm_is_ucontrol(kvm) && !sca_can_add_vcpu(kvm, id))
                goto out;
 
        rc = -ENOMEM;
@@ -1482,20 +1643,6 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
        vcpu->arch.sie_block->itdba = (unsigned long) &sie_page->itdb;
 
        vcpu->arch.sie_block->icpua = id;
-       if (!kvm_is_ucontrol(kvm)) {
-               if (!kvm->arch.sca) {
-                       WARN_ON_ONCE(1);
-                       goto out_free_cpu;
-               }
-               if (!kvm->arch.sca->cpu[id].sda)
-                       kvm->arch.sca->cpu[id].sda =
-                               (__u64) vcpu->arch.sie_block;
-               vcpu->arch.sie_block->scaoh =
-                       (__u32)(((__u64)kvm->arch.sca) >> 32);
-               vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca;
-               set_bit(63 - id, (unsigned long *) &kvm->arch.sca->mcn);
-       }
-
        spin_lock_init(&vcpu->arch.local_int.lock);
        vcpu->arch.local_int.float_int = &kvm->arch.float_int;
        vcpu->arch.local_int.wq = &vcpu->wq;
@@ -1509,15 +1656,13 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
         */
        vcpu->arch.guest_fpregs.fprs = kzalloc(sizeof(freg_t) * __NUM_FPRS,
                                               GFP_KERNEL);
-       if (!vcpu->arch.guest_fpregs.fprs) {
-               rc = -ENOMEM;
+       if (!vcpu->arch.guest_fpregs.fprs)
                goto out_free_sie_block;
-       }
 
        rc = kvm_vcpu_init(vcpu, kvm, id);
        if (rc)
                goto out_free_sie_block;
-       VM_EVENT(kvm, 3, "create cpu %d at %p, sie block at %p", id, vcpu,
+       VM_EVENT(kvm, 3, "create cpu %d at 0x%pK, sie block at 0x%pK", id, vcpu,
                 vcpu->arch.sie_block);
        trace_kvm_s390_create_vcpu(id, vcpu, vcpu->arch.sie_block);
 
@@ -2013,7 +2158,8 @@ static int vcpu_pre_run(struct kvm_vcpu *vcpu)
         */
        kvm_check_async_pf_completion(vcpu);
 
-       memcpy(&vcpu->arch.sie_block->gg14, &vcpu->run->s.regs.gprs[14], 16);
+       vcpu->arch.sie_block->gg14 = vcpu->run->s.regs.gprs[14];
+       vcpu->arch.sie_block->gg15 = vcpu->run->s.regs.gprs[15];
 
        if (need_resched())
                schedule();
@@ -2071,8 +2217,6 @@ static int vcpu_post_run_fault_in_sie(struct kvm_vcpu *vcpu)
 
 static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
 {
-       int rc = -1;
-
        VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
                   vcpu->arch.sie_block->icptcode);
        trace_kvm_s390_sie_exit(vcpu, vcpu->arch.sie_block->icptcode);
@@ -2080,40 +2224,36 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
        if (guestdbg_enabled(vcpu))
                kvm_s390_restore_guest_per_regs(vcpu);
 
-       if (exit_reason >= 0) {
-               rc = 0;
+       vcpu->run->s.regs.gprs[14] = vcpu->arch.sie_block->gg14;
+       vcpu->run->s.regs.gprs[15] = vcpu->arch.sie_block->gg15;
+
+       if (vcpu->arch.sie_block->icptcode > 0) {
+               int rc = kvm_handle_sie_intercept(vcpu);
+
+               if (rc != -EOPNOTSUPP)
+                       return rc;
+               vcpu->run->exit_reason = KVM_EXIT_S390_SIEIC;
+               vcpu->run->s390_sieic.icptcode = vcpu->arch.sie_block->icptcode;
+               vcpu->run->s390_sieic.ipa = vcpu->arch.sie_block->ipa;
+               vcpu->run->s390_sieic.ipb = vcpu->arch.sie_block->ipb;
+               return -EREMOTE;
+       } else if (exit_reason != -EFAULT) {
+               vcpu->stat.exit_null++;
+               return 0;
        } else if (kvm_is_ucontrol(vcpu->kvm)) {
                vcpu->run->exit_reason = KVM_EXIT_S390_UCONTROL;
                vcpu->run->s390_ucontrol.trans_exc_code =
                                                current->thread.gmap_addr;
                vcpu->run->s390_ucontrol.pgm_code = 0x10;
-               rc = -EREMOTE;
-
+               return -EREMOTE;
        } else if (current->thread.gmap_pfault) {
                trace_kvm_s390_major_guest_pfault(vcpu);
                current->thread.gmap_pfault = 0;
-               if (kvm_arch_setup_async_pf(vcpu)) {
-                       rc = 0;
-               } else {
-                       gpa_t gpa = current->thread.gmap_addr;
-                       rc = kvm_arch_fault_in_page(vcpu, gpa, 1);
-               }
+               if (kvm_arch_setup_async_pf(vcpu))
+                       return 0;
+               return kvm_arch_fault_in_page(vcpu, current->thread.gmap_addr, 1);
        }
-
-       if (rc == -1)
-               rc = vcpu_post_run_fault_in_sie(vcpu);
-
-       memcpy(&vcpu->run->s.regs.gprs[14], &vcpu->arch.sie_block->gg14, 16);
-
-       if (rc == 0) {
-               if (kvm_is_ucontrol(vcpu->kvm))
-                       /* Don't exit for host interrupts. */
-                       rc = vcpu->arch.sie_block->icptcode ? -EOPNOTSUPP : 0;
-               else
-                       rc = kvm_handle_sie_intercept(vcpu);
-       }
-
-       return rc;
+       return vcpu_post_run_fault_in_sie(vcpu);
 }
 
 static int __vcpu_run(struct kvm_vcpu *vcpu)
@@ -2233,18 +2373,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                rc = 0;
        }
 
-       if (rc == -EOPNOTSUPP) {
-               /* intercept cannot be handled in-kernel, prepare kvm-run */
-               kvm_run->exit_reason         = KVM_EXIT_S390_SIEIC;
-               kvm_run->s390_sieic.icptcode = vcpu->arch.sie_block->icptcode;
-               kvm_run->s390_sieic.ipa      = vcpu->arch.sie_block->ipa;
-               kvm_run->s390_sieic.ipb      = vcpu->arch.sie_block->ipb;
-               rc = 0;
-       }
-
        if (rc == -EREMOTE) {
-               /* intercept was handled, but userspace support is needed
-                * kvm_run has been prepared by the handler */
+               /* userspace support is needed, kvm_run has been prepared */
                rc = 0;
        }
 
@@ -2736,6 +2866,9 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
        if (mem->memory_size & 0xffffful)
                return -EINVAL;
 
+       if (mem->guest_phys_addr + mem->memory_size > kvm->arch.mem_limit)
+               return -EINVAL;
+
        return 0;
 }
 
@@ -2767,6 +2900,11 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
 
 static int __init kvm_s390_init(void)
 {
+       if (!sclp.has_sief2) {
+               pr_info("SIE not available\n");
+               return -ENODEV;
+       }
+
        return kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE);
 }
 
index 1e70e00d3c5ecd4b97df9faa2d7d8b98fabecb58..df1abada1f36dfc3579ab6ff2ef45c7db828490b 100644 (file)
@@ -340,4 +340,11 @@ void kvm_s390_clear_bp_data(struct kvm_vcpu *vcpu);
 void kvm_s390_prepare_debug_exit(struct kvm_vcpu *vcpu);
 void kvm_s390_handle_per_event(struct kvm_vcpu *vcpu);
 
+/* support for Basic/Extended SCA handling */
+static inline union ipte_control *kvm_s390_get_ipte_control(struct kvm *kvm)
+{
+       struct bsca_block *sca = kvm->arch.sca; /* SCA version doesn't matter */
+
+       return &sca->ipte_control;
+}
 #endif
index cc1d6c68356fc3ede1cb2dd22cc6781f83c8288b..396485bca191ce46b5a46a8466ecb3af8b67ac23 100644 (file)
@@ -55,8 +55,8 @@ TRACE_EVENT(kvm_s390_create_vcpu,
                    __entry->sie_block = sie_block;
                    ),
 
-           TP_printk("create cpu %d at %p, sie block at %p", __entry->id,
-                     __entry->vcpu, __entry->sie_block)
+           TP_printk("create cpu %d at 0x%pK, sie block at 0x%pK",
+                     __entry->id, __entry->vcpu, __entry->sie_block)
        );
 
 TRACE_EVENT(kvm_s390_destroy_vcpu,
@@ -254,7 +254,7 @@ TRACE_EVENT(kvm_s390_enable_css,
                    __entry->kvm = kvm;
                    ),
 
-           TP_printk("enabling channel I/O support (kvm @ %p)\n",
+           TP_printk("enabling channel I/O support (kvm @ %pK)\n",
                      __entry->kvm)
        );
 
index 54ef3bc01b43c361a47d6a9112b9bb7bfcdc4501..63b039899a5ed1d70c56445b28f18b6d5389df28 100644 (file)
@@ -133,7 +133,7 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit)
 /**
  * gmap_alloc - allocate a guest address space
  * @mm: pointer to the parent mm_struct
- * @limit: maximum size of the gmap address space
+ * @limit: maximum address of the gmap address space
  *
  * Returns a guest address space structure.
  */
@@ -402,7 +402,7 @@ int gmap_map_segment(struct gmap *gmap, unsigned long from,
        if ((from | to | len) & (PMD_SIZE - 1))
                return -EINVAL;
        if (len == 0 || from + len < from || to + len < to ||
-           from + len > TASK_MAX_SIZE || to + len > gmap->asce_end)
+           from + len - 1 > TASK_MAX_SIZE || to + len - 1 > gmap->asce_end)
                return -EINVAL;
 
        flush = 0;
index cbd2a9f02a91ff795696b23656e570d3110102af..62c3b81300ed282de2721dded8f1f34fcc954076 100644 (file)
 #include <linux/gpio.h>
 #include <linux/videodev2.h>
 #include <linux/sh_intc.h>
-#include <media/ov772x.h>
+#include <media/i2c/ov772x.h>
 #include <media/soc_camera.h>
-#include <media/soc_camera_platform.h>
-#include <media/sh_mobile_ceu.h>
+#include <linux/platform_data/media/soc_camera_platform.h>
+#include <media/drv-intf/sh_mobile_ceu.h>
 #include <video/sh_mobile_lcdc.h>
 #include <asm/io.h>
 #include <asm/clock.h>
index d531791f06ffe154bed0b4bbd978709d6b5e8309..a9c0c07386fddd963a3bcae54428b21060152174 100644 (file)
 #include <video/sh_mobile_lcdc.h>
 #include <sound/sh_fsi.h>
 #include <sound/simple_card.h>
-#include <media/sh_mobile_ceu.h>
+#include <media/drv-intf/sh_mobile_ceu.h>
 #include <media/soc_camera.h>
-#include <media/tw9910.h>
-#include <media/mt9t112.h>
+#include <media/i2c/tw9910.h>
+#include <media/i2c/mt9t112.h>
 #include <asm/heartbeat.h>
 #include <asm/clock.h>
 #include <asm/suspend.h>
@@ -900,8 +900,8 @@ static struct platform_device irda_device = {
        .resource       = irda_resources,
 };
 
-#include <media/ak881x.h>
-#include <media/sh_vou.h>
+#include <media/i2c/ak881x.h>
+#include <media/drv-intf/sh_vou.h>
 
 static struct ak881x_pdata ak881x_pdata = {
        .flags = AK881X_IF_MODE_SLAVE,
index 7d997cec09c53ef0a10fc18d6db4e6c5f796331e..6bd9230e64e3003790833f31111f6398548c767f 100644 (file)
@@ -27,9 +27,9 @@
 #include <linux/usb/r8a66597.h>
 #include <linux/videodev2.h>
 #include <linux/sh_intc.h>
-#include <media/rj54n1cb0c.h>
+#include <media/i2c/rj54n1cb0c.h>
 #include <media/soc_camera.h>
-#include <media/sh_mobile_ceu.h>
+#include <media/drv-intf/sh_mobile_ceu.h>
 #include <video/sh_mobile_lcdc.h>
 #include <asm/suspend.h>
 #include <asm/clock.h>
index 29b7c0dcfc51c6e5c200d1c3c4d377627a3b50cf..8f237a5bd9aab21473d52bc3808e69bcc2adb6d5 100644 (file)
 #include <linux/videodev2.h>
 #include <linux/sh_intc.h>
 #include <video/sh_mobile_lcdc.h>
-#include <media/sh_mobile_ceu.h>
-#include <media/ov772x.h>
+#include <media/drv-intf/sh_mobile_ceu.h>
+#include <media/i2c/ov772x.h>
 #include <media/soc_camera.h>
-#include <media/tw9910.h>
+#include <media/i2c/tw9910.h>
 #include <asm/clock.h>
 #include <asm/machvec.h>
 #include <asm/io.h>
index 4f6635a075f20429549251b77fd1cc053dbe1f0c..e0e1df136642cdbb08d8f63f3d0c16cb4266ba61 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/sh_intc.h>
 #include <linux/videodev2.h>
 #include <video/sh_mobile_lcdc.h>
-#include <media/sh_mobile_ceu.h>
+#include <media/drv-intf/sh_mobile_ceu.h>
 #include <sound/sh_fsi.h>
 #include <sound/simple_card.h>
 #include <asm/io.h>
@@ -534,8 +534,8 @@ static struct platform_device irda_device = {
        .resource       = irda_resources,
 };
 
-#include <media/ak881x.h>
-#include <media/sh_vou.h>
+#include <media/i2c/ak881x.h>
+#include <media/drv-intf/sh_vou.h>
 
 static struct ak881x_pdata ak881x_pdata = {
        .flags = AK881X_IF_MODE_SLAVE,
index f31a124a84975938648feb14302ee1e62dd46dee..1c26d440d288dfb8d28579fda55e2a76ccf4c139 100644 (file)
 #define __NR_execveat          350
 #define __NR_membarrier                351
 #define __NR_userfaultfd       352
+#define __NR_bind              353
+#define __NR_listen            354
+#define __NR_setsockopt                355
+#define __NR_mlock2            356
 
-#define NR_syscalls            353
+#define NR_syscalls            357
 
 /* Bitmask values returned from kern_features system call.  */
 #define KERN_FEATURE_MIXED_MODE_STACK  0x00000001
index 78e80293cb6dff900aac7acc8d1d2b38de01ea26..e663b6c78de2e6498a5a458f1129504cae3ab2a8 100644 (file)
@@ -35,18 +35,18 @@ sys_call_table:
 /*80*/ .long sys_setgroups16, sys_getpgrp, sys_setgroups, sys_setitimer, sys_ftruncate64
 /*85*/ .long sys_swapon, sys_getitimer, sys_setuid, sys_sethostname, sys_setgid
 /*90*/ .long sys_dup2, sys_setfsuid, sys_fcntl, sys_select, sys_setfsgid
-/*95*/ .long sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*95*/ .long sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
 /*100*/        .long sys_getpriority, sys_rt_sigreturn, sys_rt_sigaction, sys_rt_sigprocmask, sys_rt_sigpending
 /*105*/        .long sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_setresuid, sys_getresuid
-/*110*/        .long sys_setresgid, sys_getresgid, sys_setregid, sys_nis_syscall, sys_nis_syscall
-/*115*/        .long sys_getgroups, sys_gettimeofday, sys_getrusage, sys_nis_syscall, sys_getcwd
+/*110*/        .long sys_setresgid, sys_getresgid, sys_setregid, sys_recvmsg, sys_sendmsg
+/*115*/        .long sys_getgroups, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_getcwd
 /*120*/        .long sys_readv, sys_writev, sys_settimeofday, sys_fchown16, sys_fchmod
-/*125*/        .long sys_nis_syscall, sys_setreuid16, sys_setregid16, sys_rename, sys_truncate
-/*130*/        .long sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall
-/*135*/        .long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_stat64
-/*140*/        .long sys_sendfile64, sys_nis_syscall, sys_futex, sys_gettid, sys_getrlimit
+/*125*/        .long sys_recvfrom, sys_setreuid16, sys_setregid16, sys_rename, sys_truncate
+/*130*/        .long sys_ftruncate, sys_flock, sys_lstat64, sys_sendto, sys_shutdown
+/*135*/        .long sys_socketpair, sys_mkdir, sys_rmdir, sys_utimes, sys_stat64
+/*140*/        .long sys_sendfile64, sys_getpeername, sys_futex, sys_gettid, sys_getrlimit
 /*145*/        .long sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
-/*150*/        .long sys_nis_syscall, sys_inotify_init, sys_inotify_add_watch, sys_poll, sys_getdents64
+/*150*/        .long sys_getsockname, sys_inotify_init, sys_inotify_add_watch, sys_poll, sys_getdents64
 /*155*/        .long sys_fcntl64, sys_inotify_rm_watch, sys_statfs, sys_fstatfs, sys_oldumount
 /*160*/        .long sys_sched_setaffinity, sys_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_nis_syscall
 /*165*/        .long sys_quotactl, sys_set_tid_address, sys_mount, sys_ustat, sys_setxattr
@@ -87,4 +87,5 @@ sys_call_table:
 /*335*/        .long sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev
 /*340*/        .long sys_ni_syscall, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr
 /*345*/        .long sys_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create, sys_bpf
-/*350*/        .long sys_execveat, sys_membarrier, sys_userfaultfd
+/*350*/        .long sys_execveat, sys_membarrier, sys_userfaultfd, sys_bind, sys_listen
+/*355*/        .long sys_setsockopt, sys_mlock2
index 2549c2c3ec2f5d2cd745b1c8c0736d722320f42d..1557121f4cdce8a6ae21c31fb33e9aa2d7cbc443 100644 (file)
@@ -37,15 +37,15 @@ sys_call_table32:
 /*80*/ .word sys_setgroups16, sys_getpgrp, sys_setgroups, compat_sys_setitimer, sys32_ftruncate64
        .word sys_swapon, compat_sys_getitimer, sys_setuid, sys_sethostname, sys_setgid
 /*90*/ .word sys_dup2, sys_setfsuid, compat_sys_fcntl, sys32_select, sys_setfsgid
-       .word sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+       .word sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
 /*100*/ .word sys_getpriority, sys32_rt_sigreturn, compat_sys_rt_sigaction, compat_sys_rt_sigprocmask, compat_sys_rt_sigpending
        .word compat_sys_rt_sigtimedwait, compat_sys_rt_sigqueueinfo, compat_sys_rt_sigsuspend, sys_setresuid, sys_getresuid
-/*110*/        .word sys_setresgid, sys_getresgid, sys_setregid, sys_nis_syscall, sys_nis_syscall
-       .word sys_getgroups, compat_sys_gettimeofday, compat_sys_getrusage, sys_nis_syscall, sys_getcwd
+/*110*/        .word sys_setresgid, sys_getresgid, sys_setregid, compat_sys_recvmsg, compat_sys_sendmsg
+       .word sys_getgroups, compat_sys_gettimeofday, compat_sys_getrusage, compat_sys_getsockopt, sys_getcwd
 /*120*/        .word compat_sys_readv, compat_sys_writev, compat_sys_settimeofday, sys_fchown16, sys_fchmod
-       .word sys_nis_syscall, sys_setreuid16, sys_setregid16, sys_rename, compat_sys_truncate
-/*130*/        .word compat_sys_ftruncate, sys_flock, compat_sys_lstat64, sys_nis_syscall, sys_nis_syscall
-       .word sys_nis_syscall, sys_mkdir, sys_rmdir, compat_sys_utimes, compat_sys_stat64
+       .word sys_recvfrom, sys_setreuid16, sys_setregid16, sys_rename, compat_sys_truncate
+/*130*/        .word compat_sys_ftruncate, sys_flock, compat_sys_lstat64, sys_sendto, sys_shutdown
+       .word sys_socketpair, sys_mkdir, sys_rmdir, compat_sys_utimes, compat_sys_stat64
 /*140*/        .word sys_sendfile64, sys_nis_syscall, sys32_futex, sys_gettid, compat_sys_getrlimit
        .word compat_sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
 /*150*/        .word sys_nis_syscall, sys_inotify_init, sys_inotify_add_watch, sys_poll, sys_getdents64
@@ -88,7 +88,8 @@ sys_call_table32:
        .word sys_syncfs, compat_sys_sendmmsg, sys_setns, compat_sys_process_vm_readv, compat_sys_process_vm_writev
 /*340*/        .word sys_kern_features, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr
        .word sys32_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create, sys_bpf
-/*350*/        .word sys32_execveat, sys_membarrier, sys_userfaultfd
+/*350*/        .word sys32_execveat, sys_membarrier, sys_userfaultfd, sys_bind, sys_listen
+       .word compat_sys_setsockopt, sys_mlock2
 
 #endif /* CONFIG_COMPAT */
 
@@ -168,4 +169,5 @@ sys_call_table:
        .word sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev
 /*340*/        .word sys_kern_features, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr
        .word sys_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create, sys_bpf
-/*350*/        .word sys64_execveat, sys_membarrier, sys_userfaultfd
+/*350*/        .word sys64_execveat, sys_membarrier, sys_userfaultfd, sys_bind, sys_listen
+       .word sys_setsockopt, sys_mlock2
index 22564f5f23647a6f54752052091d2c74c194bccf..3e6e05a7c4c22b297861eb82871d92b7217cffee 100644 (file)
@@ -420,22 +420,9 @@ void bpf_jit_compile(struct bpf_prog *fp)
                }
                emit_reg_move(O7, r_saved_O7);
 
-               switch (filter[0].code) {
-               case BPF_RET | BPF_K:
-               case BPF_LD | BPF_W | BPF_LEN:
-               case BPF_LD | BPF_W | BPF_ABS:
-               case BPF_LD | BPF_H | BPF_ABS:
-               case BPF_LD | BPF_B | BPF_ABS:
-                       /* The first instruction sets the A register (or is
-                        * a "RET 'constant'")
-                        */
-                       break;
-               default:
-                       /* Make sure we dont leak kernel information to the
-                        * user.
-                        */
+               /* Make sure we dont leak kernel information to the user. */
+               if (bpf_needs_clear_a(&filter[0]))
                        emit_clear(r_A); /* A = 0 */
-               }
 
                for (i = 0; i < flen; i++) {
                        unsigned int K = filter[i].k;
index 106c21bd7f449d947094db5fdefce8a9a6e1b142..8ec7a4599c085dd0d05f7ad819c11d4659223c51 100644 (file)
@@ -176,8 +176,6 @@ config NR_CPUS
          smaller kernel memory footprint results from using a smaller
          value on chips with fewer tiles.
 
-if TILEGX
-
 choice
        prompt "Kernel page size"
        default PAGE_SIZE_64KB
@@ -188,8 +186,11 @@ choice
          connections, etc., it may be better to select 16KB, which uses
          memory more efficiently at some cost in TLB performance.
 
-         Note that this option is TILE-Gx specific; currently
-         TILEPro page size is set by rebuilding the hypervisor.
+         Note that for TILEPro, you must also rebuild the hypervisor
+         with a matching page size.
+
+config PAGE_SIZE_4KB
+       bool "4KB" if TILEPRO
 
 config PAGE_SIZE_16KB
        bool "16KB"
@@ -199,8 +200,6 @@ config PAGE_SIZE_64KB
 
 endchoice
 
-endif
-
 source "kernel/Kconfig.hz"
 
 config KEXEC
index 0ccda3c425be0d3b19a27c13b68ad6b6eaa37525..25d5899497be193bdbaba16a46107e7030de7fe8 100644 (file)
@@ -127,8 +127,6 @@ long long _atomic64_cmpxchg(long long *v, long long o, long long n);
 
 #endif
 
-#define tas(ptr) xchg((ptr), 1)
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_TILE_CMPXCHG_H */
index a213a8d84a95ac48a149de807558290c21dbe2cb..8eca6a0e176200c3604151c4168b0553a0002768 100644 (file)
 #include <arch/chip.h>
 
 /* PAGE_SHIFT and HPAGE_SHIFT determine the page sizes. */
-#if defined(CONFIG_PAGE_SIZE_16KB)
+#if defined(CONFIG_PAGE_SIZE_4KB)  /* tilepro only */
+#define PAGE_SHIFT     12
+#define CTX_PAGE_FLAG  HV_CTX_PG_SM_4K
+#elif defined(CONFIG_PAGE_SIZE_16KB)
 #define PAGE_SHIFT     14
 #define CTX_PAGE_FLAG  HV_CTX_PG_SM_16K
 #elif defined(CONFIG_PAGE_SIZE_64KB)
 #define PAGE_SHIFT     16
 #define CTX_PAGE_FLAG  HV_CTX_PG_SM_64K
 #else
-#define PAGE_SHIFT     HV_LOG2_DEFAULT_PAGE_SIZE_SMALL
-#define CTX_PAGE_FLAG  0
+#error Page size not specified in Kconfig
 #endif
 #define HPAGE_SHIFT    HV_LOG2_DEFAULT_PAGE_SIZE_LARGE
 
index db3622f22b618303a8bc9c3c2f34762f400dbafb..258965d56beb9ccba468ba2bf6b5b99ab17cd798 100644 (file)
@@ -349,6 +349,17 @@ config X86_FEATURE_NAMES
 
          If in doubt, say Y.
 
+config X86_FAST_FEATURE_TESTS
+       bool "Fast CPU feature tests" if EMBEDDED
+       default y
+       ---help---
+         Some fast-paths in the kernel depend on the capabilities of the CPU.
+         Say Y here for the kernel to patch in the appropriate code at runtime
+         based on the capabilities of the CPU. The infrastructure for patching
+         code at runtime takes up some additional space; space-constrained
+         embedded systems may wish to say N here to produce smaller, slightly
+         slower code.
+
 config X86_X2APIC
        bool "Support x2apic"
        depends on X86_LOCAL_APIC && X86_64 && (IRQ_REMAP || HYPERVISOR_GUEST)
@@ -687,6 +698,14 @@ config PARAVIRT_SPINLOCKS
 
          If you are unsure how to answer this question, answer Y.
 
+config QUEUED_LOCK_STAT
+       bool "Paravirt queued spinlock statistics"
+       depends on PARAVIRT_SPINLOCKS && DEBUG_FS && QUEUED_SPINLOCKS
+       ---help---
+         Enable the collection of statistical data on the slowpath
+         behavior of paravirtualized queued spinlocks and report
+         them on debugfs.
+
 source "arch/x86/xen/Kconfig"
 
 config KVM_GUEST
index 137dfa96aa14e1c8c3a9c1d7b50b21d910cabae4..110253ce83afcb30a8473f5c6d2136aadbe50144 100644 (file)
@@ -69,7 +69,7 @@ config X86_PTDUMP_CORE
        def_bool n
 
 config X86_PTDUMP
-       bool "Export kernel pagetable layout to userspace via debugfs"
+       tristate "Export kernel pagetable layout to userspace via debugfs"
        depends on DEBUG_KERNEL
        select DEBUG_FS
        select X86_PTDUMP_CORE
index 722bacea040e71f4cae3769e38605e51a6fd8f82..8baaff5af0b572b27e9c488083d2d751216775d9 100644 (file)
@@ -125,7 +125,7 @@ static struct crypto_alg alg = {
 
 static int __init chacha20_simd_mod_init(void)
 {
-       if (!cpu_has_ssse3)
+       if (!boot_cpu_has(X86_FEATURE_SSSE3))
                return -ENODEV;
 
 #ifdef CONFIG_AS_AVX2
index 81a595d75cf5959bbcae8c2096ebdf0f538bf7f9..0e9871693f2469d3106f57ab6dc94d85a3f16146 100644 (file)
@@ -257,7 +257,7 @@ static int __init crc32c_intel_mod_init(void)
        if (!x86_match_cpu(crc32c_cpu_id))
                return -ENODEV;
 #ifdef CONFIG_X86_64
-       if (cpu_has_pclmulqdq) {
+       if (boot_cpu_has(X86_FEATURE_PCLMULQDQ)) {
                alg.update = crc32c_pcl_intel_update;
                alg.finup = crc32c_pcl_intel_finup;
                alg.digest = crc32c_pcl_intel_digest;
index 3c71dd947c7b32dbbfabeea409b3437c3d5ec127..e32206e0986828390e769604ec6cd510b1f2296e 100644 (file)
@@ -1,3 +1,5 @@
+#include <linux/jump_label.h>
+
 /*
 
  x86 function call convention, 64-bit:
@@ -232,3 +234,16 @@ For 32-bit we have the following conventions - kernel is built with
 
 #endif /* CONFIG_X86_64 */
 
+/*
+ * This does 'call enter_from_user_mode' unless we can avoid it based on
+ * kernel config or using the static jump infrastructure.
+ */
+.macro CALL_enter_from_user_mode
+#ifdef CONFIG_CONTEXT_TRACKING
+#ifdef HAVE_JUMP_LABEL
+       STATIC_JUMP_IF_FALSE .Lafter_call_\@, context_tracking_enabled, def=0
+#endif
+       call enter_from_user_mode
+.Lafter_call_\@:
+#endif
+.endm
index a89fdbc1f0beb7e7198c7a625767a2cfe32ca9e3..03663740c86655cabf21504578e97d73d98595be 100644 (file)
@@ -421,7 +421,7 @@ __visible long do_fast_syscall_32(struct pt_regs *regs)
        regs->ip = landing_pad;
 
        /*
-        * Fetch ECX from where the vDSO stashed it.
+        * Fetch EBP from where the vDSO stashed it.
         *
         * WARNING: We are in CONTEXT_USER and RCU isn't paying attention!
         */
@@ -432,10 +432,10 @@ __visible long do_fast_syscall_32(struct pt_regs *regs)
                 * Micro-optimization: the pointer we're following is explicitly
                 * 32 bits, so it can't be out of range.
                 */
-               __get_user(*(u32 *)&regs->cx,
+               __get_user(*(u32 *)&regs->bp,
                            (u32 __user __force *)(unsigned long)(u32)regs->sp)
 #else
-               get_user(*(u32 *)&regs->cx,
+               get_user(*(u32 *)&regs->bp,
                         (u32 __user __force *)(unsigned long)(u32)regs->sp)
 #endif
                ) {
index 3eb572ed3d7ad438d8dfd1627b5b4121314c9f67..77d8c5112900e0edb73741af9c7cc4a60b0bb8f5 100644 (file)
@@ -292,7 +292,7 @@ ENTRY(entry_SYSENTER_32)
        movl    TSS_sysenter_sp0(%esp), %esp
 sysenter_past_esp:
        pushl   $__USER_DS              /* pt_regs->ss */
-       pushl   %ecx                    /* pt_regs->cx */
+       pushl   %ebp                    /* pt_regs->sp (stashed in bp) */
        pushfl                          /* pt_regs->flags (except IF = 0) */
        orl     $X86_EFLAGS_IF, (%esp)  /* Fix IF */
        pushl   $__USER_CS              /* pt_regs->cs */
@@ -308,8 +308,9 @@ sysenter_past_esp:
 
        movl    %esp, %eax
        call    do_fast_syscall_32
-       testl   %eax, %eax
-       jz      .Lsyscall_32_done
+       /* XEN PV guests always use IRET path */
+       ALTERNATIVE "testl %eax, %eax; jz .Lsyscall_32_done", \
+                   "jmp .Lsyscall_32_done", X86_FEATURE_XENPV
 
 /* Opportunistic SYSEXIT */
        TRACE_IRQS_ON                   /* User mode traces as IRQs on. */
@@ -328,7 +329,8 @@ sysenter_past_esp:
         * Return back to the vDSO, which will pop ecx and edx.
         * Don't bother with DS and ES (they already contain __USER_DS).
         */
-       ENABLE_INTERRUPTS_SYSEXIT
+       sti
+       sysexit
 
 .pushsection .fixup, "ax"
 2:     movl    $0, PT_FS(%esp)
@@ -551,11 +553,6 @@ ENTRY(native_iret)
        iret
        _ASM_EXTABLE(native_iret, iret_exc)
 END(native_iret)
-
-ENTRY(native_irq_enable_sysexit)
-       sti
-       sysexit
-END(native_irq_enable_sysexit)
 #endif
 
 ENTRY(overflow)
index a55697d19824727fda8306c566bb99cb4ba6d980..9d34d3cfceb61c1073c507f5a0f90e939eb146a3 100644 (file)
@@ -520,9 +520,7 @@ END(irq_entries_start)
         */
        TRACE_IRQS_OFF
 
-#ifdef CONFIG_CONTEXT_TRACKING
-       call enter_from_user_mode
-#endif
+       CALL_enter_from_user_mode
 
 1:
        /*
@@ -1066,9 +1064,7 @@ ENTRY(error_entry)
         * (which can take locks).
         */
        TRACE_IRQS_OFF
-#ifdef CONFIG_CONTEXT_TRACKING
-       call enter_from_user_mode
-#endif
+       CALL_enter_from_user_mode
        ret
 
 .Lerror_entry_done:
index c3201830a85ee8dcddabb0cab864545d99d47fd3..ff1c6d61f332d22e6f95f54a782b150b39bf75dc 100644 (file)
 
        .section .entry.text, "ax"
 
-#ifdef CONFIG_PARAVIRT
-ENTRY(native_usergs_sysret32)
-       swapgs
-       sysretl
-ENDPROC(native_usergs_sysret32)
-#endif
-
 /*
  * 32-bit SYSENTER instruction entry.
  *
@@ -63,7 +56,7 @@ ENTRY(entry_SYSENTER_compat)
 
        /* Construct struct pt_regs on stack */
        pushq   $__USER32_DS            /* pt_regs->ss */
-       pushq   %rcx                    /* pt_regs->sp */
+       pushq   %rbp                    /* pt_regs->sp (stashed in bp) */
 
        /*
         * Push flags.  This is nasty.  First, interrupts are currently
@@ -82,14 +75,14 @@ ENTRY(entry_SYSENTER_compat)
        pushq   %rdi                    /* pt_regs->di */
        pushq   %rsi                    /* pt_regs->si */
        pushq   %rdx                    /* pt_regs->dx */
-       pushq   %rcx                    /* pt_regs->cx (will be overwritten) */
+       pushq   %rcx                    /* pt_regs->cx */
        pushq   $-ENOSYS                /* pt_regs->ax */
        pushq   %r8                     /* pt_regs->r8  = 0 */
        pushq   %r8                     /* pt_regs->r9  = 0 */
        pushq   %r8                     /* pt_regs->r10 = 0 */
        pushq   %r8                     /* pt_regs->r11 = 0 */
        pushq   %rbx                    /* pt_regs->rbx */
-       pushq   %rbp                    /* pt_regs->rbp */
+       pushq   %rbp                    /* pt_regs->rbp (will be overwritten) */
        pushq   %r8                     /* pt_regs->r12 = 0 */
        pushq   %r8                     /* pt_regs->r13 = 0 */
        pushq   %r8                     /* pt_regs->r14 = 0 */
@@ -103,15 +96,15 @@ ENTRY(entry_SYSENTER_compat)
         * This needs to happen before enabling interrupts so that
         * we don't get preempted with NT set.
         *
-        * NB.: sysenter_fix_flags is a label with the code under it moved
+        * NB.: .Lsysenter_fix_flags is a label with the code under it moved
         * out-of-line as an optimization: NT is unlikely to be set in the
         * majority of the cases and instead of polluting the I$ unnecessarily,
         * we're keeping that code behind a branch which will predict as
         * not-taken and therefore its instructions won't be fetched.
         */
        testl   $X86_EFLAGS_NT, EFLAGS(%rsp)
-       jnz     sysenter_fix_flags
-sysenter_flags_fixed:
+       jnz     .Lsysenter_fix_flags
+.Lsysenter_flags_fixed:
 
        /*
         * User mode is traced as though IRQs are on, and SYSENTER
@@ -121,14 +114,15 @@ sysenter_flags_fixed:
 
        movq    %rsp, %rdi
        call    do_fast_syscall_32
-       testl   %eax, %eax
-       jz      .Lsyscall_32_done
+       /* XEN PV guests always use IRET path */
+       ALTERNATIVE "testl %eax, %eax; jz .Lsyscall_32_done", \
+                   "jmp .Lsyscall_32_done", X86_FEATURE_XENPV
        jmp     sysret32_from_system_call
 
-sysenter_fix_flags:
+.Lsysenter_fix_flags:
        pushq   $X86_EFLAGS_FIXED
        popfq
-       jmp     sysenter_flags_fixed
+       jmp     .Lsysenter_flags_fixed
 ENDPROC(entry_SYSENTER_compat)
 
 /*
@@ -178,7 +172,7 @@ ENTRY(entry_SYSCALL_compat)
        pushq   %rdi                    /* pt_regs->di */
        pushq   %rsi                    /* pt_regs->si */
        pushq   %rdx                    /* pt_regs->dx */
-       pushq   %rcx                    /* pt_regs->cx (will be overwritten) */
+       pushq   %rbp                    /* pt_regs->cx (stashed in bp) */
        pushq   $-ENOSYS                /* pt_regs->ax */
        xorq    %r8,%r8
        pushq   %r8                     /* pt_regs->r8  = 0 */
@@ -186,7 +180,7 @@ ENTRY(entry_SYSCALL_compat)
        pushq   %r8                     /* pt_regs->r10 = 0 */
        pushq   %r8                     /* pt_regs->r11 = 0 */
        pushq   %rbx                    /* pt_regs->rbx */
-       pushq   %rbp                    /* pt_regs->rbp */
+       pushq   %rbp                    /* pt_regs->rbp (will be overwritten) */
        pushq   %r8                     /* pt_regs->r12 = 0 */
        pushq   %r8                     /* pt_regs->r13 = 0 */
        pushq   %r8                     /* pt_regs->r14 = 0 */
@@ -200,8 +194,9 @@ ENTRY(entry_SYSCALL_compat)
 
        movq    %rsp, %rdi
        call    do_fast_syscall_32
-       testl   %eax, %eax
-       jz      .Lsyscall_32_done
+       /* XEN PV guests always use IRET path */
+       ALTERNATIVE "testl %eax, %eax; jz .Lsyscall_32_done", \
+                   "jmp .Lsyscall_32_done", X86_FEATURE_XENPV
 
        /* Opportunistic SYSRET */
 sysret32_from_system_call:
@@ -236,7 +231,8 @@ sysret32_from_system_call:
        xorq    %r9, %r9
        xorq    %r10, %r10
        movq    RSP-ORIG_RAX(%rsp), %rsp
-        USERGS_SYSRET32
+       swapgs
+       sysretl
 END(entry_SYSCALL_compat)
 
 /*
index ca94fa6492516b0b1d669b6f52b09e968e3ae5cf..8602f06c759f7eec2786eaa17df10b6a6720e8ea 100644 (file)
 #include <asm/vvar.h>
 #include <asm/unistd.h>
 #include <asm/msr.h>
+#include <asm/pvclock.h>
 #include <linux/math64.h>
 #include <linux/time.h>
+#include <linux/kernel.h>
 
 #define gtod (&VVAR(vsyscall_gtod_data))
 
@@ -36,12 +38,12 @@ static notrace cycle_t vread_hpet(void)
 }
 #endif
 
-#ifndef BUILD_VDSO32
+#ifdef CONFIG_PARAVIRT_CLOCK
+extern u8 pvclock_page
+       __attribute__((visibility("hidden")));
+#endif
 
-#include <linux/kernel.h>
-#include <asm/vsyscall.h>
-#include <asm/fixmap.h>
-#include <asm/pvclock.h>
+#ifndef BUILD_VDSO32
 
 notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
 {
@@ -60,75 +62,6 @@ notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz)
        return ret;
 }
 
-#ifdef CONFIG_PARAVIRT_CLOCK
-
-static notrace const struct pvclock_vsyscall_time_info *get_pvti(int cpu)
-{
-       const struct pvclock_vsyscall_time_info *pvti_base;
-       int idx = cpu / (PAGE_SIZE/PVTI_SIZE);
-       int offset = cpu % (PAGE_SIZE/PVTI_SIZE);
-
-       BUG_ON(PVCLOCK_FIXMAP_BEGIN + idx > PVCLOCK_FIXMAP_END);
-
-       pvti_base = (struct pvclock_vsyscall_time_info *)
-                   __fix_to_virt(PVCLOCK_FIXMAP_BEGIN+idx);
-
-       return &pvti_base[offset];
-}
-
-static notrace cycle_t vread_pvclock(int *mode)
-{
-       const struct pvclock_vsyscall_time_info *pvti;
-       cycle_t ret;
-       u64 last;
-       u32 version;
-       u8 flags;
-       unsigned cpu, cpu1;
-
-
-       /*
-        * Note: hypervisor must guarantee that:
-        * 1. cpu ID number maps 1:1 to per-CPU pvclock time info.
-        * 2. that per-CPU pvclock time info is updated if the
-        *    underlying CPU changes.
-        * 3. that version is increased whenever underlying CPU
-        *    changes.
-        *
-        */
-       do {
-               cpu = __getcpu() & VGETCPU_CPU_MASK;
-               /* TODO: We can put vcpu id into higher bits of pvti.version.
-                * This will save a couple of cycles by getting rid of
-                * __getcpu() calls (Gleb).
-                */
-
-               pvti = get_pvti(cpu);
-
-               version = __pvclock_read_cycles(&pvti->pvti, &ret, &flags);
-
-               /*
-                * Test we're still on the cpu as well as the version.
-                * We could have been migrated just after the first
-                * vgetcpu but before fetching the version, so we
-                * wouldn't notice a version change.
-                */
-               cpu1 = __getcpu() & VGETCPU_CPU_MASK;
-       } while (unlikely(cpu != cpu1 ||
-                         (pvti->pvti.version & 1) ||
-                         pvti->pvti.version != version));
-
-       if (unlikely(!(flags & PVCLOCK_TSC_STABLE_BIT)))
-               *mode = VCLOCK_NONE;
-
-       /* refer to tsc.c read_tsc() comment for rationale */
-       last = gtod->cycle_last;
-
-       if (likely(ret >= last))
-               return ret;
-
-       return last;
-}
-#endif
 
 #else
 
@@ -162,15 +95,77 @@ notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz)
        return ret;
 }
 
+#endif
+
 #ifdef CONFIG_PARAVIRT_CLOCK
+static notrace const struct pvclock_vsyscall_time_info *get_pvti0(void)
+{
+       return (const struct pvclock_vsyscall_time_info *)&pvclock_page;
+}
 
 static notrace cycle_t vread_pvclock(int *mode)
 {
-       *mode = VCLOCK_NONE;
-       return 0;
-}
-#endif
+       const struct pvclock_vcpu_time_info *pvti = &get_pvti0()->pvti;
+       cycle_t ret;
+       u64 tsc, pvti_tsc;
+       u64 last, delta, pvti_system_time;
+       u32 version, pvti_tsc_to_system_mul, pvti_tsc_shift;
+
+       /*
+        * Note: The kernel and hypervisor must guarantee that cpu ID
+        * number maps 1:1 to per-CPU pvclock time info.
+        *
+        * Because the hypervisor is entirely unaware of guest userspace
+        * preemption, it cannot guarantee that per-CPU pvclock time
+        * info is updated if the underlying CPU changes or that that
+        * version is increased whenever underlying CPU changes.
+        *
+        * On KVM, we are guaranteed that pvti updates for any vCPU are
+        * atomic as seen by *all* vCPUs.  This is an even stronger
+        * guarantee than we get with a normal seqlock.
+        *
+        * On Xen, we don't appear to have that guarantee, but Xen still
+        * supplies a valid seqlock using the version field.
+
+        * We only do pvclock vdso timing at all if
+        * PVCLOCK_TSC_STABLE_BIT is set, and we interpret that bit to
+        * mean that all vCPUs have matching pvti and that the TSC is
+        * synced, so we can just look at vCPU 0's pvti.
+        */
 
+       if (unlikely(!(pvti->flags & PVCLOCK_TSC_STABLE_BIT))) {
+               *mode = VCLOCK_NONE;
+               return 0;
+       }
+
+       do {
+               version = pvti->version;
+
+               smp_rmb();
+
+               tsc = rdtsc_ordered();
+               pvti_tsc_to_system_mul = pvti->tsc_to_system_mul;
+               pvti_tsc_shift = pvti->tsc_shift;
+               pvti_system_time = pvti->system_time;
+               pvti_tsc = pvti->tsc_timestamp;
+
+               /* Make sure that the version double-check is last. */
+               smp_rmb();
+       } while (unlikely((version & 1) || version != pvti->version));
+
+       delta = tsc - pvti_tsc;
+       ret = pvti_system_time +
+               pvclock_scale_delta(delta, pvti_tsc_to_system_mul,
+                                   pvti_tsc_shift);
+
+       /* refer to vread_tsc() comment for rationale */
+       last = gtod->cycle_last;
+
+       if (likely(ret >= last))
+               return ret;
+
+       return last;
+}
 #endif
 
 notrace static cycle_t vread_tsc(void)
index de2c921025f5870e9105f5598abc20cc2a7df80a..4158acc17df07c355f0d86e19fd3b4f9b43e590e 100644 (file)
@@ -25,7 +25,7 @@ SECTIONS
         * segment.
         */
 
-       vvar_start = . - 2 * PAGE_SIZE;
+       vvar_start = . - 3 * PAGE_SIZE;
        vvar_page = vvar_start;
 
        /* Place all vvars at the offsets in asm/vvar.h. */
@@ -36,6 +36,7 @@ SECTIONS
 #undef EMIT_VVAR
 
        hpet_page = vvar_start + PAGE_SIZE;
+       pvclock_page = vvar_start + 2 * PAGE_SIZE;
 
        . = SIZEOF_HEADERS;
 
index 785d9922b106317e9285dbcde43417417f4911fb..491020b2826d9d1e3907e14524d9bbea46c2b726 100644 (file)
@@ -73,6 +73,7 @@ enum {
        sym_vvar_start,
        sym_vvar_page,
        sym_hpet_page,
+       sym_pvclock_page,
        sym_VDSO_FAKE_SECTION_TABLE_START,
        sym_VDSO_FAKE_SECTION_TABLE_END,
 };
@@ -80,6 +81,7 @@ enum {
 const int special_pages[] = {
        sym_vvar_page,
        sym_hpet_page,
+       sym_pvclock_page,
 };
 
 struct vdso_sym {
@@ -91,6 +93,7 @@ struct vdso_sym required_syms[] = {
        [sym_vvar_start] = {"vvar_start", true},
        [sym_vvar_page] = {"vvar_page", true},
        [sym_hpet_page] = {"hpet_page", true},
+       [sym_pvclock_page] = {"pvclock_page", true},
        [sym_VDSO_FAKE_SECTION_TABLE_START] = {
                "VDSO_FAKE_SECTION_TABLE_START", false
        },
index 93bd8452383f8e355fcc5743a54947f46ef1a32e..3a1d9297074bc5e1d2e559735bb5247acffa6164 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Code for the vDSO.  This version uses the old int $0x80 method.
+ * AT_SYSINFO entry point
 */
 
 #include <asm/dwarf2.h>
@@ -21,35 +21,67 @@ __kernel_vsyscall:
        /*
         * Reshuffle regs so that all of any of the entry instructions
         * will preserve enough state.
+        *
+        * A really nice entry sequence would be:
+        *  pushl %edx
+        *  pushl %ecx
+        *  movl  %esp, %ecx
+        *
+        * Unfortunately, naughty Android versions between July and December
+        * 2015 actually hardcode the traditional Linux SYSENTER entry
+        * sequence.  That is severely broken for a number of reasons (ask
+        * anyone with an AMD CPU, for example).  Nonetheless, we try to keep
+        * it working approximately as well as it ever worked.
+        *
+        * This link may eludicate some of the history:
+        *   https://android-review.googlesource.com/#/q/Iac3295376d61ef83e713ac9b528f3b50aa780cd7
+        * personally, I find it hard to understand what's going on there.
+        *
+        * Note to future user developers: DO NOT USE SYSENTER IN YOUR CODE.
+        * Execute an indirect call to the address in the AT_SYSINFO auxv
+        * entry.  That is the ONLY correct way to make a fast 32-bit system
+        * call on Linux.  (Open-coding int $0x80 is also fine, but it's
+        * slow.)
         */
+       pushl   %ecx
+       CFI_ADJUST_CFA_OFFSET   4
+       CFI_REL_OFFSET          ecx, 0
        pushl   %edx
        CFI_ADJUST_CFA_OFFSET   4
        CFI_REL_OFFSET          edx, 0
-       pushl   %ecx
+       pushl   %ebp
        CFI_ADJUST_CFA_OFFSET   4
-       CFI_REL_OFFSET          ecx, 0
-       movl    %esp, %ecx
+       CFI_REL_OFFSET          ebp, 0
+
+       #define SYSENTER_SEQUENCE       "movl %esp, %ebp; sysenter"
+       #define SYSCALL_SEQUENCE        "movl %ecx, %ebp; syscall"
 
 #ifdef CONFIG_X86_64
        /* If SYSENTER (Intel) or SYSCALL32 (AMD) is available, use it. */
-       ALTERNATIVE_2 "", "sysenter", X86_FEATURE_SYSENTER32, \
-                         "syscall",  X86_FEATURE_SYSCALL32
+       ALTERNATIVE_2 "", SYSENTER_SEQUENCE, X86_FEATURE_SYSENTER32, \
+                         SYSCALL_SEQUENCE,  X86_FEATURE_SYSCALL32
 #else
-       ALTERNATIVE "", "sysenter", X86_FEATURE_SEP
+       ALTERNATIVE "", SYSENTER_SEQUENCE, X86_FEATURE_SEP
 #endif
 
        /* Enter using int $0x80 */
-       movl    (%esp), %ecx
        int     $0x80
 GLOBAL(int80_landing_pad)
 
-       /* Restore ECX and EDX in case they were clobbered. */
-       popl    %ecx
-       CFI_RESTORE             ecx
+       /*
+        * Restore EDX and ECX in case they were clobbered.  EBP is not
+        * clobbered (the kernel restores it), but it's cleaner and
+        * probably faster to pop it than to adjust ESP using addl.
+        */
+       popl    %ebp
+       CFI_RESTORE             ebp
        CFI_ADJUST_CFA_OFFSET   -4
        popl    %edx
        CFI_RESTORE             edx
        CFI_ADJUST_CFA_OFFSET   -4
+       popl    %ecx
+       CFI_RESTORE             ecx
+       CFI_ADJUST_CFA_OFFSET   -4
        ret
        CFI_ENDPROC
 
index 64df47148160239af2442b93ff4c32de941aa362..b8f69e264ac4148afbdaeedc69e24132980117a9 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/random.h>
 #include <linux/elf.h>
 #include <linux/cpu.h>
+#include <asm/pvclock.h>
 #include <asm/vgtod.h>
 #include <asm/proto.h>
 #include <asm/vdso.h>
@@ -100,6 +101,7 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
                .name = "[vvar]",
                .pages = no_pages,
        };
+       struct pvclock_vsyscall_time_info *pvti;
 
        if (calculate_addr) {
                addr = vdso_addr(current->mm->start_stack,
@@ -169,6 +171,18 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
        }
 #endif
 
+       pvti = pvclock_pvti_cpu0_va();
+       if (pvti && image->sym_pvclock_page) {
+               ret = remap_pfn_range(vma,
+                                     text_start + image->sym_pvclock_page,
+                                     __pa(pvti) >> PAGE_SHIFT,
+                                     PAGE_SIZE,
+                                     PAGE_READONLY);
+
+               if (ret)
+                       goto up_fail;
+       }
+
 up_fail:
        if (ret)
                current->mm->context.vdso = NULL;
index a30316bf801ab9da14753425de67670f71feece0..c80f6b6f3da222dc86dc00747429b618589502eb 100644 (file)
 #define APIC_VERBOSE 1
 #define APIC_DEBUG   2
 
+/* Macros for apic_extnmi which controls external NMI masking */
+#define APIC_EXTNMI_BSP                0 /* Default */
+#define APIC_EXTNMI_ALL                1
+#define APIC_EXTNMI_NONE       2
+
 /*
  * Define the default level of output to be very little
  * This can be turned up by using apic=verbose for more
@@ -303,6 +308,7 @@ struct apic {
                                      unsigned int *apicid);
 
        /* ipi */
+       void (*send_IPI)(int cpu, int vector);
        void (*send_IPI_mask)(const struct cpumask *mask, int vector);
        void (*send_IPI_mask_allbutself)(const struct cpumask *mask,
                                         int vector);
index ae5fb83e6d91c9bf459b02f143a9b583a4515ed7..3e86742881984006555fa433d9988a2c4eaa7b4f 100644 (file)
@@ -3,7 +3,6 @@
 
 #include <linux/compiler.h>
 #include <linux/types.h>
-#include <asm/processor.h>
 #include <asm/alternative.h>
 #include <asm/cmpxchg.h>
 #include <asm/rmwcc.h>
index a11c30b77fb57dfe75b9645ac4f6197d67048e9d..a984111135b16e9c7c51d2cde681aa3b310a6a6b 100644 (file)
@@ -3,7 +3,6 @@
 
 #include <linux/compiler.h>
 #include <linux/types.h>
-#include <asm/processor.h>
 //#include <asm/cmpxchg.h>
 
 /* An 64bit atomic type */
index 0d467b33883544121860305ab7bb7459b98112eb..a8303ebe089f8da9f2ae5d5cd8c870c974468eef 100644 (file)
@@ -31,7 +31,7 @@
 #include <asm/types.h>
 
 struct iommu_table {
-       struct cal_chipset_ops *chip_ops; /* chipset specific funcs */
+       const struct cal_chipset_ops *chip_ops; /* chipset specific funcs */
        unsigned long  it_base;      /* mapped address of tce table */
        unsigned long  it_hint;      /* Hint for next alloc */
        unsigned long *it_map;       /* A simple allocation bitmap for now */
index f7e142926481b6fce09ce3f2d5ddc7f5869b86d8..e4959d023af84857c7b184b1c64d9d715f318a29 100644 (file)
@@ -109,6 +109,6 @@ static inline u64 __cmpxchg64_local(volatile u64 *ptr, u64 old, u64 new)
 
 #endif
 
-#define system_has_cmpxchg_double() cpu_has_cx8
+#define system_has_cmpxchg_double() boot_cpu_has(X86_FEATURE_CX8)
 
 #endif /* _ASM_X86_CMPXCHG_32_H */
index 1af94697aae510fb8eee5699b96895622975f5ec..caa23a34c963ae34e1492c19633c53019d308caf 100644 (file)
@@ -18,6 +18,6 @@ static inline void set_64bit(volatile u64 *ptr, u64 val)
        cmpxchg_local((ptr), (o), (n));                                 \
 })
 
-#define system_has_cmpxchg_double() cpu_has_cx16
+#define system_has_cmpxchg_double() boot_cpu_has(X86_FEATURE_CX16)
 
 #endif /* _ASM_X86_CMPXCHG_64_H */
index bf2caa1dedc5a3e1f9a3854b689d95c68b62b40f..678637ad7476358a8263deee72a84e476912d2f0 100644 (file)
@@ -36,4 +36,7 @@ extern int _debug_hotplug_cpu(int cpu, int action);
 
 int mwait_usable(const struct cpuinfo_x86 *);
 
+unsigned int x86_family(unsigned int sig);
+unsigned int x86_model(unsigned int sig);
+unsigned int x86_stepping(unsigned int sig);
 #endif /* _ASM_X86_CPU_H */
index e4f8010f22e04d2f261bb73bc7745f68f36a392f..7ad8c946429776b6dad30238e9d5e2d65a1a3c87 100644 (file)
@@ -12,7 +12,7 @@
 #include <asm/disabled-features.h>
 #endif
 
-#define NCAPINTS       14      /* N 32-bit words worth of info */
+#define NCAPINTS       16      /* N 32-bit words worth of info */
 #define NBUGINTS       1       /* N 32-bit bug flags */
 
 /*
 
 /*
  * Auxiliary flags: Linux defined - For features scattered in various
- * CPUID levels like 0x6, 0xA etc, word 7
+ * CPUID levels like 0x6, 0xA etc, word 7.
+ *
+ * Reuse free bits when adding new feature flags!
  */
-#define X86_FEATURE_IDA                ( 7*32+ 0) /* Intel Dynamic Acceleration */
-#define X86_FEATURE_ARAT       ( 7*32+ 1) /* Always Running APIC Timer */
+
 #define X86_FEATURE_CPB                ( 7*32+ 2) /* AMD Core Performance Boost */
 #define X86_FEATURE_EPB                ( 7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */
-#define X86_FEATURE_PLN                ( 7*32+ 5) /* Intel Power Limit Notification */
-#define X86_FEATURE_PTS                ( 7*32+ 6) /* Intel Package Thermal Status */
-#define X86_FEATURE_DTHERM     ( 7*32+ 7) /* Digital Thermal Sensor */
+
 #define X86_FEATURE_HW_PSTATE  ( 7*32+ 8) /* AMD HW-PState */
 #define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
-#define X86_FEATURE_HWP                ( 7*32+ 10) /* "hwp" Intel HWP */
-#define X86_FEATURE_HWP_NOTIFY ( 7*32+ 11) /* Intel HWP_NOTIFY */
-#define X86_FEATURE_HWP_ACT_WINDOW ( 7*32+ 12) /* Intel HWP_ACT_WINDOW */
-#define X86_FEATURE_HWP_EPP    ( 7*32+13) /* Intel HWP_EPP */
-#define X86_FEATURE_HWP_PKG_REQ ( 7*32+14) /* Intel HWP_PKG_REQ */
+
 #define X86_FEATURE_INTEL_PT   ( 7*32+15) /* Intel Processor Trace */
 
 /* Virtualization flags: Linux defined, word 8 */
 #define X86_FEATURE_FLEXPRIORITY ( 8*32+ 2) /* Intel FlexPriority */
 #define X86_FEATURE_EPT         ( 8*32+ 3) /* Intel Extended Page Table */
 #define X86_FEATURE_VPID        ( 8*32+ 4) /* Intel Virtual Processor ID */
-#define X86_FEATURE_NPT                ( 8*32+ 5) /* AMD Nested Page Table support */
-#define X86_FEATURE_LBRV       ( 8*32+ 6) /* AMD LBR Virtualization support */
-#define X86_FEATURE_SVML       ( 8*32+ 7) /* "svm_lock" AMD SVM locking MSR */
-#define X86_FEATURE_NRIPS      ( 8*32+ 8) /* "nrip_save" AMD SVM next_rip save */
-#define X86_FEATURE_TSCRATEMSR  ( 8*32+ 9) /* "tsc_scale" AMD TSC scaling support */
-#define X86_FEATURE_VMCBCLEAN   ( 8*32+10) /* "vmcb_clean" AMD VMCB clean bits support */
-#define X86_FEATURE_FLUSHBYASID ( 8*32+11) /* AMD flush-by-ASID support */
-#define X86_FEATURE_DECODEASSISTS ( 8*32+12) /* AMD Decode Assists support */
-#define X86_FEATURE_PAUSEFILTER ( 8*32+13) /* AMD filtered pause intercept */
-#define X86_FEATURE_PFTHRESHOLD ( 8*32+14) /* AMD pause filter threshold */
+
 #define X86_FEATURE_VMMCALL     ( 8*32+15) /* Prefer vmmcall to vmcall */
+#define X86_FEATURE_XENPV       ( 8*32+16) /* "" Xen paravirtual guest */
 
 
 /* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */
 /* AMD-defined CPU features, CPUID level 0x80000008 (ebx), word 13 */
 #define X86_FEATURE_CLZERO     (13*32+0) /* CLZERO instruction */
 
+/* Thermal and Power Management Leaf, CPUID level 0x00000006 (eax), word 14 */
+#define X86_FEATURE_DTHERM     (14*32+ 0) /* Digital Thermal Sensor */
+#define X86_FEATURE_IDA                (14*32+ 1) /* Intel Dynamic Acceleration */
+#define X86_FEATURE_ARAT       (14*32+ 2) /* Always Running APIC Timer */
+#define X86_FEATURE_PLN                (14*32+ 4) /* Intel Power Limit Notification */
+#define X86_FEATURE_PTS                (14*32+ 6) /* Intel Package Thermal Status */
+#define X86_FEATURE_HWP                (14*32+ 7) /* Intel Hardware P-states */
+#define X86_FEATURE_HWP_NOTIFY (14*32+ 8) /* HWP Notification */
+#define X86_FEATURE_HWP_ACT_WINDOW (14*32+ 9) /* HWP Activity Window */
+#define X86_FEATURE_HWP_EPP    (14*32+10) /* HWP Energy Perf. Preference */
+#define X86_FEATURE_HWP_PKG_REQ (14*32+11) /* HWP Package Level Request */
+
+/* AMD SVM Feature Identification, CPUID level 0x8000000a (edx), word 15 */
+#define X86_FEATURE_NPT                (15*32+ 0) /* Nested Page Table support */
+#define X86_FEATURE_LBRV       (15*32+ 1) /* LBR Virtualization support */
+#define X86_FEATURE_SVML       (15*32+ 2) /* "svm_lock" SVM locking MSR */
+#define X86_FEATURE_NRIPS      (15*32+ 3) /* "nrip_save" SVM next_rip save */
+#define X86_FEATURE_TSCRATEMSR  (15*32+ 4) /* "tsc_scale" TSC scaling support */
+#define X86_FEATURE_VMCBCLEAN   (15*32+ 5) /* "vmcb_clean" VMCB clean bits support */
+#define X86_FEATURE_FLUSHBYASID (15*32+ 6) /* flush-by-ASID support */
+#define X86_FEATURE_DECODEASSISTS (15*32+ 7) /* Decode Assists support */
+#define X86_FEATURE_PAUSEFILTER (15*32+10) /* filtered pause intercept */
+#define X86_FEATURE_PFTHRESHOLD (15*32+12) /* pause filter threshold */
+
 /*
  * BUG word(s)
  */
 #include <asm/asm.h>
 #include <linux/bitops.h>
 
+enum cpuid_leafs
+{
+       CPUID_1_EDX             = 0,
+       CPUID_8000_0001_EDX,
+       CPUID_8086_0001_EDX,
+       CPUID_LNX_1,
+       CPUID_1_ECX,
+       CPUID_C000_0001_EDX,
+       CPUID_8000_0001_ECX,
+       CPUID_LNX_2,
+       CPUID_LNX_3,
+       CPUID_7_0_EBX,
+       CPUID_D_1_EAX,
+       CPUID_F_0_EDX,
+       CPUID_F_1_EDX,
+       CPUID_8000_0008_EBX,
+       CPUID_6_EAX,
+       CPUID_8000_000A_EDX,
+};
+
 #ifdef CONFIG_X86_FEATURE_NAMES
 extern const char * const x86_cap_flags[NCAPINTS*32];
 extern const char * const x86_power_flags[32];
@@ -355,60 +386,31 @@ extern const char * const x86_bug_flags[NBUGINTS*32];
 } while (0)
 
 #define cpu_has_fpu            boot_cpu_has(X86_FEATURE_FPU)
-#define cpu_has_de             boot_cpu_has(X86_FEATURE_DE)
 #define cpu_has_pse            boot_cpu_has(X86_FEATURE_PSE)
 #define cpu_has_tsc            boot_cpu_has(X86_FEATURE_TSC)
 #define cpu_has_pge            boot_cpu_has(X86_FEATURE_PGE)
 #define cpu_has_apic           boot_cpu_has(X86_FEATURE_APIC)
-#define cpu_has_sep            boot_cpu_has(X86_FEATURE_SEP)
-#define cpu_has_mtrr           boot_cpu_has(X86_FEATURE_MTRR)
-#define cpu_has_mmx            boot_cpu_has(X86_FEATURE_MMX)
 #define cpu_has_fxsr           boot_cpu_has(X86_FEATURE_FXSR)
 #define cpu_has_xmm            boot_cpu_has(X86_FEATURE_XMM)
 #define cpu_has_xmm2           boot_cpu_has(X86_FEATURE_XMM2)
-#define cpu_has_xmm3           boot_cpu_has(X86_FEATURE_XMM3)
-#define cpu_has_ssse3          boot_cpu_has(X86_FEATURE_SSSE3)
 #define cpu_has_aes            boot_cpu_has(X86_FEATURE_AES)
 #define cpu_has_avx            boot_cpu_has(X86_FEATURE_AVX)
 #define cpu_has_avx2           boot_cpu_has(X86_FEATURE_AVX2)
-#define cpu_has_ht             boot_cpu_has(X86_FEATURE_HT)
-#define cpu_has_nx             boot_cpu_has(X86_FEATURE_NX)
-#define cpu_has_xstore         boot_cpu_has(X86_FEATURE_XSTORE)
-#define cpu_has_xstore_enabled boot_cpu_has(X86_FEATURE_XSTORE_EN)
-#define cpu_has_xcrypt         boot_cpu_has(X86_FEATURE_XCRYPT)
-#define cpu_has_xcrypt_enabled boot_cpu_has(X86_FEATURE_XCRYPT_EN)
-#define cpu_has_ace2           boot_cpu_has(X86_FEATURE_ACE2)
-#define cpu_has_ace2_enabled   boot_cpu_has(X86_FEATURE_ACE2_EN)
-#define cpu_has_phe            boot_cpu_has(X86_FEATURE_PHE)
-#define cpu_has_phe_enabled    boot_cpu_has(X86_FEATURE_PHE_EN)
-#define cpu_has_pmm            boot_cpu_has(X86_FEATURE_PMM)
-#define cpu_has_pmm_enabled    boot_cpu_has(X86_FEATURE_PMM_EN)
-#define cpu_has_ds             boot_cpu_has(X86_FEATURE_DS)
-#define cpu_has_pebs           boot_cpu_has(X86_FEATURE_PEBS)
 #define cpu_has_clflush                boot_cpu_has(X86_FEATURE_CLFLUSH)
-#define cpu_has_bts            boot_cpu_has(X86_FEATURE_BTS)
 #define cpu_has_gbpages                boot_cpu_has(X86_FEATURE_GBPAGES)
 #define cpu_has_arch_perfmon   boot_cpu_has(X86_FEATURE_ARCH_PERFMON)
 #define cpu_has_pat            boot_cpu_has(X86_FEATURE_PAT)
-#define cpu_has_xmm4_1         boot_cpu_has(X86_FEATURE_XMM4_1)
-#define cpu_has_xmm4_2         boot_cpu_has(X86_FEATURE_XMM4_2)
 #define cpu_has_x2apic         boot_cpu_has(X86_FEATURE_X2APIC)
 #define cpu_has_xsave          boot_cpu_has(X86_FEATURE_XSAVE)
-#define cpu_has_xsaveopt       boot_cpu_has(X86_FEATURE_XSAVEOPT)
 #define cpu_has_xsaves         boot_cpu_has(X86_FEATURE_XSAVES)
 #define cpu_has_osxsave                boot_cpu_has(X86_FEATURE_OSXSAVE)
 #define cpu_has_hypervisor     boot_cpu_has(X86_FEATURE_HYPERVISOR)
-#define cpu_has_pclmulqdq      boot_cpu_has(X86_FEATURE_PCLMULQDQ)
-#define cpu_has_perfctr_core   boot_cpu_has(X86_FEATURE_PERFCTR_CORE)
-#define cpu_has_perfctr_nb     boot_cpu_has(X86_FEATURE_PERFCTR_NB)
-#define cpu_has_perfctr_l2     boot_cpu_has(X86_FEATURE_PERFCTR_L2)
-#define cpu_has_cx8            boot_cpu_has(X86_FEATURE_CX8)
-#define cpu_has_cx16           boot_cpu_has(X86_FEATURE_CX16)
-#define cpu_has_eager_fpu      boot_cpu_has(X86_FEATURE_EAGER_FPU)
-#define cpu_has_topoext                boot_cpu_has(X86_FEATURE_TOPOEXT)
-#define cpu_has_bpext          boot_cpu_has(X86_FEATURE_BPEXT)
-
-#if __GNUC__ >= 4
+/*
+ * Do not add any more of those clumsy macros - use static_cpu_has_safe() for
+ * fast paths and boot_cpu_has() otherwise!
+ */
+
+#if __GNUC__ >= 4 && defined(CONFIG_X86_FAST_FEATURE_TESTS)
 extern void warn_pre_alternatives(void);
 extern bool __static_cpu_has_safe(u16 bit);
 
index f80d70009ff873c9c15bc0baaeeb0151b8e6aee8..6d7d0e52ed5a5388b87e834083d90307a6a250ba 100644 (file)
@@ -19,7 +19,6 @@
 #include <asm/acpi.h>
 #include <asm/apicdef.h>
 #include <asm/page.h>
-#include <asm/pvclock.h>
 #ifdef CONFIG_X86_32
 #include <linux/threads.h>
 #include <asm/kmap_types.h>
@@ -72,10 +71,6 @@ enum fixed_addresses {
 #ifdef CONFIG_X86_VSYSCALL_EMULATION
        VSYSCALL_PAGE = (FIXADDR_TOP - VSYSCALL_ADDR) >> PAGE_SHIFT,
 #endif
-#ifdef CONFIG_PARAVIRT_CLOCK
-       PVCLOCK_FIXMAP_BEGIN,
-       PVCLOCK_FIXMAP_END = PVCLOCK_FIXMAP_BEGIN+PVCLOCK_VSYSCALL_NR_PAGES-1,
-#endif
 #endif
        FIX_DBGP_BASE,
        FIX_EARLYCON_MEM_BASE,
index 3c3550c3a4a3f089777a8ff3baf75de49ccb94af..eadcdd5bb9464af38645499004fee0755d6b071f 100644 (file)
@@ -224,18 +224,67 @@ static inline void copy_fxregs_to_kernel(struct fpu *fpu)
 #define XRSTOR         ".byte " REX_PREFIX "0x0f,0xae,0x2f"
 #define XRSTORS                ".byte " REX_PREFIX "0x0f,0xc7,0x1f"
 
-/* xstate instruction fault handler: */
-#define xstate_fault(__err)            \
-                                       \
-       ".section .fixup,\"ax\"\n"      \
-                                       \
-       "3:  movl $-2,%[_err]\n"        \
-       "    jmp  2b\n"                 \
-                                       \
-       ".previous\n"                   \
-                                       \
-       _ASM_EXTABLE(1b, 3b)            \
-       : [_err] "=r" (__err)
+#define XSTATE_OP(op, st, lmask, hmask, err)                           \
+       asm volatile("1:" op "\n\t"                                     \
+                    "xor %[err], %[err]\n"                             \
+                    "2:\n\t"                                           \
+                    ".pushsection .fixup,\"ax\"\n\t"                   \
+                    "3: movl $-2,%[err]\n\t"                           \
+                    "jmp 2b\n\t"                                       \
+                    ".popsection\n\t"                                  \
+                    _ASM_EXTABLE(1b, 3b)                               \
+                    : [err] "=r" (err)                                 \
+                    : "D" (st), "m" (*st), "a" (lmask), "d" (hmask)    \
+                    : "memory")
+
+/*
+ * If XSAVES is enabled, it replaces XSAVEOPT because it supports a compact
+ * format and supervisor states in addition to modified optimization in
+ * XSAVEOPT.
+ *
+ * Otherwise, if XSAVEOPT is enabled, XSAVEOPT replaces XSAVE because XSAVEOPT
+ * supports modified optimization which is not supported by XSAVE.
+ *
+ * We use XSAVE as a fallback.
+ *
+ * The 661 label is defined in the ALTERNATIVE* macros as the address of the
+ * original instruction which gets replaced. We need to use it here as the
+ * address of the instruction where we might get an exception at.
+ */
+#define XSTATE_XSAVE(st, lmask, hmask, err)                            \
+       asm volatile(ALTERNATIVE_2(XSAVE,                               \
+                                  XSAVEOPT, X86_FEATURE_XSAVEOPT,      \
+                                  XSAVES,   X86_FEATURE_XSAVES)        \
+                    "\n"                                               \
+                    "xor %[err], %[err]\n"                             \
+                    "3:\n"                                             \
+                    ".pushsection .fixup,\"ax\"\n"                     \
+                    "4: movl $-2, %[err]\n"                            \
+                    "jmp 3b\n"                                         \
+                    ".popsection\n"                                    \
+                    _ASM_EXTABLE(661b, 4b)                             \
+                    : [err] "=r" (err)                                 \
+                    : "D" (st), "m" (*st), "a" (lmask), "d" (hmask)    \
+                    : "memory")
+
+/*
+ * Use XRSTORS to restore context if it is enabled. XRSTORS supports compact
+ * XSAVE area format.
+ */
+#define XSTATE_XRESTORE(st, lmask, hmask, err)                         \
+       asm volatile(ALTERNATIVE(XRSTOR,                                \
+                                XRSTORS, X86_FEATURE_XSAVES)           \
+                    "\n"                                               \
+                    "xor %[err], %[err]\n"                             \
+                    "3:\n"                                             \
+                    ".pushsection .fixup,\"ax\"\n"                     \
+                    "4: movl $-2, %[err]\n"                            \
+                    "jmp 3b\n"                                         \
+                    ".popsection\n"                                    \
+                    _ASM_EXTABLE(661b, 4b)                             \
+                    : [err] "=r" (err)                                 \
+                    : "D" (st), "m" (*st), "a" (lmask), "d" (hmask)    \
+                    : "memory")
 
 /*
  * This function is called only during boot time when x86 caps are not set
@@ -246,22 +295,14 @@ static inline void copy_xregs_to_kernel_booting(struct xregs_state *xstate)
        u64 mask = -1;
        u32 lmask = mask;
        u32 hmask = mask >> 32;
-       int err = 0;
+       int err;
 
        WARN_ON(system_state != SYSTEM_BOOTING);
 
-       if (boot_cpu_has(X86_FEATURE_XSAVES))
-               asm volatile("1:"XSAVES"\n\t"
-                       "2:\n\t"
-                            xstate_fault(err)
-                       : "D" (xstate), "m" (*xstate), "a" (lmask), "d" (hmask), "0" (err)
-                       : "memory");
+       if (static_cpu_has_safe(X86_FEATURE_XSAVES))
+               XSTATE_OP(XSAVES, xstate, lmask, hmask, err);
        else
-               asm volatile("1:"XSAVE"\n\t"
-                       "2:\n\t"
-                            xstate_fault(err)
-                       : "D" (xstate), "m" (*xstate), "a" (lmask), "d" (hmask), "0" (err)
-                       : "memory");
+               XSTATE_OP(XSAVE, xstate, lmask, hmask, err);
 
        /* We should never fault when copying to a kernel buffer: */
        WARN_ON_FPU(err);
@@ -276,22 +317,14 @@ static inline void copy_kernel_to_xregs_booting(struct xregs_state *xstate)
        u64 mask = -1;
        u32 lmask = mask;
        u32 hmask = mask >> 32;
-       int err = 0;
+       int err;
 
        WARN_ON(system_state != SYSTEM_BOOTING);
 
-       if (boot_cpu_has(X86_FEATURE_XSAVES))
-               asm volatile("1:"XRSTORS"\n\t"
-                       "2:\n\t"
-                            xstate_fault(err)
-                       : "D" (xstate), "m" (*xstate), "a" (lmask), "d" (hmask), "0" (err)
-                       : "memory");
+       if (static_cpu_has_safe(X86_FEATURE_XSAVES))
+               XSTATE_OP(XRSTORS, xstate, lmask, hmask, err);
        else
-               asm volatile("1:"XRSTOR"\n\t"
-                       "2:\n\t"
-                            xstate_fault(err)
-                       : "D" (xstate), "m" (*xstate), "a" (lmask), "d" (hmask), "0" (err)
-                       : "memory");
+               XSTATE_OP(XRSTOR, xstate, lmask, hmask, err);
 
        /* We should never fault when copying from a kernel buffer: */
        WARN_ON_FPU(err);
@@ -305,33 +338,11 @@ static inline void copy_xregs_to_kernel(struct xregs_state *xstate)
        u64 mask = -1;
        u32 lmask = mask;
        u32 hmask = mask >> 32;
-       int err = 0;
+       int err;
 
        WARN_ON(!alternatives_patched);
 
-       /*
-        * If xsaves is enabled, xsaves replaces xsaveopt because
-        * it supports compact format and supervisor states in addition to
-        * modified optimization in xsaveopt.
-        *
-        * Otherwise, if xsaveopt is enabled, xsaveopt replaces xsave
-        * because xsaveopt supports modified optimization which is not
-        * supported by xsave.
-        *
-        * If none of xsaves and xsaveopt is enabled, use xsave.
-        */
-       alternative_input_2(
-               "1:"XSAVE,
-               XSAVEOPT,
-               X86_FEATURE_XSAVEOPT,
-               XSAVES,
-               X86_FEATURE_XSAVES,
-               [xstate] "D" (xstate), "a" (lmask), "d" (hmask) :
-               "memory");
-       asm volatile("2:\n\t"
-                    xstate_fault(err)
-                    : "0" (err)
-                    : "memory");
+       XSTATE_XSAVE(xstate, lmask, hmask, err);
 
        /* We should never fault when copying to a kernel buffer: */
        WARN_ON_FPU(err);
@@ -344,23 +355,9 @@ static inline void copy_kernel_to_xregs(struct xregs_state *xstate, u64 mask)
 {
        u32 lmask = mask;
        u32 hmask = mask >> 32;
-       int err = 0;
+       int err;
 
-       /*
-        * Use xrstors to restore context if it is enabled. xrstors supports
-        * compacted format of xsave area which is not supported by xrstor.
-        */
-       alternative_input(
-               "1: " XRSTOR,
-               XRSTORS,
-               X86_FEATURE_XSAVES,
-               "D" (xstate), "m" (*xstate), "a" (lmask), "d" (hmask)
-               : "memory");
-
-       asm volatile("2:\n"
-                    xstate_fault(err)
-                    : "0" (err)
-                    : "memory");
+       XSTATE_XRESTORE(xstate, lmask, hmask, err);
 
        /* We should never fault when copying from a kernel buffer: */
        WARN_ON_FPU(err);
@@ -388,12 +385,10 @@ static inline int copy_xregs_to_user(struct xregs_state __user *buf)
        if (unlikely(err))
                return -EFAULT;
 
-       __asm__ __volatile__(ASM_STAC "\n"
-                            "1:"XSAVE"\n"
-                            "2: " ASM_CLAC "\n"
-                            xstate_fault(err)
-                            : "D" (buf), "a" (-1), "d" (-1), "0" (err)
-                            : "memory");
+       stac();
+       XSTATE_OP(XSAVE, buf, -1, -1, err);
+       clac();
+
        return err;
 }
 
@@ -405,14 +400,12 @@ static inline int copy_user_to_xregs(struct xregs_state __user *buf, u64 mask)
        struct xregs_state *xstate = ((__force struct xregs_state *)buf);
        u32 lmask = mask;
        u32 hmask = mask >> 32;
-       int err = 0;
-
-       __asm__ __volatile__(ASM_STAC "\n"
-                            "1:"XRSTOR"\n"
-                            "2: " ASM_CLAC "\n"
-                            xstate_fault(err)
-                            : "D" (xstate), "a" (lmask), "d" (hmask), "0" (err)
-                            : "memory");       /* memory required? */
+       int err;
+
+       stac();
+       XSTATE_OP(XRSTOR, xstate, lmask, hmask, err);
+       clac();
+
        return err;
 }
 
diff --git a/arch/x86/include/asm/intel_pt.h b/arch/x86/include/asm/intel_pt.h
new file mode 100644 (file)
index 0000000..e1a4117
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _ASM_X86_INTEL_PT_H
+#define _ASM_X86_INTEL_PT_H
+
+#if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_INTEL)
+void cpu_emergency_stop_pt(void);
+#else
+static inline void cpu_emergency_stop_pt(void) {}
+#endif
+
+#endif /* _ASM_X86_INTEL_PT_H */
index 615fa9061b57cde4f8cdb10ac574904eec6e1147..cfc9a0d2d07ce4b6d2bf2a3dc1aa623114eb11bb 100644 (file)
@@ -119,6 +119,8 @@ static inline void
        native_apic_mem_write(APIC_ICR, cfg);
 }
 
+extern void default_send_IPI_single(int cpu, int vector);
+extern void default_send_IPI_single_phys(int cpu, int vector);
 extern void default_send_IPI_mask_sequence_phys(const struct cpumask *mask,
                                                 int vector);
 extern void default_send_IPI_mask_allbutself_phys(const struct cpumask *mask,
index 5daeca3d0f9e5b04d69a183dbe06e2c68fe9c0bb..adc54c12cbd15650fee002cff6d773de7f15429e 100644 (file)
@@ -1,12 +1,18 @@
 #ifndef _ASM_X86_JUMP_LABEL_H
 #define _ASM_X86_JUMP_LABEL_H
 
-#ifndef __ASSEMBLY__
-
-#include <linux/stringify.h>
-#include <linux/types.h>
-#include <asm/nops.h>
-#include <asm/asm.h>
+#ifndef HAVE_JUMP_LABEL
+/*
+ * For better or for worse, if jump labels (the gcc extension) are missing,
+ * then the entire static branch patching infrastructure is compiled out.
+ * If that happens, the code in here will malfunction.  Raise a compiler
+ * error instead.
+ *
+ * In theory, jump labels and the static branch patching infrastructure
+ * could be decoupled to fix this.
+ */
+#error asm/jump_label.h included on a non-jump-label kernel
+#endif
 
 #define JUMP_LABEL_NOP_SIZE 5
 
 # define STATIC_KEY_INIT_NOP GENERIC_NOP5_ATOMIC
 #endif
 
+#include <asm/asm.h>
+#include <asm/nops.h>
+
+#ifndef __ASSEMBLY__
+
+#include <linux/stringify.h>
+#include <linux/types.h>
+
 static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
 {
        asm_volatile_goto("1:"
@@ -59,5 +73,40 @@ struct jump_entry {
        jump_label_t key;
 };
 
-#endif  /* __ASSEMBLY__ */
+#else  /* __ASSEMBLY__ */
+
+.macro STATIC_JUMP_IF_TRUE target, key, def
+.Lstatic_jump_\@:
+       .if \def
+       /* Equivalent to "jmp.d32 \target" */
+       .byte           0xe9
+       .long           \target - .Lstatic_jump_after_\@
+.Lstatic_jump_after_\@:
+       .else
+       .byte           STATIC_KEY_INIT_NOP
+       .endif
+       .pushsection __jump_table, "aw"
+       _ASM_ALIGN
+       _ASM_PTR        .Lstatic_jump_\@, \target, \key
+       .popsection
+.endm
+
+.macro STATIC_JUMP_IF_FALSE target, key, def
+.Lstatic_jump_\@:
+       .if \def
+       .byte           STATIC_KEY_INIT_NOP
+       .else
+       /* Equivalent to "jmp.d32 \target" */
+       .byte           0xe9
+       .long           \target - .Lstatic_jump_after_\@
+.Lstatic_jump_after_\@:
+       .endif
+       .pushsection __jump_table, "aw"
+       _ASM_ALIGN
+       _ASM_PTR        .Lstatic_jump_\@, \target, \key + 1
+       .popsection
+.endm
+
+#endif /* __ASSEMBLY__ */
+
 #endif
index 30cfd64295a0075ab9c4727721c0fc8c8b607f46..44adbb81904184da0cbbab08807075a24918ba28 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/pvclock_gtod.h>
 #include <linux/clocksource.h>
 #include <linux/irqbypass.h>
+#include <linux/hyperv.h>
 
 #include <asm/pvclock-abi.h>
 #include <asm/desc.h>
 
 #define KVM_IRQCHIP_NUM_PINS  KVM_IOAPIC_NUM_PINS
 
+/* x86-specific vcpu->requests bit members */
+#define KVM_REQ_MIGRATE_TIMER      8
+#define KVM_REQ_REPORT_TPR_ACCESS  9
+#define KVM_REQ_TRIPLE_FAULT      10
+#define KVM_REQ_MMU_SYNC          11
+#define KVM_REQ_CLOCK_UPDATE      12
+#define KVM_REQ_DEACTIVATE_FPU    13
+#define KVM_REQ_EVENT             14
+#define KVM_REQ_APF_HALT          15
+#define KVM_REQ_STEAL_UPDATE      16
+#define KVM_REQ_NMI               17
+#define KVM_REQ_PMU               18
+#define KVM_REQ_PMI               19
+#define KVM_REQ_SMI               20
+#define KVM_REQ_MASTERCLOCK_UPDATE 21
+#define KVM_REQ_MCLOCK_INPROGRESS 22
+#define KVM_REQ_SCAN_IOAPIC       23
+#define KVM_REQ_GLOBAL_CLOCK_UPDATE 24
+#define KVM_REQ_APIC_PAGE_RELOAD  25
+#define KVM_REQ_HV_CRASH          26
+#define KVM_REQ_IOAPIC_EOI_EXIT   27
+#define KVM_REQ_HV_RESET          28
+#define KVM_REQ_HV_EXIT           29
+#define KVM_REQ_HV_STIMER         30
+
 #define CR0_RESERVED_BITS                                               \
        (~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \
                          | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM \
@@ -213,6 +239,10 @@ union kvm_mmu_page_role {
        };
 };
 
+struct kvm_rmap_head {
+       unsigned long val;
+};
+
 struct kvm_mmu_page {
        struct list_head link;
        struct hlist_node hash_link;
@@ -230,7 +260,7 @@ struct kvm_mmu_page {
        bool unsync;
        int root_count;          /* Currently serving as active root */
        unsigned int unsync_children;
-       unsigned long parent_ptes;      /* Reverse mapping for parent_pte */
+       struct kvm_rmap_head parent_ptes; /* rmap pointers to parent sptes */
 
        /* The page is obsolete if mmu_valid_gen != kvm->arch.mmu_valid_gen.  */
        unsigned long mmu_valid_gen;
@@ -374,10 +404,38 @@ struct kvm_mtrr {
        struct list_head head;
 };
 
+/* Hyper-V SynIC timer */
+struct kvm_vcpu_hv_stimer {
+       struct hrtimer timer;
+       int index;
+       u64 config;
+       u64 count;
+       u64 exp_time;
+       struct hv_message msg;
+       bool msg_pending;
+};
+
+/* Hyper-V synthetic interrupt controller (SynIC)*/
+struct kvm_vcpu_hv_synic {
+       u64 version;
+       u64 control;
+       u64 msg_page;
+       u64 evt_page;
+       atomic64_t sint[HV_SYNIC_SINT_COUNT];
+       atomic_t sint_to_gsi[HV_SYNIC_SINT_COUNT];
+       DECLARE_BITMAP(auto_eoi_bitmap, 256);
+       DECLARE_BITMAP(vec_bitmap, 256);
+       bool active;
+};
+
 /* Hyper-V per vcpu emulation context */
 struct kvm_vcpu_hv {
        u64 hv_vapic;
        s64 runtime_offset;
+       struct kvm_vcpu_hv_synic synic;
+       struct kvm_hyperv_exit exit;
+       struct kvm_vcpu_hv_stimer stimer[HV_SYNIC_STIMER_COUNT];
+       DECLARE_BITMAP(stimer_pending_bitmap, HV_SYNIC_STIMER_COUNT);
 };
 
 struct kvm_vcpu_arch {
@@ -400,7 +458,8 @@ struct kvm_vcpu_arch {
        u64 efer;
        u64 apic_base;
        struct kvm_lapic *apic;    /* kernel irqchip context */
-       u64 eoi_exit_bitmap[4];
+       bool apicv_active;
+       DECLARE_BITMAP(ioapic_handled_vectors, 256);
        unsigned long apic_attention;
        int32_t apic_arb_prio;
        int mp_state;
@@ -589,7 +648,7 @@ struct kvm_lpage_info {
 };
 
 struct kvm_arch_memory_slot {
-       unsigned long *rmap[KVM_NR_PAGE_SIZES];
+       struct kvm_rmap_head *rmap[KVM_NR_PAGE_SIZES];
        struct kvm_lpage_info *lpage_info[KVM_NR_PAGE_SIZES - 1];
 };
 
@@ -831,10 +890,11 @@ struct kvm_x86_ops {
        void (*enable_nmi_window)(struct kvm_vcpu *vcpu);
        void (*enable_irq_window)(struct kvm_vcpu *vcpu);
        void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr);
-       int (*cpu_uses_apicv)(struct kvm_vcpu *vcpu);
+       bool (*get_enable_apicv)(void);
+       void (*refresh_apicv_exec_ctrl)(struct kvm_vcpu *vcpu);
        void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr);
        void (*hwapic_isr_update)(struct kvm *kvm, int isr);
-       void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu);
+       void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
        void (*set_virtual_x2apic_mode)(struct kvm_vcpu *vcpu, bool set);
        void (*set_apic_access_page_addr)(struct kvm_vcpu *vcpu, hpa_t hpa);
        void (*deliver_posted_interrupt)(struct kvm_vcpu *vcpu, int vector);
@@ -1086,6 +1146,8 @@ gpa_t kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva,
 gpa_t kvm_mmu_gva_to_gpa_system(struct kvm_vcpu *vcpu, gva_t gva,
                                struct x86_exception *exception);
 
+void kvm_vcpu_deactivate_apicv(struct kvm_vcpu *vcpu);
+
 int kvm_emulate_hypercall(struct kvm_vcpu *vcpu);
 
 int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code,
@@ -1231,6 +1293,9 @@ u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc);
 unsigned long kvm_get_linear_rip(struct kvm_vcpu *vcpu);
 bool kvm_is_linear_rip(struct kvm_vcpu *vcpu, unsigned long linear_rip);
 
+void kvm_make_mclock_inprogress_request(struct kvm *kvm);
+void kvm_make_scan_ioapic_request(struct kvm *kvm);
+
 void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
                                     struct kvm_async_pf *work);
 void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
index 34e62b1dcfce46a606fbe78d7d55131513d859d3..1e1b07a5a7388d45eaaf46e032efd8ee14569662 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _ASM_X86_MICROCODE_H
 #define _ASM_X86_MICROCODE_H
 
+#include <asm/cpu.h>
 #include <linux/earlycpio.h>
 
 #define native_rdmsr(msr, val1, val2)                  \
@@ -95,14 +96,14 @@ static inline void __exit exit_amd_microcode(void) {}
 
 /*
  * In early loading microcode phase on BSP, boot_cpu_data is not set up yet.
- * x86_vendor() gets vendor id for BSP.
+ * x86_cpuid_vendor() gets vendor id for BSP.
  *
  * In 32 bit AP case, accessing boot_cpu_data needs linear address. To simplify
- * coding, we still use x86_vendor() to get vendor id for AP.
+ * coding, we still use x86_cpuid_vendor() to get vendor id for AP.
  *
- * x86_vendor() gets vendor information directly from CPUID.
+ * x86_cpuid_vendor() gets vendor information directly from CPUID.
  */
-static inline int x86_vendor(void)
+static inline int x86_cpuid_vendor(void)
 {
        u32 eax = 0x00000000;
        u32 ebx, ecx = 0, edx;
@@ -118,40 +119,14 @@ static inline int x86_vendor(void)
        return X86_VENDOR_UNKNOWN;
 }
 
-static inline unsigned int __x86_family(unsigned int sig)
-{
-       unsigned int x86;
-
-       x86 = (sig >> 8) & 0xf;
-
-       if (x86 == 0xf)
-               x86 += (sig >> 20) & 0xff;
-
-       return x86;
-}
-
-static inline unsigned int x86_family(void)
+static inline unsigned int x86_cpuid_family(void)
 {
        u32 eax = 0x00000001;
        u32 ebx, ecx = 0, edx;
 
        native_cpuid(&eax, &ebx, &ecx, &edx);
 
-       return __x86_family(eax);
-}
-
-static inline unsigned int x86_model(unsigned int sig)
-{
-       unsigned int x86, model;
-
-       x86 = __x86_family(sig);
-
-       model = (sig >> 4) & 0xf;
-
-       if (x86 == 0x6 || x86 == 0xf)
-               model += ((sig >> 16) & 0xf) << 4;
-
-       return model;
+       return x86_family(eax);
 }
 
 #ifdef CONFIG_MICROCODE
index 93724cc6217763c29386f5afd350c070df512e85..eb4b09b41df50c0a1bf3213f6cc07844b674bfc0 100644 (file)
@@ -1,7 +1,13 @@
 #ifndef _ASM_X86_MSI_H
 #define _ASM_X86_MSI_H
 #include <asm/hw_irq.h>
+#include <asm/irqdomain.h>
 
 typedef struct irq_alloc_info msi_alloc_info_t;
 
+int pci_msi_prepare(struct irq_domain *domain, struct device *dev, int nvec,
+                   msi_alloc_info_t *arg);
+
+void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc);
+
 #endif /* _ASM_X86_MSI_H */
index 690b4027e17c994fdef4a626f270ca8b97ee041a..b05402ef3b842203f97def484806bec3c2320b9c 100644 (file)
 #define MSR_F15H_PERF_CTR              0xc0010201
 #define MSR_F15H_NB_PERF_CTL           0xc0010240
 #define MSR_F15H_NB_PERF_CTR           0xc0010241
+#define MSR_F15H_IC_CFG                        0xc0011021
 
 /* Fam 10h MSRs */
 #define MSR_FAM10H_MMIO_CONF_BASE      0xc0010058
diff --git a/arch/x86/include/asm/msr-trace.h b/arch/x86/include/asm/msr-trace.h
new file mode 100644 (file)
index 0000000..7567225
--- /dev/null
@@ -0,0 +1,57 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM msr
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE msr-trace
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH asm/
+
+#if !defined(_TRACE_MSR_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_MSR_H
+
+#include <linux/tracepoint.h>
+
+/*
+ * Tracing for x86 model specific registers. Directly maps to the
+ * RDMSR/WRMSR instructions.
+ */
+
+DECLARE_EVENT_CLASS(msr_trace_class,
+           TP_PROTO(unsigned msr, u64 val, int failed),
+           TP_ARGS(msr, val, failed),
+           TP_STRUCT__entry(
+                   __field(    unsigned,       msr )
+                   __field(    u64,            val )
+                   __field(    int,            failed )
+           ),
+           TP_fast_assign(
+                   __entry->msr = msr;
+                   __entry->val = val;
+                   __entry->failed = failed;
+           ),
+           TP_printk("%x, value %llx%s",
+                     __entry->msr,
+                     __entry->val,
+                     __entry->failed ? " #GP" : "")
+);
+
+DEFINE_EVENT(msr_trace_class, read_msr,
+            TP_PROTO(unsigned msr, u64 val, int failed),
+            TP_ARGS(msr, val, failed)
+);
+
+DEFINE_EVENT(msr_trace_class, write_msr,
+            TP_PROTO(unsigned msr, u64 val, int failed),
+            TP_ARGS(msr, val, failed)
+);
+
+DEFINE_EVENT(msr_trace_class, rdpmc,
+            TP_PROTO(unsigned msr, u64 val, int failed),
+            TP_ARGS(msr, val, failed)
+);
+
+#endif /* _TRACE_MSR_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index 77d8b284e4a713d95423b83b8172061c31a12321..93fb7c1cffda7a03e8e0248f634e86eb78e3ff3d 100644 (file)
@@ -32,6 +32,16 @@ struct msr_regs_info {
        int err;
 };
 
+struct saved_msr {
+       bool valid;
+       struct msr_info info;
+};
+
+struct saved_msrs {
+       unsigned int num;
+       struct saved_msr *array;
+};
+
 static inline unsigned long long native_read_tscp(unsigned int *aux)
 {
        unsigned long low, high;
@@ -57,11 +67,34 @@ static inline unsigned long long native_read_tscp(unsigned int *aux)
 #define EAX_EDX_RET(val, low, high)    "=A" (val)
 #endif
 
+#ifdef CONFIG_TRACEPOINTS
+/*
+ * Be very careful with includes. This header is prone to include loops.
+ */
+#include <asm/atomic.h>
+#include <linux/tracepoint-defs.h>
+
+extern struct tracepoint __tracepoint_read_msr;
+extern struct tracepoint __tracepoint_write_msr;
+extern struct tracepoint __tracepoint_rdpmc;
+#define msr_tracepoint_active(t) static_key_false(&(t).key)
+extern void do_trace_write_msr(unsigned msr, u64 val, int failed);
+extern void do_trace_read_msr(unsigned msr, u64 val, int failed);
+extern void do_trace_rdpmc(unsigned msr, u64 val, int failed);
+#else
+#define msr_tracepoint_active(t) false
+static inline void do_trace_write_msr(unsigned msr, u64 val, int failed) {}
+static inline void do_trace_read_msr(unsigned msr, u64 val, int failed) {}
+static inline void do_trace_rdpmc(unsigned msr, u64 val, int failed) {}
+#endif
+
 static inline unsigned long long native_read_msr(unsigned int msr)
 {
        DECLARE_ARGS(val, low, high);
 
        asm volatile("rdmsr" : EAX_EDX_RET(val, low, high) : "c" (msr));
+       if (msr_tracepoint_active(__tracepoint_read_msr))
+               do_trace_read_msr(msr, EAX_EDX_VAL(val, low, high), 0);
        return EAX_EDX_VAL(val, low, high);
 }
 
@@ -78,6 +111,8 @@ static inline unsigned long long native_read_msr_safe(unsigned int msr,
                     _ASM_EXTABLE(2b, 3b)
                     : [err] "=r" (*err), EAX_EDX_RET(val, low, high)
                     : "c" (msr), [fault] "i" (-EIO));
+       if (msr_tracepoint_active(__tracepoint_read_msr))
+               do_trace_read_msr(msr, EAX_EDX_VAL(val, low, high), *err);
        return EAX_EDX_VAL(val, low, high);
 }
 
@@ -85,6 +120,8 @@ static inline void native_write_msr(unsigned int msr,
                                    unsigned low, unsigned high)
 {
        asm volatile("wrmsr" : : "c" (msr), "a"(low), "d" (high) : "memory");
+       if (msr_tracepoint_active(__tracepoint_read_msr))
+               do_trace_write_msr(msr, ((u64)high << 32 | low), 0);
 }
 
 /* Can be uninlined because referenced by paravirt */
@@ -102,6 +139,8 @@ notrace static inline int native_write_msr_safe(unsigned int msr,
                     : "c" (msr), "0" (low), "d" (high),
                       [fault] "i" (-EIO)
                     : "memory");
+       if (msr_tracepoint_active(__tracepoint_read_msr))
+               do_trace_write_msr(msr, ((u64)high << 32 | low), err);
        return err;
 }
 
@@ -160,6 +199,8 @@ static inline unsigned long long native_read_pmc(int counter)
        DECLARE_ARGS(val, low, high);
 
        asm volatile("rdpmc" : EAX_EDX_RET(val, low, high) : "c" (counter));
+       if (msr_tracepoint_active(__tracepoint_rdpmc))
+               do_trace_rdpmc(counter, EAX_EDX_VAL(val, low, high), 0);
        return EAX_EDX_VAL(val, low, high);
 }
 
@@ -190,7 +231,7 @@ static inline void wrmsr(unsigned msr, unsigned low, unsigned high)
 
 static inline void wrmsrl(unsigned msr, u64 val)
 {
-       native_write_msr(msr, (u32)val, (u32)(val >> 32));
+       native_write_msr(msr, (u32)(val & 0xffffffffULL), (u32)(val >> 32));
 }
 
 /* wrmsr with exception handling */
index cc071c6f7d4da2847b3df2c4cbf7666edde5675b..7bd0099384cac4ed0fa89a4e25c42e4a63ae5f9c 100644 (file)
@@ -5,9 +5,9 @@
 #include <linux/types.h>
 
 /* PAGE_SHIFT determines the page size */
-#define PAGE_SHIFT     12
-#define PAGE_SIZE      (_AC(1,UL) << PAGE_SHIFT)
-#define PAGE_MASK      (~(PAGE_SIZE-1))
+#define PAGE_SHIFT             12
+#define PAGE_SIZE              (_AC(1,UL) << PAGE_SHIFT)
+#define PAGE_MASK              (~(PAGE_SIZE-1))
 
 #define PMD_PAGE_SIZE          (_AC(1, UL) << PMD_SHIFT)
 #define PMD_PAGE_MASK          (~(PMD_PAGE_SIZE-1))
index 10d0596433f89b849f91c164d7252a29bcac921b..f6192502149e58064aa75950d4bb361db54c58f2 100644 (file)
@@ -19,6 +19,12 @@ static inline int paravirt_enabled(void)
        return pv_info.paravirt_enabled;
 }
 
+static inline int paravirt_has_feature(unsigned int feature)
+{
+       WARN_ON_ONCE(!pv_info.paravirt_enabled);
+       return (pv_info.features & feature);
+}
+
 static inline void load_sp0(struct tss_struct *tss,
                             struct thread_struct *thread)
 {
@@ -285,15 +291,6 @@ static inline void slow_down_io(void)
 #endif
 }
 
-#ifdef CONFIG_SMP
-static inline void startup_ipi_hook(int phys_apicid, unsigned long start_eip,
-                                   unsigned long start_esp)
-{
-       PVOP_VCALL3(pv_apic_ops.startup_ipi_hook,
-                   phys_apicid, start_eip, start_esp);
-}
-#endif
-
 static inline void paravirt_activate_mm(struct mm_struct *prev,
                                        struct mm_struct *next)
 {
@@ -375,23 +372,6 @@ static inline void pte_update(struct mm_struct *mm, unsigned long addr,
 {
        PVOP_VCALL3(pv_mmu_ops.pte_update, mm, addr, ptep);
 }
-static inline void pmd_update(struct mm_struct *mm, unsigned long addr,
-                             pmd_t *pmdp)
-{
-       PVOP_VCALL3(pv_mmu_ops.pmd_update, mm, addr, pmdp);
-}
-
-static inline void pte_update_defer(struct mm_struct *mm, unsigned long addr,
-                                   pte_t *ptep)
-{
-       PVOP_VCALL3(pv_mmu_ops.pte_update_defer, mm, addr, ptep);
-}
-
-static inline void pmd_update_defer(struct mm_struct *mm, unsigned long addr,
-                                   pmd_t *pmdp)
-{
-       PVOP_VCALL3(pv_mmu_ops.pmd_update_defer, mm, addr, pmdp);
-}
 
 static inline pte_t __pte(pteval_t val)
 {
@@ -922,23 +902,11 @@ extern void default_banner(void);
                  call PARA_INDIRECT(pv_irq_ops+PV_IRQ_irq_enable);     \
                  PV_RESTORE_REGS(clobbers | CLBR_CALLEE_SAVE);)
 
-#define USERGS_SYSRET32                                                        \
-       PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_usergs_sysret32),       \
-                 CLBR_NONE,                                            \
-                 jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_usergs_sysret32))
-
 #ifdef CONFIG_X86_32
 #define GET_CR0_INTO_EAX                               \
        push %ecx; push %edx;                           \
        call PARA_INDIRECT(pv_cpu_ops+PV_CPU_read_cr0); \
        pop %edx; pop %ecx
-
-#define ENABLE_INTERRUPTS_SYSEXIT                                      \
-       PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_irq_enable_sysexit),    \
-                 CLBR_NONE,                                            \
-                 jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_irq_enable_sysexit))
-
-
 #else  /* !CONFIG_X86_32 */
 
 /*
index 31247b5bff7c8ff86d893851dc9073b72a647cc2..77db5616a4739703ddf0edb2f7b10f10f67d4552 100644 (file)
@@ -70,9 +70,14 @@ struct pv_info {
 #endif
 
        int paravirt_enabled;
+       unsigned int features;    /* valid only if paravirt_enabled is set */
        const char *name;
 };
 
+#define paravirt_has(x) paravirt_has_feature(PV_SUPPORTED_##x)
+/* Supported features */
+#define PV_SUPPORTED_RTC        (1<<0)
+
 struct pv_init_ops {
        /*
         * Patch may replace one of the defined code sequences with
@@ -157,15 +162,6 @@ struct pv_cpu_ops {
 
        u64 (*read_pmc)(int counter);
 
-#ifdef CONFIG_X86_32
-       /*
-        * Atomically enable interrupts and return to userspace.  This
-        * is only used in 32-bit kernels.  64-bit kernels use
-        * usergs_sysret32 instead.
-        */
-       void (*irq_enable_sysexit)(void);
-#endif
-
        /*
         * Switch to usermode gs and return to 64-bit usermode using
         * sysret.  Only used in 64-bit kernels to return to 64-bit
@@ -174,14 +170,6 @@ struct pv_cpu_ops {
         */
        void (*usergs_sysret64)(void);
 
-       /*
-        * Switch to usermode gs and return to 32-bit usermode using
-        * sysret.  Used to return to 32-on-64 compat processes.
-        * Other usermode register state, including %esp, must already
-        * be restored.
-        */
-       void (*usergs_sysret32)(void);
-
        /* Normal iret.  Jump to this with the standard iret stack
           frame set up. */
        void (*iret)(void);
@@ -215,14 +203,6 @@ struct pv_irq_ops {
 #endif
 };
 
-struct pv_apic_ops {
-#ifdef CONFIG_X86_LOCAL_APIC
-       void (*startup_ipi_hook)(int phys_apicid,
-                                unsigned long start_eip,
-                                unsigned long start_esp);
-#endif
-};
-
 struct pv_mmu_ops {
        unsigned long (*read_cr2)(void);
        void (*write_cr2)(unsigned long);
@@ -274,12 +254,6 @@ struct pv_mmu_ops {
                           pmd_t *pmdp, pmd_t pmdval);
        void (*pte_update)(struct mm_struct *mm, unsigned long addr,
                           pte_t *ptep);
-       void (*pte_update_defer)(struct mm_struct *mm,
-                                unsigned long addr, pte_t *ptep);
-       void (*pmd_update)(struct mm_struct *mm, unsigned long addr,
-                          pmd_t *pmdp);
-       void (*pmd_update_defer)(struct mm_struct *mm,
-                                unsigned long addr, pmd_t *pmdp);
 
        pte_t (*ptep_modify_prot_start)(struct mm_struct *mm, unsigned long addr,
                                        pte_t *ptep);
@@ -354,7 +328,6 @@ struct paravirt_patch_template {
        struct pv_time_ops pv_time_ops;
        struct pv_cpu_ops pv_cpu_ops;
        struct pv_irq_ops pv_irq_ops;
-       struct pv_apic_ops pv_apic_ops;
        struct pv_mmu_ops pv_mmu_ops;
        struct pv_lock_ops pv_lock_ops;
 };
@@ -364,7 +337,6 @@ extern struct pv_init_ops pv_init_ops;
 extern struct pv_time_ops pv_time_ops;
 extern struct pv_cpu_ops pv_cpu_ops;
 extern struct pv_irq_ops pv_irq_ops;
-extern struct pv_apic_ops pv_apic_ops;
 extern struct pv_mmu_ops pv_mmu_ops;
 extern struct pv_lock_ops pv_lock_ops;
 
@@ -402,10 +374,8 @@ extern struct pv_lock_ops pv_lock_ops;
        __visible extern const char start_##ops##_##name[], end_##ops##_##name[];       \
        asm(NATIVE_LABEL("start_", ops, name) code NATIVE_LABEL("end_", ops, name))
 
-unsigned paravirt_patch_nop(void);
 unsigned paravirt_patch_ident_32(void *insnbuf, unsigned len);
 unsigned paravirt_patch_ident_64(void *insnbuf, unsigned len);
-unsigned paravirt_patch_ignore(unsigned len);
 unsigned paravirt_patch_call(void *insnbuf,
                             const void *target, u16 tgt_clobbers,
                             unsigned long addr, u16 site_clobbers,
index 6ec0c8b2e9df5b1d4c7702fd7f1d96c2c24db5d4..d3eee663c41fccdf031e0f72f9847b6a26f493cf 100644 (file)
@@ -69,9 +69,6 @@ extern struct mm_struct *pgd_page_get_mm(struct page *page);
 #define pmd_clear(pmd)                 native_pmd_clear(pmd)
 
 #define pte_update(mm, addr, ptep)              do { } while (0)
-#define pte_update_defer(mm, addr, ptep)        do { } while (0)
-#define pmd_update(mm, addr, ptep)              do { } while (0)
-#define pmd_update_defer(mm, addr, ptep)        do { } while (0)
 
 #define pgd_val(x)     native_pgd_val(x)
 #define __pgd(x)       native_make_pgd(x)
@@ -731,14 +728,9 @@ static inline void native_set_pmd_at(struct mm_struct *mm, unsigned long addr,
  * updates should either be sets, clears, or set_pte_atomic for P->P
  * transitions, which means this hook should only be called for user PTEs.
  * This hook implies a P->P protection or access change has taken place, which
- * requires a subsequent TLB flush.  The notification can optionally be delayed
- * until the TLB flush event by using the pte_update_defer form of the
- * interface, but care must be taken to assure that the flush happens while
- * still holding the same page table lock so that the shadow and primary pages
- * do not become out of sync on SMP.
+ * requires a subsequent TLB flush.
  */
 #define pte_update(mm, addr, ptep)             do { } while (0)
-#define pte_update_defer(mm, addr, ptep)       do { } while (0)
 #endif
 
 /*
@@ -830,9 +822,7 @@ static inline int pmd_write(pmd_t pmd)
 static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, unsigned long addr,
                                       pmd_t *pmdp)
 {
-       pmd_t pmd = native_pmdp_get_and_clear(pmdp);
-       pmd_update(mm, addr, pmdp);
-       return pmd;
+       return native_pmdp_get_and_clear(pmdp);
 }
 
 #define __HAVE_ARCH_PMDP_SET_WRPROTECT
@@ -840,7 +830,6 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm,
                                      unsigned long addr, pmd_t *pmdp)
 {
        clear_bit(_PAGE_BIT_RW, (unsigned long *)pmdp);
-       pmd_update(mm, addr, pmdp);
 }
 
 /*
index 67522256c7ffaf610aa70ef885bd8df584d1bbbd..2d5a50cb61a2d6ad5c68d5563636edcc112ff4f9 100644 (file)
@@ -472,6 +472,7 @@ static inline unsigned long current_top_of_stack(void)
 #else
 #define __cpuid                        native_cpuid
 #define paravirt_enabled()     0
+#define paravirt_has(x)        0
 
 static inline void load_sp0(struct tss_struct *tss,
                            struct thread_struct *thread)
index 7a6bed5c08bc3cc266dcc7c24e71863f684d2630..fdcc04020636e33269d7a756162cfe852f509823 100644 (file)
@@ -4,6 +4,15 @@
 #include <linux/clocksource.h>
 #include <asm/pvclock-abi.h>
 
+#ifdef CONFIG_KVM_GUEST
+extern struct pvclock_vsyscall_time_info *pvclock_pvti_cpu0_va(void);
+#else
+static inline struct pvclock_vsyscall_time_info *pvclock_pvti_cpu0_va(void)
+{
+       return NULL;
+}
+#endif
+
 /* some helper functions for xen and kvm pv clock sources */
 cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src);
 u8 pvclock_read_flags(struct pvclock_vcpu_time_info *src);
@@ -91,10 +100,5 @@ struct pvclock_vsyscall_time_info {
 } __attribute__((__aligned__(SMP_CACHE_BYTES)));
 
 #define PVTI_SIZE sizeof(struct pvclock_vsyscall_time_info)
-#define PVCLOCK_VSYSCALL_NR_PAGES (((NR_CPUS-1)/(PAGE_SIZE/PVTI_SIZE))+1)
-
-int __init pvclock_init_vsyscall(struct pvclock_vsyscall_time_info *i,
-                                int size);
-struct pvclock_vcpu_time_info *pvclock_get_vsyscall_time_info(int cpu);
 
 #endif /* _ASM_X86_PVCLOCK_H */
index b002e711ba88eaf1610071ef7459054ad18155b2..9f92c180ed2fb769bf0e5d0b83ae6eba9ac27f75 100644 (file)
@@ -1,6 +1,65 @@
 #ifndef __ASM_QSPINLOCK_PARAVIRT_H
 #define __ASM_QSPINLOCK_PARAVIRT_H
 
+/*
+ * For x86-64, PV_CALLEE_SAVE_REGS_THUNK() saves and restores 8 64-bit
+ * registers. For i386, however, only 1 32-bit register needs to be saved
+ * and restored. So an optimized version of __pv_queued_spin_unlock() is
+ * hand-coded for 64-bit, but it isn't worthwhile to do it for 32-bit.
+ */
+#ifdef CONFIG_64BIT
+
+PV_CALLEE_SAVE_REGS_THUNK(__pv_queued_spin_unlock_slowpath);
+#define __pv_queued_spin_unlock        __pv_queued_spin_unlock
+#define PV_UNLOCK              "__raw_callee_save___pv_queued_spin_unlock"
+#define PV_UNLOCK_SLOWPATH     "__raw_callee_save___pv_queued_spin_unlock_slowpath"
+
+/*
+ * Optimized assembly version of __raw_callee_save___pv_queued_spin_unlock
+ * which combines the registers saving trunk and the body of the following
+ * C code:
+ *
+ * void __pv_queued_spin_unlock(struct qspinlock *lock)
+ * {
+ *     struct __qspinlock *l = (void *)lock;
+ *     u8 lockval = cmpxchg(&l->locked, _Q_LOCKED_VAL, 0);
+ *
+ *     if (likely(lockval == _Q_LOCKED_VAL))
+ *             return;
+ *     pv_queued_spin_unlock_slowpath(lock, lockval);
+ * }
+ *
+ * For x86-64,
+ *   rdi = lock              (first argument)
+ *   rsi = lockval           (second argument)
+ *   rdx = internal variable (set to 0)
+ */
+asm    (".pushsection .text;"
+       ".globl " PV_UNLOCK ";"
+       ".align 4,0x90;"
+       PV_UNLOCK ": "
+       "push  %rdx;"
+       "mov   $0x1,%eax;"
+       "xor   %edx,%edx;"
+       "lock cmpxchg %dl,(%rdi);"
+       "cmp   $0x1,%al;"
+       "jne   .slowpath;"
+       "pop   %rdx;"
+       "ret;"
+       ".slowpath: "
+       "push   %rsi;"
+       "movzbl %al,%esi;"
+       "call " PV_UNLOCK_SLOWPATH ";"
+       "pop    %rsi;"
+       "pop    %rdx;"
+       "ret;"
+       ".size " PV_UNLOCK ", .-" PV_UNLOCK ";"
+       ".popsection");
+
+#else /* CONFIG_64BIT */
+
+extern void __pv_queued_spin_unlock(struct qspinlock *lock);
 PV_CALLEE_SAVE_REGS_THUNK(__pv_queued_spin_unlock);
 
+#endif /* CONFIG_64BIT */
 #endif
index a82c4f1b4d83e96daf1d99126a290c45ffa38a6c..2cb1cc253d51ebb5828e89f63b63462396050970 100644 (file)
@@ -25,5 +25,6 @@ void __noreturn machine_real_restart(unsigned int type);
 
 typedef void (*nmi_shootdown_cb)(int, struct pt_regs*);
 void nmi_shootdown_cpus(nmi_shootdown_cb callback);
+void run_crash_ipi_callback(struct pt_regs *regs);
 
 #endif /* _ASM_X86_REBOOT_H */
index 222a6a3ca2b5ebeeff21037b8a3b517b8fd3353a..dfcf0727623b3f89d53374ea504f243e802be149 100644 (file)
 extern int smp_num_siblings;
 extern unsigned int num_processors;
 
-static inline bool cpu_has_ht_siblings(void)
-{
-       bool has_siblings = false;
-#ifdef CONFIG_SMP
-       has_siblings = cpu_has_ht && smp_num_siblings > 1;
-#endif
-       return has_siblings;
-}
-
 DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_sibling_map);
 DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_core_map);
 /* cpus sharing the last level cache: */
@@ -74,9 +65,6 @@ struct smp_ops {
 extern void set_cpu_sibling_map(int cpu);
 
 #ifdef CONFIG_SMP
-#ifndef CONFIG_PARAVIRT
-#define startup_ipi_hook(phys_apicid, start_eip, start_esp) do { } while (0)
-#endif
 extern struct smp_ops smp_ops;
 
 static inline void smp_send_stop(void)
index d1793f06854d28f22481c40f03cd2171d7b13495..8e9dbe7b73a1fa2d3c2a5b26a3d226352157c637 100644 (file)
@@ -15,6 +15,7 @@ struct saved_context {
        unsigned long cr0, cr2, cr3, cr4;
        u64 misc_enable;
        bool misc_enable_saved;
+       struct saved_msrs saved_msrs;
        struct desc_ptr gdt_desc;
        struct desc_ptr idt;
        u16 ldt;
index 7ebf0ebe4e687f3704cac47b3de3dd1b906d27e8..6136a18152af28bb4cdb72b652a6161c85b20e51 100644 (file)
@@ -24,6 +24,7 @@ struct saved_context {
        unsigned long cr0, cr2, cr3, cr4, cr8;
        u64 misc_enable;
        bool misc_enable_saved;
+       struct saved_msrs saved_msrs;
        unsigned long efer;
        u16 gdt_pad; /* Unused */
        struct desc_ptr gdt_desc;
index 09b1b0ab94b7653f7ed7019eb7e35b518582f825..660458af425d795e051ad781e9a9c948b8a4ceff 100644 (file)
@@ -745,5 +745,14 @@ copy_to_user(void __user *to, const void *from, unsigned long n)
 #undef __copy_from_user_overflow
 #undef __copy_to_user_overflow
 
+/*
+ * We rely on the nested NMI work to allow atomic faults from the NMI path; the
+ * nested NMI paths are careful to preserve CR2.
+ *
+ * Caller must use pagefault_enable/disable, or run in interrupt context,
+ * and also do a uaccess_ok() check
+ */
+#define __copy_from_user_nmi __copy_from_user_inatomic
+
 #endif /* _ASM_X86_UACCESS_H */
 
index 756de9190aecad5d7939ee7189703a9177f4da25..deabaf9759b640d5cd93f50f9db67ef2dc60a807 100644 (file)
@@ -22,6 +22,7 @@ struct vdso_image {
 
        long sym_vvar_page;
        long sym_hpet_page;
+       long sym_pvclock_page;
        long sym_VDSO32_NOTE_MASK;
        long sym___kernel_sigreturn;
        long sym___kernel_rt_sigreturn;
index cd0fc0cc78bc34f1d378c844baf6007ce60c1797..1ae89a2721d6f5a120650630d317913c3ee2c32a 100644 (file)
@@ -82,13 +82,11 @@ struct x86_init_paging {
  * struct x86_init_timers - platform specific timer setup
  * @setup_perpcu_clockev:      set up the per cpu clock event device for the
  *                             boot cpu
- * @tsc_pre_init:              platform function called before TSC init
  * @timer_init:                        initialize the platform timer (default PIT/HPET)
  * @wallclock_init:            init the wallclock device
  */
 struct x86_init_timers {
        void (*setup_percpu_clockev)(void);
-       void (*tsc_pre_init)(void);
        void (*timer_init)(void);
        void (*wallclock_init)(void);
 };
index 4c20dd333412db5b367d0625e9b7cf69a7891493..3bcdcc84259d98b919a7cc455b07082660bb6393 100644 (file)
@@ -310,10 +310,10 @@ HYPERVISOR_mca(struct xen_mc *mc_op)
 }
 
 static inline int
-HYPERVISOR_dom0_op(struct xen_platform_op *platform_op)
+HYPERVISOR_platform_op(struct xen_platform_op *op)
 {
-       platform_op->interface_version = XENPF_INTERFACE_VERSION;
-       return _hypercall1(int, dom0_op, platform_op);
+       op->interface_version = XENPF_INTERFACE_VERSION;
+       return _hypercall1(int, platform_op, op);
 }
 
 static inline int
index 5a08bc8bff33934e10b4b9afe8e3236ac8c5ce93..c54beb44c4c1f20e4dda33fb901d17b2850fecf5 100644 (file)
@@ -553,7 +553,7 @@ do {                                                        \
        if (cpu_has_xmm) {                              \
                xor_speed(&xor_block_pIII_sse);         \
                xor_speed(&xor_block_sse_pf64);         \
-       } else if (cpu_has_mmx) {                       \
+       } else if (boot_cpu_has(X86_FEATURE_MMX)) {     \
                xor_speed(&xor_block_pII_mmx);          \
                xor_speed(&xor_block_p5_mmx);           \
        } else {                                        \
index 040d4083c24fb1190df2d9377b6396dc4e2b8b3c..7956412d09bd8b340a41660d41aed4fac3947a6e 100644 (file)
@@ -269,4 +269,96 @@ typedef struct _HV_REFERENCE_TSC_PAGE {
 #define HV_SYNIC_SINT_AUTO_EOI         (1ULL << 17)
 #define HV_SYNIC_SINT_VECTOR_MASK      (0xFF)
 
+#define HV_SYNIC_STIMER_COUNT          (4)
+
+/* Define synthetic interrupt controller message constants. */
+#define HV_MESSAGE_SIZE                        (256)
+#define HV_MESSAGE_PAYLOAD_BYTE_COUNT  (240)
+#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30)
+
+/* Define hypervisor message types. */
+enum hv_message_type {
+       HVMSG_NONE                      = 0x00000000,
+
+       /* Memory access messages. */
+       HVMSG_UNMAPPED_GPA              = 0x80000000,
+       HVMSG_GPA_INTERCEPT             = 0x80000001,
+
+       /* Timer notification messages. */
+       HVMSG_TIMER_EXPIRED                     = 0x80000010,
+
+       /* Error messages. */
+       HVMSG_INVALID_VP_REGISTER_VALUE = 0x80000020,
+       HVMSG_UNRECOVERABLE_EXCEPTION   = 0x80000021,
+       HVMSG_UNSUPPORTED_FEATURE               = 0x80000022,
+
+       /* Trace buffer complete messages. */
+       HVMSG_EVENTLOG_BUFFERCOMPLETE   = 0x80000040,
+
+       /* Platform-specific processor intercept messages. */
+       HVMSG_X64_IOPORT_INTERCEPT              = 0x80010000,
+       HVMSG_X64_MSR_INTERCEPT         = 0x80010001,
+       HVMSG_X64_CPUID_INTERCEPT               = 0x80010002,
+       HVMSG_X64_EXCEPTION_INTERCEPT   = 0x80010003,
+       HVMSG_X64_APIC_EOI                      = 0x80010004,
+       HVMSG_X64_LEGACY_FP_ERROR               = 0x80010005
+};
+
+/* Define synthetic interrupt controller message flags. */
+union hv_message_flags {
+       __u8 asu8;
+       struct {
+               __u8 msg_pending:1;
+               __u8 reserved:7;
+       };
+};
+
+/* Define port identifier type. */
+union hv_port_id {
+       __u32 asu32;
+       struct {
+               __u32 id:24;
+               __u32 reserved:8;
+       } u;
+};
+
+/* Define synthetic interrupt controller message header. */
+struct hv_message_header {
+       __u32 message_type;
+       __u8 payload_size;
+       union hv_message_flags message_flags;
+       __u8 reserved[2];
+       union {
+               __u64 sender;
+               union hv_port_id port;
+       };
+};
+
+/* Define synthetic interrupt controller message format. */
+struct hv_message {
+       struct hv_message_header header;
+       union {
+               __u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
+       } u;
+};
+
+/* Define the synthetic interrupt message page layout. */
+struct hv_message_page {
+       struct hv_message sint_message[HV_SYNIC_SINT_COUNT];
+};
+
+/* Define timer message payload structure. */
+struct hv_timer_message_payload {
+       __u32 timer_index;
+       __u32 reserved;
+       __u64 expiration_time;  /* When the timer expired */
+       __u64 delivery_time;    /* When the message was delivered */
+};
+
+#define HV_STIMER_ENABLE               (1ULL << 0)
+#define HV_STIMER_PERIODIC             (1ULL << 1)
+#define HV_STIMER_LAZY                 (1ULL << 2)
+#define HV_STIMER_AUTOENABLE           (1ULL << 3)
+#define HV_STIMER_SINT(config)         (__u8)(((config) >> 16) & 0x0F)
+
 #endif
index 03429da2fa80145bbe11e56587e2c7868f467d5d..2184943341bf0db75a113d239e193cacbbfa07f2 100644 (file)
@@ -16,7 +16,7 @@ struct mce {
        __u8  cpuvendor;        /* cpu vendor as encoded in system.h */
        __u8  inject_flags;     /* software inject flags */
        __u8  severity;
-       __u8  usable_addr;
+       __u8  pad;
        __u32 cpuid;    /* CPUID 1 EAX */
        __u8  cs;               /* code segment */
        __u8  bank;     /* machine check bank */
index 2f69e3b184f62c2f7e87c6956bc58fbadb711965..8a5cddac7d444084c223e95948944b5099d15003 100644 (file)
@@ -81,6 +81,12 @@ physid_mask_t phys_cpu_present_map;
  */
 static unsigned int disabled_cpu_apicid __read_mostly = BAD_APICID;
 
+/*
+ * This variable controls which CPUs receive external NMIs.  By default,
+ * external NMIs are delivered only to the BSP.
+ */
+static int apic_extnmi = APIC_EXTNMI_BSP;
+
 /*
  * Map cpu index to physical APIC ID
  */
@@ -1161,6 +1167,8 @@ void __init init_bsp_APIC(void)
        value = APIC_DM_NMI;
        if (!lapic_is_integrated())             /* 82489DX */
                value |= APIC_LVT_LEVEL_TRIGGER;
+       if (apic_extnmi == APIC_EXTNMI_NONE)
+               value |= APIC_LVT_MASKED;
        apic_write(APIC_LVT1, value);
 }
 
@@ -1378,9 +1386,11 @@ void setup_local_APIC(void)
        apic_write(APIC_LVT0, value);
 
        /*
-        * only the BP should see the LINT1 NMI signal, obviously.
+        * Only the BSP sees the LINT1 NMI signal by default. This can be
+        * modified by apic_extnmi= boot option.
         */
-       if (!cpu)
+       if ((!cpu && apic_extnmi != APIC_EXTNMI_NONE) ||
+           apic_extnmi == APIC_EXTNMI_ALL)
                value = APIC_DM_NMI;
        else
                value = APIC_DM_NMI | APIC_LVT_MASKED;
@@ -2270,6 +2280,7 @@ static struct {
        unsigned int apic_tmict;
        unsigned int apic_tdcr;
        unsigned int apic_thmr;
+       unsigned int apic_cmci;
 } apic_pm_state;
 
 static int lapic_suspend(void)
@@ -2299,6 +2310,10 @@ static int lapic_suspend(void)
        if (maxlvt >= 5)
                apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);
 #endif
+#ifdef CONFIG_X86_MCE_INTEL
+       if (maxlvt >= 6)
+               apic_pm_state.apic_cmci = apic_read(APIC_LVTCMCI);
+#endif
 
        local_irq_save(flags);
        disable_local_APIC();
@@ -2355,9 +2370,13 @@ static void lapic_resume(void)
        apic_write(APIC_SPIV, apic_pm_state.apic_spiv);
        apic_write(APIC_LVT0, apic_pm_state.apic_lvt0);
        apic_write(APIC_LVT1, apic_pm_state.apic_lvt1);
-#if defined(CONFIG_X86_MCE_INTEL)
+#ifdef CONFIG_X86_THERMAL_VECTOR
        if (maxlvt >= 5)
                apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr);
+#endif
+#ifdef CONFIG_X86_MCE_INTEL
+       if (maxlvt >= 6)
+               apic_write(APIC_LVTCMCI, apic_pm_state.apic_cmci);
 #endif
        if (maxlvt >= 4)
                apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc);
@@ -2548,3 +2567,23 @@ static int __init apic_set_disabled_cpu_apicid(char *arg)
        return 0;
 }
 early_param("disable_cpu_apicid", apic_set_disabled_cpu_apicid);
+
+static int __init apic_set_extnmi(char *arg)
+{
+       if (!arg)
+               return -EINVAL;
+
+       if (!strncmp("all", arg, 3))
+               apic_extnmi = APIC_EXTNMI_ALL;
+       else if (!strncmp("none", arg, 4))
+               apic_extnmi = APIC_EXTNMI_NONE;
+       else if (!strncmp("bsp", arg, 3))
+               apic_extnmi = APIC_EXTNMI_BSP;
+       else {
+               pr_warn("Unknown external NMI delivery mode `%s' ignored\n", arg);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+early_param("apic_extnmi", apic_set_extnmi);
index f92ab36979a207911d63bb522d45cc40d71f5a9e..9968f30cca3e187d28acf2d7631609c29cb1bcf6 100644 (file)
@@ -185,6 +185,7 @@ static struct apic apic_flat =  {
 
        .cpu_mask_to_apicid_and         = flat_cpu_mask_to_apicid_and,
 
+       .send_IPI                       = default_send_IPI_single,
        .send_IPI_mask                  = flat_send_IPI_mask,
        .send_IPI_mask_allbutself       = flat_send_IPI_mask_allbutself,
        .send_IPI_allbutself            = flat_send_IPI_allbutself,
@@ -230,17 +231,6 @@ static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
        return 0;
 }
 
-static void physflat_send_IPI_mask(const struct cpumask *cpumask, int vector)
-{
-       default_send_IPI_mask_sequence_phys(cpumask, vector);
-}
-
-static void physflat_send_IPI_mask_allbutself(const struct cpumask *cpumask,
-                                             int vector)
-{
-       default_send_IPI_mask_allbutself_phys(cpumask, vector);
-}
-
 static void physflat_send_IPI_allbutself(int vector)
 {
        default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector);
@@ -248,7 +238,7 @@ static void physflat_send_IPI_allbutself(int vector)
 
 static void physflat_send_IPI_all(int vector)
 {
-       physflat_send_IPI_mask(cpu_online_mask, vector);
+       default_send_IPI_mask_sequence_phys(cpu_online_mask, vector);
 }
 
 static int physflat_probe(void)
@@ -292,8 +282,9 @@ static struct apic apic_physflat =  {
 
        .cpu_mask_to_apicid_and         = default_cpu_mask_to_apicid_and,
 
-       .send_IPI_mask                  = physflat_send_IPI_mask,
-       .send_IPI_mask_allbutself       = physflat_send_IPI_mask_allbutself,
+       .send_IPI                       = default_send_IPI_single_phys,
+       .send_IPI_mask                  = default_send_IPI_mask_sequence_phys,
+       .send_IPI_mask_allbutself       = default_send_IPI_mask_allbutself_phys,
        .send_IPI_allbutself            = physflat_send_IPI_allbutself,
        .send_IPI_all                   = physflat_send_IPI_all,
        .send_IPI_self                  = apic_send_IPI_self,
index 0d96749cfcacf4c558fc3c1163bd2825a0fa84bf..331a7a07c48fefe0313f3089c1bb497dc48cd7e4 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/e820.h>
 
 static void noop_init_apic_ldr(void) { }
+static void noop_send_IPI(int cpu, int vector) { }
 static void noop_send_IPI_mask(const struct cpumask *cpumask, int vector) { }
 static void noop_send_IPI_mask_allbutself(const struct cpumask *cpumask, int vector) { }
 static void noop_send_IPI_allbutself(int vector) { }
@@ -144,6 +145,7 @@ struct apic apic_noop = {
 
        .cpu_mask_to_apicid_and         = flat_cpu_mask_to_apicid_and,
 
+       .send_IPI                       = noop_send_IPI,
        .send_IPI_mask                  = noop_send_IPI_mask,
        .send_IPI_mask_allbutself       = noop_send_IPI_mask_allbutself,
        .send_IPI_allbutself            = noop_send_IPI_allbutself,
index 38dd5efdd04c33aa58b2b20b19596bcd12e3e4af..c80c02c6ec4944a85715f4438443e5987df4f612 100644 (file)
@@ -193,20 +193,17 @@ static int __init numachip_system_init(void)
        case 1:
                init_extra_mapping_uc(NUMACHIP_LCSR_BASE, NUMACHIP_LCSR_SIZE);
                numachip_apic_icr_write = numachip1_apic_icr_write;
-               x86_init.pci.arch_init = pci_numachip_init;
                break;
        case 2:
                init_extra_mapping_uc(NUMACHIP2_LCSR_BASE, NUMACHIP2_LCSR_SIZE);
                numachip_apic_icr_write = numachip2_apic_icr_write;
-
-               /* Use MCFG config cycles rather than locked CF8 cycles */
-               raw_pci_ops = &pci_mmcfg;
                break;
        default:
                return 0;
        }
 
        x86_cpuinit.fixup_cpu_id = fixup_cpu_id;
+       x86_init.pci.arch_init = pci_numachip_init;
 
        return 0;
 }
@@ -276,6 +273,7 @@ static const struct apic apic_numachip1 __refconst = {
 
        .cpu_mask_to_apicid_and         = default_cpu_mask_to_apicid_and,
 
+       .send_IPI                       = numachip_send_IPI_one,
        .send_IPI_mask                  = numachip_send_IPI_mask,
        .send_IPI_mask_allbutself       = numachip_send_IPI_mask_allbutself,
        .send_IPI_allbutself            = numachip_send_IPI_allbutself,
@@ -327,6 +325,7 @@ static const struct apic apic_numachip2 __refconst = {
 
        .cpu_mask_to_apicid_and         = default_cpu_mask_to_apicid_and,
 
+       .send_IPI                       = numachip_send_IPI_one,
        .send_IPI_mask                  = numachip_send_IPI_mask,
        .send_IPI_mask_allbutself       = numachip_send_IPI_mask_allbutself,
        .send_IPI_allbutself            = numachip_send_IPI_allbutself,
index 971cf8875939d1a5264a46018a7997abe0525158..cf9bd896c12d38f8ac5772a2d578fae1b68da3df 100644 (file)
@@ -96,11 +96,6 @@ static int bigsmp_phys_pkg_id(int cpuid_apic, int index_msb)
        return cpuid_apic >> index_msb;
 }
 
-static inline void bigsmp_send_IPI_mask(const struct cpumask *mask, int vector)
-{
-       default_send_IPI_mask_sequence_phys(mask, vector);
-}
-
 static void bigsmp_send_IPI_allbutself(int vector)
 {
        default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector);
@@ -108,7 +103,7 @@ static void bigsmp_send_IPI_allbutself(int vector)
 
 static void bigsmp_send_IPI_all(int vector)
 {
-       bigsmp_send_IPI_mask(cpu_online_mask, vector);
+       default_send_IPI_mask_sequence_phys(cpu_online_mask, vector);
 }
 
 static int dmi_bigsmp; /* can be set by dmi scanners */
@@ -180,7 +175,8 @@ static struct apic apic_bigsmp = {
 
        .cpu_mask_to_apicid_and         = default_cpu_mask_to_apicid_and,
 
-       .send_IPI_mask                  = bigsmp_send_IPI_mask,
+       .send_IPI                       = default_send_IPI_single_phys,
+       .send_IPI_mask                  = default_send_IPI_mask_sequence_phys,
        .send_IPI_mask_allbutself       = NULL,
        .send_IPI_allbutself            = bigsmp_send_IPI_allbutself,
        .send_IPI_all                   = bigsmp_send_IPI_all,
index 62071569bd50d8137758a64be8b5b1c32329b240..eb45fc9b61248e9c9e819c974741c2652f56e644 100644 (file)
 #include <asm/proto.h>
 #include <asm/ipi.h>
 
+void default_send_IPI_single_phys(int cpu, int vector)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       __default_send_IPI_dest_field(per_cpu(x86_cpu_to_apicid, cpu),
+                                     vector, APIC_DEST_PHYSICAL);
+       local_irq_restore(flags);
+}
+
 void default_send_IPI_mask_sequence_phys(const struct cpumask *mask, int vector)
 {
        unsigned long query_cpu;
@@ -55,6 +65,14 @@ void default_send_IPI_mask_allbutself_phys(const struct cpumask *mask,
        local_irq_restore(flags);
 }
 
+/*
+ * Helper function for APICs which insist on cpumasks
+ */
+void default_send_IPI_single(int cpu, int vector)
+{
+       apic->send_IPI_mask(cpumask_of(cpu), vector);
+}
+
 #ifdef CONFIG_X86_32
 
 void default_send_IPI_mask_sequence_logical(const struct cpumask *mask,
index 5f1feb6854afe9ffa719d9099133c8b4b674a5a0..ade25320df96479193fe850e8747f9acad758b2d 100644 (file)
@@ -96,8 +96,8 @@ static irq_hw_number_t pci_msi_get_hwirq(struct msi_domain_info *info,
        return arg->msi_hwirq;
 }
 
-static int pci_msi_prepare(struct irq_domain *domain, struct device *dev,
-                          int nvec, msi_alloc_info_t *arg)
+int pci_msi_prepare(struct irq_domain *domain, struct device *dev, int nvec,
+                   msi_alloc_info_t *arg)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct msi_desc *desc = first_pci_msi_entry(pdev);
@@ -113,11 +113,13 @@ static int pci_msi_prepare(struct irq_domain *domain, struct device *dev,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(pci_msi_prepare);
 
-static void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
+void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
 {
        arg->msi_hwirq = pci_msi_domain_calc_hwirq(arg->msi_dev, desc);
 }
+EXPORT_SYMBOL_GPL(pci_msi_set_desc);
 
 static struct msi_domain_ops pci_msi_domain_ops = {
        .get_hwirq      = pci_msi_get_hwirq,
index 7694ae6c1199b370331e550601ac6a36d89933e9..f316e34abb42bef31fbf8948bb1cdd8c4491fcbe 100644 (file)
@@ -105,6 +105,7 @@ static struct apic apic_default = {
 
        .cpu_mask_to_apicid_and         = flat_cpu_mask_to_apicid_and,
 
+       .send_IPI                       = default_send_IPI_single,
        .send_IPI_mask                  = default_send_IPI_mask_logical,
        .send_IPI_mask_allbutself       = default_send_IPI_mask_allbutself_logical,
        .send_IPI_allbutself            = default_send_IPI_allbutself,
index 861bc59c8f2564eac7b87193e7cd250571e1fbf4..908cb37da171ebed1a361203dc520c15e4e42736 100644 (file)
@@ -29,6 +29,7 @@ struct apic_chip_data {
 };
 
 struct irq_domain *x86_vector_domain;
+EXPORT_SYMBOL_GPL(x86_vector_domain);
 static DEFINE_RAW_SPINLOCK(vector_lock);
 static cpumask_var_t vector_cpumask;
 static struct irq_chip lapic_controller;
@@ -66,6 +67,7 @@ struct irq_cfg *irqd_cfg(struct irq_data *irq_data)
 
        return data ? &data->cfg : NULL;
 }
+EXPORT_SYMBOL_GPL(irqd_cfg);
 
 struct irq_cfg *irq_cfg(unsigned int irq)
 {
index cc8311c4d29850c4d0760fabfbd305ead526d321..aca8b75c15527fcb0aa78bcabbcbb9fe6b14fdc0 100644 (file)
@@ -23,6 +23,14 @@ static inline u32 x2apic_cluster(int cpu)
        return per_cpu(x86_cpu_to_logical_apicid, cpu) >> 16;
 }
 
+static void x2apic_send_IPI(int cpu, int vector)
+{
+       u32 dest = per_cpu(x86_cpu_to_logical_apicid, cpu);
+
+       x2apic_wrmsr_fence();
+       __x2apic_send_IPI_dest(dest, vector, APIC_DEST_LOGICAL);
+}
+
 static void
 __x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
 {
@@ -266,6 +274,7 @@ static struct apic apic_x2apic_cluster = {
 
        .cpu_mask_to_apicid_and         = x2apic_cpu_mask_to_apicid_and,
 
+       .send_IPI                       = x2apic_send_IPI,
        .send_IPI_mask                  = x2apic_send_IPI_mask,
        .send_IPI_mask_allbutself       = x2apic_send_IPI_mask_allbutself,
        .send_IPI_allbutself            = x2apic_send_IPI_allbutself,
index 662e9150ea6f29e6c050ce76d719ed3d77385148..a1242e2c12e646d4eb2b805e4359ce9068e4db56 100644 (file)
@@ -36,6 +36,14 @@ static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
        return x2apic_enabled() && (x2apic_phys || x2apic_fadt_phys());
 }
 
+static void x2apic_send_IPI(int cpu, int vector)
+{
+       u32 dest = per_cpu(x86_cpu_to_apicid, cpu);
+
+       x2apic_wrmsr_fence();
+       __x2apic_send_IPI_dest(dest, vector, APIC_DEST_PHYSICAL);
+}
+
 static void
 __x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
 {
@@ -122,6 +130,7 @@ static struct apic apic_x2apic_phys = {
 
        .cpu_mask_to_apicid_and         = default_cpu_mask_to_apicid_and,
 
+       .send_IPI                       = x2apic_send_IPI,
        .send_IPI_mask                  = x2apic_send_IPI_mask,
        .send_IPI_mask_allbutself       = x2apic_send_IPI_mask_allbutself,
        .send_IPI_allbutself            = x2apic_send_IPI_allbutself,
index 4a139465f1d4f025366af706b410594dc43d65b1..d760c6bb37b53c25931bef3bc47c903def86c8ee 100644 (file)
@@ -406,6 +406,7 @@ static struct apic __refdata apic_x2apic_uv_x = {
 
        .cpu_mask_to_apicid_and         = uv_cpu_mask_to_apicid_and,
 
+       .send_IPI                       = uv_send_IPI_one,
        .send_IPI_mask                  = uv_send_IPI_mask,
        .send_IPI_mask_allbutself       = uv_send_IPI_mask_allbutself,
        .send_IPI_allbutself            = uv_send_IPI_allbutself,
index 439df975bc7aed0861581381476eeb933bc086de..84a7524b202cad58509a68db5e6d229f7765b6aa 100644 (file)
@@ -65,9 +65,6 @@ void common(void) {
        OFFSET(PV_IRQ_irq_disable, pv_irq_ops, irq_disable);
        OFFSET(PV_IRQ_irq_enable, pv_irq_ops, irq_enable);
        OFFSET(PV_CPU_iret, pv_cpu_ops, iret);
-#ifdef CONFIG_X86_32
-       OFFSET(PV_CPU_irq_enable_sysexit, pv_cpu_ops, irq_enable_sysexit);
-#endif
        OFFSET(PV_CPU_read_cr0, pv_cpu_ops, read_cr0);
        OFFSET(PV_MMU_read_cr2, pv_mmu_ops, read_cr2);
 #endif
index d8f42f902a0f6a6f8d3d5fbeebad623fc729a906..f2edafb5f24eb2034ee54751292af3fa9bd70fb9 100644 (file)
@@ -23,7 +23,6 @@ int main(void)
 {
 #ifdef CONFIG_PARAVIRT
        OFFSET(PV_IRQ_adjust_exception_frame, pv_irq_ops, adjust_exception_frame);
-       OFFSET(PV_CPU_usergs_sysret32, pv_cpu_ops, usergs_sysret32);
        OFFSET(PV_CPU_usergs_sysret64, pv_cpu_ops, usergs_sysret64);
        OFFSET(PV_CPU_swapgs, pv_cpu_ops, swapgs);
        BLANK();
index a8816b3251620c941f543e595e949aa60c43467d..e678ddeed03067c3e1d63ebc3b7bd53239d3f8cb 100644 (file)
@@ -304,7 +304,7 @@ static void amd_get_topology(struct cpuinfo_x86 *c)
        int cpu = smp_processor_id();
 
        /* get information required for multi-node processors */
-       if (cpu_has_topoext) {
+       if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
                u32 eax, ebx, ecx, edx;
 
                cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
@@ -678,9 +678,9 @@ static void init_amd_bd(struct cpuinfo_x86 *c)
         * Disable it on the affected CPUs.
         */
        if ((c->x86_model >= 0x02) && (c->x86_model < 0x20)) {
-               if (!rdmsrl_safe(0xc0011021, &value) && !(value & 0x1E)) {
+               if (!rdmsrl_safe(MSR_F15H_IC_CFG, &value) && !(value & 0x1E)) {
                        value |= 0x1E;
-                       wrmsrl_safe(0xc0011021, value);
+                       wrmsrl_safe(MSR_F15H_IC_CFG, value);
                }
        }
 }
@@ -922,7 +922,7 @@ static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum)
 
 void set_dr_addr_mask(unsigned long mask, int dr)
 {
-       if (!cpu_has_bpext)
+       if (!boot_cpu_has(X86_FEATURE_BPEXT))
                return;
 
        switch (dr) {
index d8fba5c15fbd8882f317daa2779c39ff4429b0d4..ae20be6e483c77703413cf36e9db065134da01f3 100644 (file)
@@ -43,7 +43,7 @@ static void init_c3(struct cpuinfo_x86 *c)
                /* store Centaur Extended Feature Flags as
                 * word 5 of the CPU capability bit array
                 */
-               c->x86_capability[5] = cpuid_edx(0xC0000001);
+               c->x86_capability[CPUID_C000_0001_EDX] = cpuid_edx(0xC0000001);
        }
 #ifdef CONFIG_X86_32
        /* Cyrix III family needs CX8 & PGE explicitly enabled. */
index c2b7522cbf357617bf8302f3c4f964834b940926..37830de8f60a8f0d8f8da27d409da72ce1f13551 100644 (file)
@@ -581,14 +581,9 @@ void cpu_detect(struct cpuinfo_x86 *c)
                u32 junk, tfms, cap0, misc;
 
                cpuid(0x00000001, &tfms, &misc, &junk, &cap0);
-               c->x86 = (tfms >> 8) & 0xf;
-               c->x86_model = (tfms >> 4) & 0xf;
-               c->x86_mask = tfms & 0xf;
-
-               if (c->x86 == 0xf)
-                       c->x86 += (tfms >> 20) & 0xff;
-               if (c->x86 >= 0x6)
-                       c->x86_model += ((tfms >> 16) & 0xf) << 4;
+               c->x86          = x86_family(tfms);
+               c->x86_model    = x86_model(tfms);
+               c->x86_mask     = x86_stepping(tfms);
 
                if (cap0 & (1<<19)) {
                        c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
@@ -599,50 +594,47 @@ void cpu_detect(struct cpuinfo_x86 *c)
 
 void get_cpu_cap(struct cpuinfo_x86 *c)
 {
-       u32 tfms, xlvl;
-       u32 ebx;
+       u32 eax, ebx, ecx, edx;
 
        /* Intel-defined flags: level 0x00000001 */
        if (c->cpuid_level >= 0x00000001) {
-               u32 capability, excap;
+               cpuid(0x00000001, &eax, &ebx, &ecx, &edx);
 
-               cpuid(0x00000001, &tfms, &ebx, &excap, &capability);
-               c->x86_capability[0] = capability;
-               c->x86_capability[4] = excap;
+               c->x86_capability[CPUID_1_ECX] = ecx;
+               c->x86_capability[CPUID_1_EDX] = edx;
        }
 
        /* Additional Intel-defined flags: level 0x00000007 */
        if (c->cpuid_level >= 0x00000007) {
-               u32 eax, ebx, ecx, edx;
-
                cpuid_count(0x00000007, 0, &eax, &ebx, &ecx, &edx);
 
-               c->x86_capability[9] = ebx;
+               c->x86_capability[CPUID_7_0_EBX] = ebx;
+
+               c->x86_capability[CPUID_6_EAX] = cpuid_eax(0x00000006);
        }
 
        /* Extended state features: level 0x0000000d */
        if (c->cpuid_level >= 0x0000000d) {
-               u32 eax, ebx, ecx, edx;
-
                cpuid_count(0x0000000d, 1, &eax, &ebx, &ecx, &edx);
 
-               c->x86_capability[10] = eax;
+               c->x86_capability[CPUID_D_1_EAX] = eax;
        }
 
        /* Additional Intel-defined flags: level 0x0000000F */
        if (c->cpuid_level >= 0x0000000F) {
-               u32 eax, ebx, ecx, edx;
 
                /* QoS sub-leaf, EAX=0Fh, ECX=0 */
                cpuid_count(0x0000000F, 0, &eax, &ebx, &ecx, &edx);
-               c->x86_capability[11] = edx;
+               c->x86_capability[CPUID_F_0_EDX] = edx;
+
                if (cpu_has(c, X86_FEATURE_CQM_LLC)) {
                        /* will be overridden if occupancy monitoring exists */
                        c->x86_cache_max_rmid = ebx;
 
                        /* QoS sub-leaf, EAX=0Fh, ECX=1 */
                        cpuid_count(0x0000000F, 1, &eax, &ebx, &ecx, &edx);
-                       c->x86_capability[12] = edx;
+                       c->x86_capability[CPUID_F_1_EDX] = edx;
+
                        if (cpu_has(c, X86_FEATURE_CQM_OCCUP_LLC)) {
                                c->x86_cache_max_rmid = ecx;
                                c->x86_cache_occ_scale = ebx;
@@ -654,22 +646,24 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
        }
 
        /* AMD-defined flags: level 0x80000001 */
-       xlvl = cpuid_eax(0x80000000);
-       c->extended_cpuid_level = xlvl;
+       eax = cpuid_eax(0x80000000);
+       c->extended_cpuid_level = eax;
 
-       if ((xlvl & 0xffff0000) == 0x80000000) {
-               if (xlvl >= 0x80000001) {
-                       c->x86_capability[1] = cpuid_edx(0x80000001);
-                       c->x86_capability[6] = cpuid_ecx(0x80000001);
+       if ((eax & 0xffff0000) == 0x80000000) {
+               if (eax >= 0x80000001) {
+                       cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
+
+                       c->x86_capability[CPUID_8000_0001_ECX] = ecx;
+                       c->x86_capability[CPUID_8000_0001_EDX] = edx;
                }
        }
 
        if (c->extended_cpuid_level >= 0x80000008) {
-               u32 eax = cpuid_eax(0x80000008);
+               cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
 
                c->x86_virt_bits = (eax >> 8) & 0xff;
                c->x86_phys_bits = eax & 0xff;
-               c->x86_capability[13] = cpuid_ebx(0x80000008);
+               c->x86_capability[CPUID_8000_0008_EBX] = ebx;
        }
 #ifdef CONFIG_X86_32
        else if (cpu_has(c, X86_FEATURE_PAE) || cpu_has(c, X86_FEATURE_PSE36))
@@ -679,6 +673,9 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
        if (c->extended_cpuid_level >= 0x80000007)
                c->x86_power = cpuid_edx(0x80000007);
 
+       if (c->extended_cpuid_level >= 0x8000000a)
+               c->x86_capability[CPUID_8000_000A_EDX] = cpuid_edx(0x8000000a);
+
        init_scattered_cpuid_features(c);
 }
 
@@ -1185,7 +1182,7 @@ void syscall_init(void)
         * They both write to the same internal register. STAR allows to
         * set CS/DS but only a 32bit target. LSTAR sets the 64bit rip.
         */
-       wrmsrl(MSR_STAR,  ((u64)__USER32_CS)<<48  | ((u64)__KERNEL_CS)<<32);
+       wrmsr(MSR_STAR, 0, (__USER32_CS << 16) | __KERNEL_CS);
        wrmsrl(MSR_LSTAR, (unsigned long)entry_SYSCALL_64);
 
 #ifdef CONFIG_IA32_EMULATION
@@ -1443,7 +1440,9 @@ void cpu_init(void)
 
        printk(KERN_INFO "Initializing CPU#%d\n", cpu);
 
-       if (cpu_feature_enabled(X86_FEATURE_VME) || cpu_has_tsc || cpu_has_de)
+       if (cpu_feature_enabled(X86_FEATURE_VME) ||
+           cpu_has_tsc ||
+           boot_cpu_has(X86_FEATURE_DE))
                cr4_clear_bits(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
 
        load_current_idt();
index 209ac1e7d1f03664010955dea71d953f6a396b5b..565648bc1a0aef6c3cf60da92ec9fb60a2408c90 100644 (file)
@@ -445,7 +445,8 @@ static void init_intel(struct cpuinfo_x86 *c)
 
        if (cpu_has_xmm2)
                set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
-       if (cpu_has_ds) {
+
+       if (boot_cpu_has(X86_FEATURE_DS)) {
                unsigned int l1;
                rdmsr(MSR_IA32_MISC_ENABLE, l1, l2);
                if (!(l1 & (1<<11)))
index e38d338a64475a82feb198c7169e54b8d6d7100a..0b6c52388cf484f809a7f328f475424dd262417c 100644 (file)
@@ -591,7 +591,7 @@ cpuid4_cache_lookup_regs(int index, struct _cpuid4_info_regs *this_leaf)
        unsigned                edx;
 
        if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
-               if (cpu_has_topoext)
+               if (boot_cpu_has(X86_FEATURE_TOPOEXT))
                        cpuid_count(0x8000001d, index, &eax.full,
                                    &ebx.full, &ecx.full, &edx);
                else
@@ -637,7 +637,7 @@ static int find_num_cache_leaves(struct cpuinfo_x86 *c)
 void init_amd_cacheinfo(struct cpuinfo_x86 *c)
 {
 
-       if (cpu_has_topoext) {
+       if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
                num_cache_leaves = find_num_cache_leaves(c);
        } else if (c->extended_cpuid_level >= 0x80000006) {
                if (cpuid_edx(0x80000006) & 0xf000)
@@ -809,7 +809,7 @@ static int __cache_amd_cpumap_setup(unsigned int cpu, int index,
        struct cacheinfo *this_leaf;
        int i, sibling;
 
-       if (cpu_has_topoext) {
+       if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
                unsigned int apicid, nshared, first, last;
 
                this_leaf = this_cpu_ci->info_list + index;
index c5b0d562dbf55064685c78b5d0fa6280748086d1..a006f4cd792b10d54a92eff4a3b9c6860aa5382e 100644 (file)
@@ -114,7 +114,6 @@ static struct work_struct mce_work;
 static struct irq_work mce_irq_work;
 
 static void (*quirk_no_way_out)(int bank, struct mce *m, struct pt_regs *regs);
-static int mce_usable_address(struct mce *m);
 
 /*
  * CPU/chipset specific EDAC code can register a notifier call here to print
@@ -475,6 +474,28 @@ static void mce_report_event(struct pt_regs *regs)
        irq_work_queue(&mce_irq_work);
 }
 
+/*
+ * Check if the address reported by the CPU is in a format we can parse.
+ * It would be possible to add code for most other cases, but all would
+ * be somewhat complicated (e.g. segment offset would require an instruction
+ * parser). So only support physical addresses up to page granuality for now.
+ */
+static int mce_usable_address(struct mce *m)
+{
+       if (!(m->status & MCI_STATUS_MISCV) || !(m->status & MCI_STATUS_ADDRV))
+               return 0;
+
+       /* Checks after this one are Intel-specific: */
+       if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
+               return 1;
+
+       if (MCI_MISC_ADDR_LSB(m->misc) > PAGE_SHIFT)
+               return 0;
+       if (MCI_MISC_ADDR_MODE(m->misc) != MCI_MISC_ADDR_PHYS)
+               return 0;
+       return 1;
+}
+
 static int srao_decode_notifier(struct notifier_block *nb, unsigned long val,
                                void *data)
 {
@@ -484,7 +505,7 @@ static int srao_decode_notifier(struct notifier_block *nb, unsigned long val,
        if (!mce)
                return NOTIFY_DONE;
 
-       if (mce->usable_addr && (mce->severity == MCE_AO_SEVERITY)) {
+       if (mce_usable_address(mce) && (mce->severity == MCE_AO_SEVERITY)) {
                pfn = mce->addr >> PAGE_SHIFT;
                memory_failure(pfn, MCE_VECTOR, 0);
        }
@@ -522,10 +543,10 @@ static bool memory_error(struct mce *m)
        struct cpuinfo_x86 *c = &boot_cpu_data;
 
        if (c->x86_vendor == X86_VENDOR_AMD) {
-               /*
-                * coming soon
-                */
-               return false;
+               /* ErrCodeExt[20:16] */
+               u8 xec = (m->status >> 16) & 0x1f;
+
+               return (xec == 0x0 || xec == 0x8);
        } else if (c->x86_vendor == X86_VENDOR_INTEL) {
                /*
                 * Intel SDM Volume 3B - 15.9.2 Compound Error Codes
@@ -567,7 +588,7 @@ DEFINE_PER_CPU(unsigned, mce_poll_count);
  */
 bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
 {
-       bool error_logged = false;
+       bool error_seen = false;
        struct mce m;
        int severity;
        int i;
@@ -601,6 +622,8 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
                    (m.status & (mca_cfg.ser ? MCI_STATUS_S : MCI_STATUS_UC)))
                        continue;
 
+               error_seen = true;
+
                mce_read_aux(&m, i);
 
                if (!(flags & MCP_TIMESTAMP))
@@ -608,27 +631,24 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
 
                severity = mce_severity(&m, mca_cfg.tolerant, NULL, false);
 
-               /*
-                * In the cases where we don't have a valid address after all,
-                * do not add it into the ring buffer.
-                */
-               if (severity == MCE_DEFERRED_SEVERITY && memory_error(&m)) {
-                       if (m.status & MCI_STATUS_ADDRV) {
+               if (severity == MCE_DEFERRED_SEVERITY && memory_error(&m))
+                       if (m.status & MCI_STATUS_ADDRV)
                                m.severity = severity;
-                               m.usable_addr = mce_usable_address(&m);
-
-                               if (!mce_gen_pool_add(&m))
-                                       mce_schedule_work();
-                       }
-               }
 
                /*
                 * Don't get the IP here because it's unlikely to
                 * have anything to do with the actual error location.
                 */
-               if (!(flags & MCP_DONTLOG) && !mca_cfg.dont_log_ce) {
-                       error_logged = true;
+               if (!(flags & MCP_DONTLOG) && !mca_cfg.dont_log_ce)
                        mce_log(&m);
+               else if (mce_usable_address(&m)) {
+                       /*
+                        * Although we skipped logging this, we still want
+                        * to take action. Add to the pool so the registered
+                        * notifiers will see it.
+                        */
+                       if (!mce_gen_pool_add(&m))
+                               mce_schedule_work();
                }
 
                /*
@@ -644,7 +664,7 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
 
        sync_core();
 
-       return error_logged;
+       return error_seen;
 }
 EXPORT_SYMBOL_GPL(machine_check_poll);
 
@@ -931,23 +951,6 @@ reset:
        return ret;
 }
 
-/*
- * Check if the address reported by the CPU is in a format we can parse.
- * It would be possible to add code for most other cases, but all would
- * be somewhat complicated (e.g. segment offset would require an instruction
- * parser). So only support physical addresses up to page granuality for now.
- */
-static int mce_usable_address(struct mce *m)
-{
-       if (!(m->status & MCI_STATUS_MISCV) || !(m->status & MCI_STATUS_ADDRV))
-               return 0;
-       if (MCI_MISC_ADDR_LSB(m->misc) > PAGE_SHIFT)
-               return 0;
-       if (MCI_MISC_ADDR_MODE(m->misc) != MCI_MISC_ADDR_PHYS)
-               return 0;
-       return 1;
-}
-
 static void mce_clear_state(unsigned long *toclear)
 {
        int i;
@@ -999,6 +1002,17 @@ void do_machine_check(struct pt_regs *regs, long error_code)
        int flags = MF_ACTION_REQUIRED;
        int lmce = 0;
 
+       /* If this CPU is offline, just bail out. */
+       if (cpu_is_offline(smp_processor_id())) {
+               u64 mcgstatus;
+
+               mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS);
+               if (mcgstatus & MCG_STATUS_RIPV) {
+                       mce_wrmsrl(MSR_IA32_MCG_STATUS, 0);
+                       return;
+               }
+       }
+
        ist_enter(regs);
 
        this_cpu_inc(mce_exception_count);
@@ -1089,7 +1103,6 @@ void do_machine_check(struct pt_regs *regs, long error_code)
 
                /* assuming valid severity level != 0 */
                m.severity = severity;
-               m.usable_addr = mce_usable_address(&m);
 
                mce_log(&m);
 
index b3e94ef461fddcea5c6d5696eb012b6c9c89edc8..faec7120c508584c9f038445c0dae593cfb5faae 100644 (file)
@@ -129,8 +129,8 @@ void __init load_ucode_bsp(void)
        if (!have_cpuid_p())
                return;
 
-       vendor = x86_vendor();
-       family = x86_family();
+       vendor = x86_cpuid_vendor();
+       family = x86_cpuid_family();
 
        switch (vendor) {
        case X86_VENDOR_INTEL:
@@ -165,8 +165,8 @@ void load_ucode_ap(void)
        if (!have_cpuid_p())
                return;
 
-       vendor = x86_vendor();
-       family = x86_family();
+       vendor = x86_cpuid_vendor();
+       family = x86_cpuid_family();
 
        switch (vendor) {
        case X86_VENDOR_INTEL:
@@ -206,8 +206,8 @@ void reload_early_microcode(void)
 {
        int vendor, family;
 
-       vendor = x86_vendor();
-       family = x86_family();
+       vendor = x86_cpuid_vendor();
+       family = x86_cpuid_family();
 
        switch (vendor) {
        case X86_VENDOR_INTEL:
index ce47402eb2f90a70f44b9902687133da3acbad47..ee81c544ee0daa8f6d8f35569463ba3b9f444f06 100644 (file)
@@ -145,10 +145,10 @@ matching_model_microcode(struct microcode_header_intel *mc_header,
        int ext_sigcount, i;
        struct extended_signature *ext_sig;
 
-       fam   = __x86_family(sig);
+       fam   = x86_family(sig);
        model = x86_model(sig);
 
-       fam_ucode   = __x86_family(mc_header->sig);
+       fam_ucode   = x86_family(mc_header->sig);
        model_ucode = x86_model(mc_header->sig);
 
        if (fam == fam_ucode && model == model_ucode)
@@ -163,7 +163,7 @@ matching_model_microcode(struct microcode_header_intel *mc_header,
        ext_sigcount = ext_header->count;
 
        for (i = 0; i < ext_sigcount; i++) {
-               fam_ucode   = __x86_family(ext_sig->sig);
+               fam_ucode   = x86_family(ext_sig->sig);
                model_ucode = x86_model(ext_sig->sig);
 
                if (fam == fam_ucode && model == model_ucode)
@@ -365,7 +365,7 @@ static int collect_cpu_info_early(struct ucode_cpu_info *uci)
        native_cpuid(&eax, &ebx, &ecx, &edx);
        csig.sig = eax;
 
-       family = __x86_family(csig.sig);
+       family = x86_family(csig.sig);
        model  = x86_model(csig.sig);
 
        if ((model >= 5) || (family > 6)) {
@@ -521,16 +521,12 @@ static bool __init load_builtin_intel_microcode(struct cpio_data *cp)
 {
 #ifdef CONFIG_X86_64
        unsigned int eax = 0x00000001, ebx, ecx = 0, edx;
-       unsigned int family, model, stepping;
        char name[30];
 
        native_cpuid(&eax, &ebx, &ecx, &edx);
 
-       family   = __x86_family(eax);
-       model    = x86_model(eax);
-       stepping = eax & 0xf;
-
-       sprintf(name, "intel-ucode/%02x-%02x-%02x", family, model, stepping);
+       sprintf(name, "intel-ucode/%02x-%02x-%02x",
+                     x86_family(eax), x86_model(eax), x86_stepping(eax));
 
        return get_builtin_firmware(cp, name);
 #else
index 70d7c93f455083e8703f6a37e94dc636432d7b64..0d98503c2245aab81283526c062f746650b99c32 100644 (file)
@@ -593,9 +593,16 @@ mtrr_calc_range_state(u64 chunk_size, u64 gran_size,
                      unsigned long x_remove_base,
                      unsigned long x_remove_size, int i)
 {
-       static struct range range_new[RANGE_NUM];
+       /*
+        * range_new should really be an automatic variable, but
+        * putting 4096 bytes on the stack is frowned upon, to put it
+        * mildly. It is safe to make it a static __initdata variable,
+        * since mtrr_calc_range_state is only called during init and
+        * there's no way it will call itself recursively.
+        */
+       static struct range range_new[RANGE_NUM] __initdata;
        unsigned long range_sums_new;
-       static int nr_range_new;
+       int nr_range_new;
        int num_reg;
 
        /* Convert ranges to var ranges state: */
index 3b533cf37c745c9ecfc81fc5fde94bc46f84e1b5..c870af1610083ec3dda7cb61b966860c9a224374 100644 (file)
@@ -349,7 +349,7 @@ static void get_fixed_ranges(mtrr_type *frs)
 
 void mtrr_save_fixed_ranges(void *info)
 {
-       if (cpu_has_mtrr)
+       if (boot_cpu_has(X86_FEATURE_MTRR))
                get_fixed_ranges(mtrr_state.fixed_ranges);
 }
 
index f891b4750f04c00b296b84598aa396bcbe9724c7..5c3d149ee91cb1f6c87ff6ad1853a38adfce82da 100644 (file)
@@ -682,7 +682,7 @@ void __init mtrr_bp_init(void)
 
        phys_addr = 32;
 
-       if (cpu_has_mtrr) {
+       if (boot_cpu_has(X86_FEATURE_MTRR)) {
                mtrr_if = &generic_mtrr_ops;
                size_or_mask = SIZE_OR_MASK_BITS(36);
                size_and_mask = 0x00f00000;
index 2bf79d7c97dfb8848b1e7b060a66ddedb4605a1a..1b443db2db5005d62ed4e08f918fdfcaa071ac37 100644 (file)
@@ -482,6 +482,9 @@ int x86_pmu_hw_config(struct perf_event *event)
                        /* Support for IP fixup */
                        if (x86_pmu.lbr_nr || x86_pmu.intel_cap.pebs_format >= 2)
                                precise++;
+
+                       if (x86_pmu.pebs_prec_dist)
+                               precise++;
                }
 
                if (event->attr.precise_ip > precise)
@@ -1531,6 +1534,7 @@ static void __init filter_events(struct attribute **attrs)
 {
        struct device_attribute *d;
        struct perf_pmu_events_attr *pmu_attr;
+       int offset = 0;
        int i, j;
 
        for (i = 0; attrs[i]; i++) {
@@ -1539,7 +1543,7 @@ static void __init filter_events(struct attribute **attrs)
                /* str trumps id */
                if (pmu_attr->event_str)
                        continue;
-               if (x86_pmu.event_map(i))
+               if (x86_pmu.event_map(i + offset))
                        continue;
 
                for (j = i; attrs[j]; j++)
@@ -1547,6 +1551,14 @@ static void __init filter_events(struct attribute **attrs)
 
                /* Check the shifted attr. */
                i--;
+
+               /*
+                * event_map() is index based, the attrs array is organized
+                * by increasing event index. If we shift the events, then
+                * we need to compensate for the event_map(), otherwise
+                * we are looking up the wrong event in the map
+                */
+               offset++;
        }
 }
 
@@ -2250,12 +2262,19 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
        ss_base = get_segment_base(regs->ss);
 
        fp = compat_ptr(ss_base + regs->bp);
+       pagefault_disable();
        while (entry->nr < PERF_MAX_STACK_DEPTH) {
                unsigned long bytes;
                frame.next_frame     = 0;
                frame.return_address = 0;
 
-               bytes = copy_from_user_nmi(&frame, fp, sizeof(frame));
+               if (!access_ok(VERIFY_READ, fp, 8))
+                       break;
+
+               bytes = __copy_from_user_nmi(&frame.next_frame, fp, 4);
+               if (bytes != 0)
+                       break;
+               bytes = __copy_from_user_nmi(&frame.return_address, fp+4, 4);
                if (bytes != 0)
                        break;
 
@@ -2265,6 +2284,7 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
                perf_callchain_store(entry, cs_base + frame.return_address);
                fp = compat_ptr(ss_base + frame.next_frame);
        }
+       pagefault_enable();
        return 1;
 }
 #else
@@ -2302,12 +2322,19 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
        if (perf_callchain_user32(regs, entry))
                return;
 
+       pagefault_disable();
        while (entry->nr < PERF_MAX_STACK_DEPTH) {
                unsigned long bytes;
                frame.next_frame             = NULL;
                frame.return_address = 0;
 
-               bytes = copy_from_user_nmi(&frame, fp, sizeof(frame));
+               if (!access_ok(VERIFY_READ, fp, 16))
+                       break;
+
+               bytes = __copy_from_user_nmi(&frame.next_frame, fp, 8);
+               if (bytes != 0)
+                       break;
+               bytes = __copy_from_user_nmi(&frame.return_address, fp+8, 8);
                if (bytes != 0)
                        break;
 
@@ -2315,8 +2342,9 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
                        break;
 
                perf_callchain_store(entry, frame.return_address);
-               fp = frame.next_frame;
+               fp = (void __user *)frame.next_frame;
        }
+       pagefault_enable();
 }
 
 /*
index d0e35ebb2adb1d34b526fcb04b2bc192c643fd55..7bb61e32fb29fdb5ba579005140c0884f1b93754 100644 (file)
 
 #include <linux/perf_event.h>
 
-#if 0
-#undef wrmsrl
-#define wrmsrl(msr, val)                                               \
-do {                                                                   \
-       unsigned int _msr = (msr);                                      \
-       u64 _val = (val);                                               \
-       trace_printk("wrmsrl(%x, %Lx)\n", (unsigned int)(_msr),         \
-                       (unsigned long long)(_val));                    \
-       native_write_msr((_msr), (u32)(_val), (u32)(_val >> 32));       \
-} while (0)
-#endif
+/* To enable MSR tracing please use the generic trace points. */
 
 /*
  *          |   NHM/WSM    |      SNB     |
@@ -318,6 +308,10 @@ struct cpu_hw_events {
 #define INTEL_UEVENT_CONSTRAINT(c, n)  \
        EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK)
 
+/* Constraint on specific umask bit only + event */
+#define INTEL_UBIT_EVENT_CONSTRAINT(c, n)      \
+       EVENT_CONSTRAINT(c, n, ARCH_PERFMON_EVENTSEL_EVENT|(c))
+
 /* Like UEVENT_CONSTRAINT, but match flags too */
 #define INTEL_FLAGS_UEVENT_CONSTRAINT(c, n)    \
        EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS)
@@ -589,7 +583,8 @@ struct x86_pmu {
                        bts_active      :1,
                        pebs            :1,
                        pebs_active     :1,
-                       pebs_broken     :1;
+                       pebs_broken     :1,
+                       pebs_prec_dist  :1;
        int             pebs_record_size;
        void            (*drain_pebs)(struct pt_regs *regs);
        struct event_constraint *pebs_constraints;
@@ -907,6 +902,8 @@ void intel_pmu_lbr_init_hsw(void);
 
 void intel_pmu_lbr_init_skl(void);
 
+void intel_pmu_lbr_init_knl(void);
+
 int intel_pmu_setup_lbr_filter(struct perf_event *event);
 
 void intel_pt_interrupt(void);
index 1cee5d2d7eceafde5d5545dac8227c55f8097386..58610539b0486ec30a357467e2425a4cdc5c5fd0 100644 (file)
@@ -18,7 +18,7 @@ static __initconst const u64 amd_hw_cache_event_ids
                [ C(RESULT_MISS)   ] = 0x0141, /* Data Cache Misses          */
        },
        [ C(OP_WRITE) ] = {
-               [ C(RESULT_ACCESS) ] = 0x0142, /* Data Cache Refills :system */
+               [ C(RESULT_ACCESS) ] = 0,
                [ C(RESULT_MISS)   ] = 0,
        },
        [ C(OP_PREFETCH) ] = {
@@ -160,7 +160,7 @@ static inline int amd_pmu_addr_offset(int index, bool eventsel)
        if (offset)
                return offset;
 
-       if (!cpu_has_perfctr_core)
+       if (!boot_cpu_has(X86_FEATURE_PERFCTR_CORE))
                offset = index;
        else
                offset = index << 1;
@@ -652,7 +652,7 @@ static __initconst const struct x86_pmu amd_pmu = {
 
 static int __init amd_core_pmu_init(void)
 {
-       if (!cpu_has_perfctr_core)
+       if (!boot_cpu_has(X86_FEATURE_PERFCTR_CORE))
                return 0;
 
        switch (boot_cpu_data.x86) {
index cc6cedb8f25d5da565f09c612eb612a0eb7db701..49742746a6c963c4a86c08c773430087225fec53 100644 (file)
@@ -523,10 +523,10 @@ static int __init amd_uncore_init(void)
        if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
                goto fail_nodev;
 
-       if (!cpu_has_topoext)
+       if (!boot_cpu_has(X86_FEATURE_TOPOEXT))
                goto fail_nodev;
 
-       if (cpu_has_perfctr_nb) {
+       if (boot_cpu_has(X86_FEATURE_PERFCTR_NB)) {
                amd_uncore_nb = alloc_percpu(struct amd_uncore *);
                if (!amd_uncore_nb) {
                        ret = -ENOMEM;
@@ -540,7 +540,7 @@ static int __init amd_uncore_init(void)
                ret = 0;
        }
 
-       if (cpu_has_perfctr_l2) {
+       if (boot_cpu_has(X86_FEATURE_PERFCTR_L2)) {
                amd_uncore_l2 = alloc_percpu(struct amd_uncore *);
                if (!amd_uncore_l2) {
                        ret = -ENOMEM;
@@ -583,10 +583,11 @@ fail_online:
 
        /* amd_uncore_nb/l2 should have been freed by cleanup_cpu_online */
        amd_uncore_nb = amd_uncore_l2 = NULL;
-       if (cpu_has_perfctr_l2)
+
+       if (boot_cpu_has(X86_FEATURE_PERFCTR_L2))
                perf_pmu_unregister(&amd_l2_pmu);
 fail_l2:
-       if (cpu_has_perfctr_nb)
+       if (boot_cpu_has(X86_FEATURE_PERFCTR_NB))
                perf_pmu_unregister(&amd_nb_pmu);
        if (amd_uncore_l2)
                free_percpu(amd_uncore_l2);
index e2a430021e46e71eb2904af74ae5a7d50653d048..a667078a51807bb5bd1ca2e5d5c4ff205e9dd42b 100644 (file)
@@ -185,6 +185,14 @@ struct event_constraint intel_skl_event_constraints[] = {
        EVENT_CONSTRAINT_END
 };
 
+static struct extra_reg intel_knl_extra_regs[] __read_mostly = {
+       INTEL_UEVENT_EXTRA_REG(0x01b7,
+                              MSR_OFFCORE_RSP_0, 0x7f9ffbffffull, RSP_0),
+       INTEL_UEVENT_EXTRA_REG(0x02b7,
+                              MSR_OFFCORE_RSP_1, 0x3f9ffbffffull, RSP_1),
+       EVENT_EXTRA_END
+};
+
 static struct extra_reg intel_snb_extra_regs[] __read_mostly = {
        /* must define OFFCORE_RSP_X first, see intel_fixup_er() */
        INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0x3f807f8fffull, RSP_0),
@@ -255,7 +263,7 @@ struct event_constraint intel_bdw_event_constraints[] = {
        FIXED_EVENT_CONSTRAINT(0x003c, 1),      /* CPU_CLK_UNHALTED.CORE */
        FIXED_EVENT_CONSTRAINT(0x0300, 2),      /* CPU_CLK_UNHALTED.REF */
        INTEL_UEVENT_CONSTRAINT(0x148, 0x4),    /* L1D_PEND_MISS.PENDING */
-       INTEL_UEVENT_CONSTRAINT(0x8a3, 0x4),    /* CYCLE_ACTIVITY.CYCLES_L1D_MISS */
+       INTEL_UBIT_EVENT_CONSTRAINT(0x8a3, 0x4),        /* CYCLE_ACTIVITY.CYCLES_L1D_MISS */
        EVENT_CONSTRAINT_END
 };
 
@@ -1457,6 +1465,42 @@ static __initconst const u64 slm_hw_cache_event_ids
  },
 };
 
+#define KNL_OT_L2_HITE         BIT_ULL(19) /* Other Tile L2 Hit */
+#define KNL_OT_L2_HITF         BIT_ULL(20) /* Other Tile L2 Hit */
+#define KNL_MCDRAM_LOCAL       BIT_ULL(21)
+#define KNL_MCDRAM_FAR         BIT_ULL(22)
+#define KNL_DDR_LOCAL          BIT_ULL(23)
+#define KNL_DDR_FAR            BIT_ULL(24)
+#define KNL_DRAM_ANY           (KNL_MCDRAM_LOCAL | KNL_MCDRAM_FAR | \
+                                   KNL_DDR_LOCAL | KNL_DDR_FAR)
+#define KNL_L2_READ            SLM_DMND_READ
+#define KNL_L2_WRITE           SLM_DMND_WRITE
+#define KNL_L2_PREFETCH                SLM_DMND_PREFETCH
+#define KNL_L2_ACCESS          SLM_LLC_ACCESS
+#define KNL_L2_MISS            (KNL_OT_L2_HITE | KNL_OT_L2_HITF | \
+                                  KNL_DRAM_ANY | SNB_SNP_ANY | \
+                                                 SNB_NON_DRAM)
+
+static __initconst const u64 knl_hw_cache_extra_regs
+                               [PERF_COUNT_HW_CACHE_MAX]
+                               [PERF_COUNT_HW_CACHE_OP_MAX]
+                               [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+       [C(LL)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)] = KNL_L2_READ | KNL_L2_ACCESS,
+                       [C(RESULT_MISS)]   = 0,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)] = KNL_L2_WRITE | KNL_L2_ACCESS,
+                       [C(RESULT_MISS)]   = KNL_L2_WRITE | KNL_L2_MISS,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)] = KNL_L2_PREFETCH | KNL_L2_ACCESS,
+                       [C(RESULT_MISS)]   = KNL_L2_PREFETCH | KNL_L2_MISS,
+               },
+       },
+};
+
 /*
  * Use from PMIs where the LBRs are already disabled.
  */
@@ -2475,6 +2519,44 @@ static void intel_pebs_aliases_snb(struct perf_event *event)
        }
 }
 
+static void intel_pebs_aliases_precdist(struct perf_event *event)
+{
+       if ((event->hw.config & X86_RAW_EVENT_MASK) == 0x003c) {
+               /*
+                * Use an alternative encoding for CPU_CLK_UNHALTED.THREAD_P
+                * (0x003c) so that we can use it with PEBS.
+                *
+                * The regular CPU_CLK_UNHALTED.THREAD_P event (0x003c) isn't
+                * PEBS capable. However we can use INST_RETIRED.PREC_DIST
+                * (0x01c0), which is a PEBS capable event, to get the same
+                * count.
+                *
+                * The PREC_DIST event has special support to minimize sample
+                * shadowing effects. One drawback is that it can be
+                * only programmed on counter 1, but that seems like an
+                * acceptable trade off.
+                */
+               u64 alt_config = X86_CONFIG(.event=0xc0, .umask=0x01, .inv=1, .cmask=16);
+
+               alt_config |= (event->hw.config & ~X86_RAW_EVENT_MASK);
+               event->hw.config = alt_config;
+       }
+}
+
+static void intel_pebs_aliases_ivb(struct perf_event *event)
+{
+       if (event->attr.precise_ip < 3)
+               return intel_pebs_aliases_snb(event);
+       return intel_pebs_aliases_precdist(event);
+}
+
+static void intel_pebs_aliases_skl(struct perf_event *event)
+{
+       if (event->attr.precise_ip < 3)
+               return intel_pebs_aliases_core2(event);
+       return intel_pebs_aliases_precdist(event);
+}
+
 static unsigned long intel_pmu_free_running_flags(struct perf_event *event)
 {
        unsigned long flags = x86_pmu.free_running_flags;
@@ -3332,6 +3414,7 @@ __init int intel_pmu_init(void)
 
                x86_pmu.event_constraints = intel_gen_event_constraints;
                x86_pmu.pebs_constraints = intel_atom_pebs_event_constraints;
+               x86_pmu.pebs_aliases = intel_pebs_aliases_core2;
                pr_cont("Atom events, ");
                break;
 
@@ -3431,7 +3514,8 @@ __init int intel_pmu_init(void)
 
                x86_pmu.event_constraints = intel_ivb_event_constraints;
                x86_pmu.pebs_constraints = intel_ivb_pebs_event_constraints;
-               x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
+               x86_pmu.pebs_aliases = intel_pebs_aliases_ivb;
+               x86_pmu.pebs_prec_dist = true;
                if (boot_cpu_data.x86_model == 62)
                        x86_pmu.extra_regs = intel_snbep_extra_regs;
                else
@@ -3464,7 +3548,8 @@ __init int intel_pmu_init(void)
                x86_pmu.event_constraints = intel_hsw_event_constraints;
                x86_pmu.pebs_constraints = intel_hsw_pebs_event_constraints;
                x86_pmu.extra_regs = intel_snbep_extra_regs;
-               x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
+               x86_pmu.pebs_aliases = intel_pebs_aliases_ivb;
+               x86_pmu.pebs_prec_dist = true;
                /* all extra regs are per-cpu when HT is on */
                x86_pmu.flags |= PMU_FL_HAS_RSP_1;
                x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
@@ -3499,7 +3584,8 @@ __init int intel_pmu_init(void)
                x86_pmu.event_constraints = intel_bdw_event_constraints;
                x86_pmu.pebs_constraints = intel_hsw_pebs_event_constraints;
                x86_pmu.extra_regs = intel_snbep_extra_regs;
-               x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
+               x86_pmu.pebs_aliases = intel_pebs_aliases_ivb;
+               x86_pmu.pebs_prec_dist = true;
                /* all extra regs are per-cpu when HT is on */
                x86_pmu.flags |= PMU_FL_HAS_RSP_1;
                x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
@@ -3511,6 +3597,24 @@ __init int intel_pmu_init(void)
                pr_cont("Broadwell events, ");
                break;
 
+       case 87: /* Knights Landing Xeon Phi */
+               memcpy(hw_cache_event_ids,
+                      slm_hw_cache_event_ids, sizeof(hw_cache_event_ids));
+               memcpy(hw_cache_extra_regs,
+                      knl_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
+               intel_pmu_lbr_init_knl();
+
+               x86_pmu.event_constraints = intel_slm_event_constraints;
+               x86_pmu.pebs_constraints = intel_slm_pebs_event_constraints;
+               x86_pmu.extra_regs = intel_knl_extra_regs;
+
+               /* all extra regs are per-cpu when HT is on */
+               x86_pmu.flags |= PMU_FL_HAS_RSP_1;
+               x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
+
+               pr_cont("Knights Landing events, ");
+               break;
+
        case 78: /* 14nm Skylake Mobile */
        case 94: /* 14nm Skylake Desktop */
                x86_pmu.late_ack = true;
@@ -3521,7 +3625,8 @@ __init int intel_pmu_init(void)
                x86_pmu.event_constraints = intel_skl_event_constraints;
                x86_pmu.pebs_constraints = intel_skl_pebs_event_constraints;
                x86_pmu.extra_regs = intel_skl_extra_regs;
-               x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
+               x86_pmu.pebs_aliases = intel_pebs_aliases_skl;
+               x86_pmu.pebs_prec_dist = true;
                /* all extra regs are per-cpu when HT is on */
                x86_pmu.flags |= PMU_FL_HAS_RSP_1;
                x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
index 5db1c7755548e2ad472b2fbe5541125a45d90376..10602f0a438fdab19311ff63bdcf014d27d3596a 100644 (file)
@@ -620,6 +620,8 @@ struct event_constraint intel_atom_pebs_event_constraints[] = {
        INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0x1),    /* MEM_LOAD_RETIRED.* */
        /* INST_RETIRED.ANY_P, inv=1, cmask=16 (cycles:p). */
        INTEL_FLAGS_EVENT_CONSTRAINT(0x108000c0, 0x01),
+       /* Allow all events as PEBS with no flags */
+       INTEL_ALL_EVENT_CONSTRAINT(0, 0x1),
        EVENT_CONSTRAINT_END
 };
 
@@ -686,6 +688,8 @@ struct event_constraint intel_ivb_pebs_event_constraints[] = {
        INTEL_PST_CONSTRAINT(0x02cd, 0x8),    /* MEM_TRANS_RETIRED.PRECISE_STORES */
        /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
        INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+       /* INST_RETIRED.PREC_DIST, inv=1, cmask=16 (cycles:ppp). */
+       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c0, 0x2),
        INTEL_EXCLEVT_CONSTRAINT(0xd0, 0xf),    /* MEM_UOP_RETIRED.* */
        INTEL_EXCLEVT_CONSTRAINT(0xd1, 0xf),    /* MEM_LOAD_UOPS_RETIRED.* */
        INTEL_EXCLEVT_CONSTRAINT(0xd2, 0xf),    /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */
@@ -700,6 +704,8 @@ struct event_constraint intel_hsw_pebs_event_constraints[] = {
        INTEL_PLD_CONSTRAINT(0x01cd, 0xf),    /* MEM_TRANS_RETIRED.* */
        /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
        INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+       /* INST_RETIRED.PREC_DIST, inv=1, cmask=16 (cycles:ppp). */
+       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c0, 0x2),
        INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
        INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD(0x11d0, 0xf), /* MEM_UOPS_RETIRED.STLB_MISS_LOADS */
        INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD(0x21d0, 0xf), /* MEM_UOPS_RETIRED.LOCK_LOADS */
@@ -718,9 +724,10 @@ struct event_constraint intel_hsw_pebs_event_constraints[] = {
 
 struct event_constraint intel_skl_pebs_event_constraints[] = {
        INTEL_FLAGS_UEVENT_CONSTRAINT(0x1c0, 0x2),      /* INST_RETIRED.PREC_DIST */
-       INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
-       /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
-       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+       /* INST_RETIRED.PREC_DIST, inv=1, cmask=16 (cycles:ppp). */
+       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c0, 0x2),
+       /* INST_RETIRED.TOTAL_CYCLES_PS (inv=1, cmask=16) (cycles:p). */
+       INTEL_FLAGS_EVENT_CONSTRAINT(0x108000c0, 0x0f),
        INTEL_PLD_CONSTRAINT(0x1cd, 0xf),                     /* MEM_TRANS_RETIRED.* */
        INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x11d0, 0xf), /* MEM_INST_RETIRED.STLB_MISS_LOADS */
        INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x12d0, 0xf), /* MEM_INST_RETIRED.STLB_MISS_STORES */
@@ -1101,6 +1108,13 @@ get_next_pebs_record_by_bit(void *base, void *top, int bit)
        void *at;
        u64 pebs_status;
 
+       /*
+        * fmt0 does not have a status bitfield (does not use
+        * perf_record_nhm format)
+        */
+       if (x86_pmu.intel_cap.pebs_format < 1)
+               return base;
+
        if (base == NULL)
                return NULL;
 
@@ -1186,7 +1200,7 @@ static void intel_pmu_drain_pebs_core(struct pt_regs *iregs)
        if (!event->attr.precise_ip)
                return;
 
-       n = (top - at) / x86_pmu.pebs_record_size;
+       n = top - at;
        if (n <= 0)
                return;
 
@@ -1230,12 +1244,21 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
                pebs_status = p->status & cpuc->pebs_enabled;
                pebs_status &= (1ULL << x86_pmu.max_pebs_events) - 1;
 
+               /*
+                * On some CPUs the PEBS status can be zero when PEBS is
+                * racing with clearing of GLOBAL_STATUS.
+                *
+                * Normally we would drop that record, but in the
+                * case when there is only a single active PEBS event
+                * we can assume it's for that event.
+                */
+               if (!pebs_status && cpuc->pebs_enabled &&
+                       !(cpuc->pebs_enabled & (cpuc->pebs_enabled-1)))
+                       pebs_status = cpuc->pebs_enabled;
+
                bit = find_first_bit((unsigned long *)&pebs_status,
                                        x86_pmu.max_pebs_events);
-               if (WARN(bit >= x86_pmu.max_pebs_events,
-                        "PEBS record without PEBS event! status=%Lx pebs_enabled=%Lx active_mask=%Lx",
-                        (unsigned long long)p->status, (unsigned long long)cpuc->pebs_enabled,
-                        *(unsigned long long *)cpuc->active_mask))
+               if (bit >= x86_pmu.max_pebs_events)
                        continue;
 
                /*
index 659f01e165d57520f33b09ba68818f72cd206a4d..653f88d259878e90eb4901010ace8e16ff21e231 100644 (file)
@@ -42,6 +42,13 @@ static enum {
 #define LBR_FAR_BIT            8 /* do not capture far branches */
 #define LBR_CALL_STACK_BIT     9 /* enable call stack */
 
+/*
+ * Following bit only exists in Linux; we mask it out before writing it to
+ * the actual MSR. But it helps the constraint perf code to understand
+ * that this is a separate configuration.
+ */
+#define LBR_NO_INFO_BIT               63 /* don't read LBR_INFO. */
+
 #define LBR_KERNEL     (1 << LBR_KERNEL_BIT)
 #define LBR_USER       (1 << LBR_USER_BIT)
 #define LBR_JCC                (1 << LBR_JCC_BIT)
@@ -52,6 +59,7 @@ static enum {
 #define LBR_IND_JMP    (1 << LBR_IND_JMP_BIT)
 #define LBR_FAR                (1 << LBR_FAR_BIT)
 #define LBR_CALL_STACK (1 << LBR_CALL_STACK_BIT)
+#define LBR_NO_INFO    (1ULL << LBR_NO_INFO_BIT)
 
 #define LBR_PLM (LBR_KERNEL | LBR_USER)
 
@@ -152,8 +160,8 @@ static void __intel_pmu_lbr_enable(bool pmi)
         * did not change.
         */
        if (cpuc->lbr_sel)
-               lbr_select = cpuc->lbr_sel->config;
-       if (!pmi)
+               lbr_select = cpuc->lbr_sel->config & x86_pmu.lbr_sel_mask;
+       if (!pmi && cpuc->lbr_sel)
                wrmsrl(MSR_LBR_SELECT, lbr_select);
 
        rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
@@ -422,6 +430,7 @@ static void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc)
  */
 static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
 {
+       bool need_info = false;
        unsigned long mask = x86_pmu.lbr_nr - 1;
        int lbr_format = x86_pmu.intel_cap.lbr_format;
        u64 tos = intel_pmu_lbr_tos();
@@ -429,8 +438,11 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
        int out = 0;
        int num = x86_pmu.lbr_nr;
 
-       if (cpuc->lbr_sel->config & LBR_CALL_STACK)
-               num = tos;
+       if (cpuc->lbr_sel) {
+               need_info = !(cpuc->lbr_sel->config & LBR_NO_INFO);
+               if (cpuc->lbr_sel->config & LBR_CALL_STACK)
+                       num = tos;
+       }
 
        for (i = 0; i < num; i++) {
                unsigned long lbr_idx = (tos - i) & mask;
@@ -442,7 +454,7 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
                rdmsrl(x86_pmu.lbr_from + lbr_idx, from);
                rdmsrl(x86_pmu.lbr_to   + lbr_idx, to);
 
-               if (lbr_format == LBR_FORMAT_INFO) {
+               if (lbr_format == LBR_FORMAT_INFO && need_info) {
                        u64 info;
 
                        rdmsrl(MSR_LBR_INFO_0 + lbr_idx, info);
@@ -590,6 +602,7 @@ static int intel_pmu_setup_hw_lbr_filter(struct perf_event *event)
                if (v != LBR_IGN)
                        mask |= v;
        }
+
        reg = &event->hw.branch_reg;
        reg->idx = EXTRA_REG_LBR;
 
@@ -600,6 +613,11 @@ static int intel_pmu_setup_hw_lbr_filter(struct perf_event *event)
         */
        reg->config = mask ^ x86_pmu.lbr_sel_mask;
 
+       if ((br_type & PERF_SAMPLE_BRANCH_NO_CYCLES) &&
+           (br_type & PERF_SAMPLE_BRANCH_NO_FLAGS) &&
+           (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO))
+               reg->config |= LBR_NO_INFO;
+
        return 0;
 }
 
@@ -1028,3 +1046,17 @@ void __init intel_pmu_lbr_init_atom(void)
         */
        pr_cont("8-deep LBR, ");
 }
+
+/* Knights Landing */
+void intel_pmu_lbr_init_knl(void)
+{
+       x86_pmu.lbr_nr     = 8;
+       x86_pmu.lbr_tos    = MSR_LBR_TOS;
+       x86_pmu.lbr_from   = MSR_LBR_NHM_FROM;
+       x86_pmu.lbr_to     = MSR_LBR_NHM_TO;
+
+       x86_pmu.lbr_sel_mask = LBR_SEL_MASK;
+       x86_pmu.lbr_sel_map  = snb_lbr_sel_map;
+
+       pr_cont("8-deep LBR, ");
+}
index 868e1194337f6cf93cd1a8048480a60aa7acf3e3..c0bbd1033b7cb380afea0379a015b5a12e179824 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/perf_event.h>
 #include <asm/insn.h>
 #include <asm/io.h>
+#include <asm/intel_pt.h>
 
 #include "perf_event.h"
 #include "intel_pt.h"
@@ -1122,6 +1123,14 @@ static int pt_event_init(struct perf_event *event)
        return 0;
 }
 
+void cpu_emergency_stop_pt(void)
+{
+       struct pt *pt = this_cpu_ptr(&pt_ctx);
+
+       if (pt->handle.event)
+               pt_event_stop(pt->handle.event, PERF_EF_UPDATE);
+}
+
 static __init int pt_init(void)
 {
        int ret, cpu, prior_warn = 0;
index ed446bdcbf312daa9587a593fc1552cda4714dd3..24a351ad628d2cbf5d60da7287a85f000f7cb24d 100644 (file)
@@ -63,7 +63,7 @@
 #define INTEL_RAPL_PP1         0x4     /* pseudo-encoding */
 
 #define NR_RAPL_DOMAINS         0x4
-static const char *rapl_domain_names[NR_RAPL_DOMAINS] __initconst = {
+static const char *const rapl_domain_names[NR_RAPL_DOMAINS] __initconst = {
        "pp0-core",
        "package",
        "dram",
@@ -109,11 +109,11 @@ static struct kobj_attribute format_attr_##_var =         \
 
 #define RAPL_CNTR_WIDTH 32 /* 32-bit rapl counters */
 
-#define RAPL_EVENT_ATTR_STR(_name, v, str)                             \
-static struct perf_pmu_events_attr event_attr_##v = {                  \
-       .attr           = __ATTR(_name, 0444, rapl_sysfs_show, NULL),   \
-       .id             = 0,                                            \
-       .event_str      = str,                                          \
+#define RAPL_EVENT_ATTR_STR(_name, v, str)                                     \
+static struct perf_pmu_events_attr event_attr_##v = {                          \
+       .attr           = __ATTR(_name, 0444, perf_event_sysfs_show, NULL),     \
+       .id             = 0,                                                    \
+       .event_str      = str,                                                  \
 };
 
 struct rapl_pmu {
@@ -405,19 +405,6 @@ static struct attribute_group rapl_pmu_attr_group = {
        .attrs = rapl_pmu_attrs,
 };
 
-static ssize_t rapl_sysfs_show(struct device *dev,
-                              struct device_attribute *attr,
-                              char *page)
-{
-       struct perf_pmu_events_attr *pmu_attr = \
-               container_of(attr, struct perf_pmu_events_attr, attr);
-
-       if (pmu_attr->event_str)
-               return sprintf(page, "%s", pmu_attr->event_str);
-
-       return 0;
-}
-
 RAPL_EVENT_ATTR_STR(energy-cores, rapl_cores, "event=0x01");
 RAPL_EVENT_ATTR_STR(energy-pkg  ,   rapl_pkg, "event=0x02");
 RAPL_EVENT_ATTR_STR(energy-ram  ,   rapl_ram, "event=0x03");
index 61215a69b03d928d83dc6e86950bd5ad1b2db68c..f97f8075bf04c9d6efed980370feca46227afc5a 100644 (file)
@@ -884,6 +884,15 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id
         * each box has a different function id.
         */
        pmu = &type->pmus[UNCORE_PCI_DEV_IDX(id->driver_data)];
+       /* Knights Landing uses a common PCI device ID for multiple instances of
+        * an uncore PMU device type. There is only one entry per device type in
+        * the knl_uncore_pci_ids table inspite of multiple devices present for
+        * some device types. Hence PCI device idx would be 0 for all devices.
+        * So increment pmu pointer to point to an unused array element.
+        */
+       if (boot_cpu_data.x86_model == 87)
+               while (pmu->func_id >= 0)
+                       pmu++;
        if (pmu->func_id < 0)
                pmu->func_id = pdev->devfn;
        else
@@ -966,6 +975,7 @@ static int __init uncore_pci_init(void)
        case 63: /* Haswell-EP */
                ret = hswep_uncore_pci_init();
                break;
+       case 79: /* BDX-EP */
        case 86: /* BDX-DE */
                ret = bdx_uncore_pci_init();
                break;
@@ -982,6 +992,9 @@ static int __init uncore_pci_init(void)
        case 61: /* Broadwell */
                ret = bdw_uncore_pci_init();
                break;
+       case 87: /* Knights Landing */
+               ret = knl_uncore_pci_init();
+               break;
        default:
                return 0;
        }
@@ -1287,9 +1300,13 @@ static int __init uncore_cpu_init(void)
        case 63: /* Haswell-EP */
                hswep_uncore_cpu_init();
                break;
+       case 79: /* BDX-EP */
        case 86: /* BDX-DE */
                bdx_uncore_cpu_init();
                break;
+       case 87: /* Knights Landing */
+               knl_uncore_cpu_init();
+               break;
        default:
                return 0;
        }
index 2f0a4a98e16bee4bcadde4591daab3be6e7c08cf..07aa2d6bd71094e411a9f98535fc4c65208a66d4 100644 (file)
@@ -338,6 +338,7 @@ int hsw_uncore_pci_init(void);
 int bdw_uncore_pci_init(void);
 void snb_uncore_cpu_init(void);
 void nhm_uncore_cpu_init(void);
+int snb_pci2phy_map_init(int devid);
 
 /* perf_event_intel_uncore_snbep.c */
 int snbep_uncore_pci_init(void);
@@ -348,6 +349,8 @@ int hswep_uncore_pci_init(void);
 void hswep_uncore_cpu_init(void);
 int bdx_uncore_pci_init(void);
 void bdx_uncore_cpu_init(void);
+int knl_uncore_pci_init(void);
+void knl_uncore_cpu_init(void);
 
 /* perf_event_intel_uncore_nhmex.c */
 void nhmex_uncore_cpu_init(void);
index 845256158a10d79fdcc9ebd4946ca20c1b468277..0b934820fafd1f64747640e09f1544b862eb8c01 100644 (file)
@@ -417,7 +417,7 @@ static void snb_uncore_imc_event_del(struct perf_event *event, int flags)
        }
 }
 
-static int snb_pci2phy_map_init(int devid)
+int snb_pci2phy_map_init(int devid)
 {
        struct pci_dev *dev = NULL;
        struct pci2phy_map *map;
index f0f4fcba252e1545fc21d8d215329a631c471aac..33acb884ccf1be9cfb9cda72ac5e27ae666e64d6 100644 (file)
 #define HSWEP_PCU_MSR_PMON_BOX_CTL             0x710
 #define HSWEP_PCU_MSR_PMON_BOX_FILTER          0x715
 
+/* KNL Ubox */
+#define KNL_U_MSR_PMON_RAW_EVENT_MASK \
+                                       (SNBEP_U_MSR_PMON_RAW_EVENT_MASK | \
+                                               SNBEP_CBO_PMON_CTL_TID_EN)
+/* KNL CHA */
+#define KNL_CHA_MSR_OFFSET                     0xc
+#define KNL_CHA_MSR_PMON_CTL_QOR               (1 << 16)
+#define KNL_CHA_MSR_PMON_RAW_EVENT_MASK \
+                                       (SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK | \
+                                        KNL_CHA_MSR_PMON_CTL_QOR)
+#define KNL_CHA_MSR_PMON_BOX_FILTER_TID                0x1ff
+#define KNL_CHA_MSR_PMON_BOX_FILTER_STATE      (7 << 18)
+#define KNL_CHA_MSR_PMON_BOX_FILTER_OP         (0xfffffe2aULL << 32)
+
+/* KNL EDC/MC UCLK */
+#define KNL_UCLK_MSR_PMON_CTR0_LOW             0x400
+#define KNL_UCLK_MSR_PMON_CTL0                 0x420
+#define KNL_UCLK_MSR_PMON_BOX_CTL              0x430
+#define KNL_UCLK_MSR_PMON_UCLK_FIXED_LOW       0x44c
+#define KNL_UCLK_MSR_PMON_UCLK_FIXED_CTL       0x454
+#define KNL_PMON_FIXED_CTL_EN                  0x1
+
+/* KNL EDC */
+#define KNL_EDC0_ECLK_MSR_PMON_CTR0_LOW                0xa00
+#define KNL_EDC0_ECLK_MSR_PMON_CTL0            0xa20
+#define KNL_EDC0_ECLK_MSR_PMON_BOX_CTL         0xa30
+#define KNL_EDC0_ECLK_MSR_PMON_ECLK_FIXED_LOW  0xa3c
+#define KNL_EDC0_ECLK_MSR_PMON_ECLK_FIXED_CTL  0xa44
+
+/* KNL MC */
+#define KNL_MC0_CH0_MSR_PMON_CTR0_LOW          0xb00
+#define KNL_MC0_CH0_MSR_PMON_CTL0              0xb20
+#define KNL_MC0_CH0_MSR_PMON_BOX_CTL           0xb30
+#define KNL_MC0_CH0_MSR_PMON_FIXED_LOW         0xb3c
+#define KNL_MC0_CH0_MSR_PMON_FIXED_CTL         0xb44
+
+/* KNL IRP */
+#define KNL_IRP_PCI_PMON_BOX_CTL               0xf0
+#define KNL_IRP_PCI_PMON_RAW_EVENT_MASK                (SNBEP_PMON_RAW_EVENT_MASK | \
+                                                KNL_CHA_MSR_PMON_CTL_QOR)
+/* KNL PCU */
+#define KNL_PCU_PMON_CTL_EV_SEL_MASK           0x0000007f
+#define KNL_PCU_PMON_CTL_USE_OCC_CTR           (1 << 7)
+#define KNL_PCU_MSR_PMON_CTL_TRESH_MASK                0x3f000000
+#define KNL_PCU_MSR_PMON_RAW_EVENT_MASK        \
+                               (KNL_PCU_PMON_CTL_EV_SEL_MASK | \
+                                KNL_PCU_PMON_CTL_USE_OCC_CTR | \
+                                SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \
+                                SNBEP_PMON_CTL_EDGE_DET | \
+                                SNBEP_CBO_PMON_CTL_TID_EN | \
+                                SNBEP_PMON_CTL_EV_SEL_EXT | \
+                                SNBEP_PMON_CTL_INVERT | \
+                                KNL_PCU_MSR_PMON_CTL_TRESH_MASK | \
+                                SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \
+                                SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET)
 
 DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
+DEFINE_UNCORE_FORMAT_ATTR(event2, event, "config:0-6");
 DEFINE_UNCORE_FORMAT_ATTR(event_ext, event, "config:0-7,21");
+DEFINE_UNCORE_FORMAT_ATTR(use_occ_ctr, use_occ_ctr, "config:7");
 DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(qor, qor, "config:16");
 DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
 DEFINE_UNCORE_FORMAT_ATTR(tid_en, tid_en, "config:19");
 DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23");
 DEFINE_UNCORE_FORMAT_ATTR(thresh8, thresh, "config:24-31");
+DEFINE_UNCORE_FORMAT_ATTR(thresh6, thresh, "config:24-29");
 DEFINE_UNCORE_FORMAT_ATTR(thresh5, thresh, "config:24-28");
 DEFINE_UNCORE_FORMAT_ATTR(occ_sel, occ_sel, "config:14-15");
 DEFINE_UNCORE_FORMAT_ATTR(occ_invert, occ_invert, "config:30");
 DEFINE_UNCORE_FORMAT_ATTR(occ_edge, occ_edge, "config:14-51");
+DEFINE_UNCORE_FORMAT_ATTR(occ_edge_det, occ_edge_det, "config:31");
 DEFINE_UNCORE_FORMAT_ATTR(filter_tid, filter_tid, "config1:0-4");
 DEFINE_UNCORE_FORMAT_ATTR(filter_tid2, filter_tid, "config1:0");
 DEFINE_UNCORE_FORMAT_ATTR(filter_tid3, filter_tid, "config1:0-5");
+DEFINE_UNCORE_FORMAT_ATTR(filter_tid4, filter_tid, "config1:0-8");
 DEFINE_UNCORE_FORMAT_ATTR(filter_cid, filter_cid, "config1:5");
 DEFINE_UNCORE_FORMAT_ATTR(filter_link, filter_link, "config1:5-8");
 DEFINE_UNCORE_FORMAT_ATTR(filter_link2, filter_link, "config1:6-8");
+DEFINE_UNCORE_FORMAT_ATTR(filter_link3, filter_link, "config1:12");
 DEFINE_UNCORE_FORMAT_ATTR(filter_nid, filter_nid, "config1:10-17");
 DEFINE_UNCORE_FORMAT_ATTR(filter_nid2, filter_nid, "config1:32-47");
 DEFINE_UNCORE_FORMAT_ATTR(filter_state, filter_state, "config1:18-22");
 DEFINE_UNCORE_FORMAT_ATTR(filter_state2, filter_state, "config1:17-22");
 DEFINE_UNCORE_FORMAT_ATTR(filter_state3, filter_state, "config1:17-23");
+DEFINE_UNCORE_FORMAT_ATTR(filter_state4, filter_state, "config1:18-20");
+DEFINE_UNCORE_FORMAT_ATTR(filter_local, filter_local, "config1:33");
+DEFINE_UNCORE_FORMAT_ATTR(filter_all_op, filter_all_op, "config1:35");
+DEFINE_UNCORE_FORMAT_ATTR(filter_nnm, filter_nnm, "config1:37");
 DEFINE_UNCORE_FORMAT_ATTR(filter_opc, filter_opc, "config1:23-31");
 DEFINE_UNCORE_FORMAT_ATTR(filter_opc2, filter_opc, "config1:52-60");
+DEFINE_UNCORE_FORMAT_ATTR(filter_opc3, filter_opc, "config1:41-60");
 DEFINE_UNCORE_FORMAT_ATTR(filter_nc, filter_nc, "config1:62");
 DEFINE_UNCORE_FORMAT_ATTR(filter_c6, filter_c6, "config1:61");
 DEFINE_UNCORE_FORMAT_ATTR(filter_isoc, filter_isoc, "config1:63");
@@ -315,8 +382,9 @@ static u64 snbep_uncore_pci_read_counter(struct intel_uncore_box *box, struct pe
 static void snbep_uncore_pci_init_box(struct intel_uncore_box *box)
 {
        struct pci_dev *pdev = box->pci_dev;
+       int box_ctl = uncore_pci_box_ctl(box);
 
-       pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, SNBEP_PMON_BOX_CTL_INT);
+       pci_write_config_dword(pdev, box_ctl, SNBEP_PMON_BOX_CTL_INT);
 }
 
 static void snbep_uncore_msr_disable_box(struct intel_uncore_box *box)
@@ -1728,6 +1796,419 @@ int ivbep_uncore_pci_init(void)
 }
 /* end of IvyTown uncore support */
 
+/* KNL uncore support */
+static struct attribute *knl_uncore_ubox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_tid_en.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh5.attr,
+       NULL,
+};
+
+static struct attribute_group knl_uncore_ubox_format_group = {
+       .name = "format",
+       .attrs = knl_uncore_ubox_formats_attr,
+};
+
+static struct intel_uncore_type knl_uncore_ubox = {
+       .name                   = "ubox",
+       .num_counters           = 2,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 48,
+       .fixed_ctr_bits         = 48,
+       .perf_ctr               = HSWEP_U_MSR_PMON_CTR0,
+       .event_ctl              = HSWEP_U_MSR_PMON_CTL0,
+       .event_mask             = KNL_U_MSR_PMON_RAW_EVENT_MASK,
+       .fixed_ctr              = HSWEP_U_MSR_PMON_UCLK_FIXED_CTR,
+       .fixed_ctl              = HSWEP_U_MSR_PMON_UCLK_FIXED_CTL,
+       .ops                    = &snbep_uncore_msr_ops,
+       .format_group           = &knl_uncore_ubox_format_group,
+};
+
+static struct attribute *knl_uncore_cha_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_qor.attr,
+       &format_attr_edge.attr,
+       &format_attr_tid_en.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       &format_attr_filter_tid4.attr,
+       &format_attr_filter_link3.attr,
+       &format_attr_filter_state4.attr,
+       &format_attr_filter_local.attr,
+       &format_attr_filter_all_op.attr,
+       &format_attr_filter_nnm.attr,
+       &format_attr_filter_opc3.attr,
+       &format_attr_filter_nc.attr,
+       &format_attr_filter_isoc.attr,
+       NULL,
+};
+
+static struct attribute_group knl_uncore_cha_format_group = {
+       .name = "format",
+       .attrs = knl_uncore_cha_formats_attr,
+};
+
+static struct event_constraint knl_uncore_cha_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x11, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x1f, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x36, 0x1),
+       EVENT_CONSTRAINT_END
+};
+
+static struct extra_reg knl_uncore_cha_extra_regs[] = {
+       SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
+                                 SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x3d, 0xff, 0x2),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x35, 0xff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x36, 0xff, 0x4),
+       EVENT_EXTRA_END
+};
+
+static u64 knl_cha_filter_mask(int fields)
+{
+       u64 mask = 0;
+
+       if (fields & 0x1)
+               mask |= KNL_CHA_MSR_PMON_BOX_FILTER_TID;
+       if (fields & 0x2)
+               mask |= KNL_CHA_MSR_PMON_BOX_FILTER_STATE;
+       if (fields & 0x4)
+               mask |= KNL_CHA_MSR_PMON_BOX_FILTER_OP;
+       return mask;
+}
+
+static struct event_constraint *
+knl_cha_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       return __snbep_cbox_get_constraint(box, event, knl_cha_filter_mask);
+}
+
+static int knl_cha_hw_config(struct intel_uncore_box *box,
+                            struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct extra_reg *er;
+       int idx = 0;
+
+       for (er = knl_uncore_cha_extra_regs; er->msr; er++) {
+               if (er->event != (event->hw.config & er->config_mask))
+                       continue;
+               idx |= er->idx;
+       }
+
+       if (idx) {
+               reg1->reg = HSWEP_C0_MSR_PMON_BOX_FILTER0 +
+                           KNL_CHA_MSR_OFFSET * box->pmu->pmu_idx;
+               reg1->config = event->attr.config1 & knl_cha_filter_mask(idx);
+               reg1->idx = idx;
+       }
+       return 0;
+}
+
+static void hswep_cbox_enable_event(struct intel_uncore_box *box,
+                                   struct perf_event *event);
+
+static struct intel_uncore_ops knl_uncore_cha_ops = {
+       .init_box               = snbep_uncore_msr_init_box,
+       .disable_box            = snbep_uncore_msr_disable_box,
+       .enable_box             = snbep_uncore_msr_enable_box,
+       .disable_event          = snbep_uncore_msr_disable_event,
+       .enable_event           = hswep_cbox_enable_event,
+       .read_counter           = uncore_msr_read_counter,
+       .hw_config              = knl_cha_hw_config,
+       .get_constraint         = knl_cha_get_constraint,
+       .put_constraint         = snbep_cbox_put_constraint,
+};
+
+static struct intel_uncore_type knl_uncore_cha = {
+       .name                   = "cha",
+       .num_counters           = 4,
+       .num_boxes              = 38,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = HSWEP_C0_MSR_PMON_CTL0,
+       .perf_ctr               = HSWEP_C0_MSR_PMON_CTR0,
+       .event_mask             = KNL_CHA_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = HSWEP_C0_MSR_PMON_BOX_CTL,
+       .msr_offset             = KNL_CHA_MSR_OFFSET,
+       .num_shared_regs        = 1,
+       .constraints            = knl_uncore_cha_constraints,
+       .ops                    = &knl_uncore_cha_ops,
+       .format_group           = &knl_uncore_cha_format_group,
+};
+
+static struct attribute *knl_uncore_pcu_formats_attr[] = {
+       &format_attr_event2.attr,
+       &format_attr_use_occ_ctr.attr,
+       &format_attr_occ_sel.attr,
+       &format_attr_edge.attr,
+       &format_attr_tid_en.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh6.attr,
+       &format_attr_occ_invert.attr,
+       &format_attr_occ_edge_det.attr,
+       NULL,
+};
+
+static struct attribute_group knl_uncore_pcu_format_group = {
+       .name = "format",
+       .attrs = knl_uncore_pcu_formats_attr,
+};
+
+static struct intel_uncore_type knl_uncore_pcu = {
+       .name                   = "pcu",
+       .num_counters           = 4,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 48,
+       .perf_ctr               = HSWEP_PCU_MSR_PMON_CTR0,
+       .event_ctl              = HSWEP_PCU_MSR_PMON_CTL0,
+       .event_mask             = KNL_PCU_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = HSWEP_PCU_MSR_PMON_BOX_CTL,
+       .ops                    = &snbep_uncore_msr_ops,
+       .format_group           = &knl_uncore_pcu_format_group,
+};
+
+static struct intel_uncore_type *knl_msr_uncores[] = {
+       &knl_uncore_ubox,
+       &knl_uncore_cha,
+       &knl_uncore_pcu,
+       NULL,
+};
+
+void knl_uncore_cpu_init(void)
+{
+       uncore_msr_uncores = knl_msr_uncores;
+}
+
+static void knl_uncore_imc_enable_box(struct intel_uncore_box *box)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       int box_ctl = uncore_pci_box_ctl(box);
+
+       pci_write_config_dword(pdev, box_ctl, 0);
+}
+
+static void knl_uncore_imc_enable_event(struct intel_uncore_box *box,
+                                       struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+
+       if ((event->attr.config & SNBEP_PMON_CTL_EV_SEL_MASK)
+                                                       == UNCORE_FIXED_EVENT)
+               pci_write_config_dword(pdev, hwc->config_base,
+                                      hwc->config | KNL_PMON_FIXED_CTL_EN);
+       else
+               pci_write_config_dword(pdev, hwc->config_base,
+                                      hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static struct intel_uncore_ops knl_uncore_imc_ops = {
+       .init_box       = snbep_uncore_pci_init_box,
+       .disable_box    = snbep_uncore_pci_disable_box,
+       .enable_box     = knl_uncore_imc_enable_box,
+       .read_counter   = snbep_uncore_pci_read_counter,
+       .enable_event   = knl_uncore_imc_enable_event,
+       .disable_event  = snbep_uncore_pci_disable_event,
+};
+
+static struct intel_uncore_type knl_uncore_imc_uclk = {
+       .name                   = "imc_uclk",
+       .num_counters           = 4,
+       .num_boxes              = 2,
+       .perf_ctr_bits          = 48,
+       .fixed_ctr_bits         = 48,
+       .perf_ctr               = KNL_UCLK_MSR_PMON_CTR0_LOW,
+       .event_ctl              = KNL_UCLK_MSR_PMON_CTL0,
+       .event_mask             = SNBEP_PMON_RAW_EVENT_MASK,
+       .fixed_ctr              = KNL_UCLK_MSR_PMON_UCLK_FIXED_LOW,
+       .fixed_ctl              = KNL_UCLK_MSR_PMON_UCLK_FIXED_CTL,
+       .box_ctl                = KNL_UCLK_MSR_PMON_BOX_CTL,
+       .ops                    = &knl_uncore_imc_ops,
+       .format_group           = &snbep_uncore_format_group,
+};
+
+static struct intel_uncore_type knl_uncore_imc_dclk = {
+       .name                   = "imc",
+       .num_counters           = 4,
+       .num_boxes              = 6,
+       .perf_ctr_bits          = 48,
+       .fixed_ctr_bits         = 48,
+       .perf_ctr               = KNL_MC0_CH0_MSR_PMON_CTR0_LOW,
+       .event_ctl              = KNL_MC0_CH0_MSR_PMON_CTL0,
+       .event_mask             = SNBEP_PMON_RAW_EVENT_MASK,
+       .fixed_ctr              = KNL_MC0_CH0_MSR_PMON_FIXED_LOW,
+       .fixed_ctl              = KNL_MC0_CH0_MSR_PMON_FIXED_CTL,
+       .box_ctl                = KNL_MC0_CH0_MSR_PMON_BOX_CTL,
+       .ops                    = &knl_uncore_imc_ops,
+       .format_group           = &snbep_uncore_format_group,
+};
+
+static struct intel_uncore_type knl_uncore_edc_uclk = {
+       .name                   = "edc_uclk",
+       .num_counters           = 4,
+       .num_boxes              = 8,
+       .perf_ctr_bits          = 48,
+       .fixed_ctr_bits         = 48,
+       .perf_ctr               = KNL_UCLK_MSR_PMON_CTR0_LOW,
+       .event_ctl              = KNL_UCLK_MSR_PMON_CTL0,
+       .event_mask             = SNBEP_PMON_RAW_EVENT_MASK,
+       .fixed_ctr              = KNL_UCLK_MSR_PMON_UCLK_FIXED_LOW,
+       .fixed_ctl              = KNL_UCLK_MSR_PMON_UCLK_FIXED_CTL,
+       .box_ctl                = KNL_UCLK_MSR_PMON_BOX_CTL,
+       .ops                    = &knl_uncore_imc_ops,
+       .format_group           = &snbep_uncore_format_group,
+};
+
+static struct intel_uncore_type knl_uncore_edc_eclk = {
+       .name                   = "edc_eclk",
+       .num_counters           = 4,
+       .num_boxes              = 8,
+       .perf_ctr_bits          = 48,
+       .fixed_ctr_bits         = 48,
+       .perf_ctr               = KNL_EDC0_ECLK_MSR_PMON_CTR0_LOW,
+       .event_ctl              = KNL_EDC0_ECLK_MSR_PMON_CTL0,
+       .event_mask             = SNBEP_PMON_RAW_EVENT_MASK,
+       .fixed_ctr              = KNL_EDC0_ECLK_MSR_PMON_ECLK_FIXED_LOW,
+       .fixed_ctl              = KNL_EDC0_ECLK_MSR_PMON_ECLK_FIXED_CTL,
+       .box_ctl                = KNL_EDC0_ECLK_MSR_PMON_BOX_CTL,
+       .ops                    = &knl_uncore_imc_ops,
+       .format_group           = &snbep_uncore_format_group,
+};
+
+static struct event_constraint knl_uncore_m2pcie_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+       EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type knl_uncore_m2pcie = {
+       .name           = "m2pcie",
+       .num_counters   = 4,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 48,
+       .constraints    = knl_uncore_m2pcie_constraints,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct attribute *knl_uncore_irp_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_qor.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       NULL,
+};
+
+static struct attribute_group knl_uncore_irp_format_group = {
+       .name = "format",
+       .attrs = knl_uncore_irp_formats_attr,
+};
+
+static struct intel_uncore_type knl_uncore_irp = {
+       .name                   = "irp",
+       .num_counters           = 2,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 48,
+       .perf_ctr               = SNBEP_PCI_PMON_CTR0,
+       .event_ctl              = SNBEP_PCI_PMON_CTL0,
+       .event_mask             = KNL_IRP_PCI_PMON_RAW_EVENT_MASK,
+       .box_ctl                = KNL_IRP_PCI_PMON_BOX_CTL,
+       .ops                    = &snbep_uncore_pci_ops,
+       .format_group           = &knl_uncore_irp_format_group,
+};
+
+enum {
+       KNL_PCI_UNCORE_MC_UCLK,
+       KNL_PCI_UNCORE_MC_DCLK,
+       KNL_PCI_UNCORE_EDC_UCLK,
+       KNL_PCI_UNCORE_EDC_ECLK,
+       KNL_PCI_UNCORE_M2PCIE,
+       KNL_PCI_UNCORE_IRP,
+};
+
+static struct intel_uncore_type *knl_pci_uncores[] = {
+       [KNL_PCI_UNCORE_MC_UCLK]        = &knl_uncore_imc_uclk,
+       [KNL_PCI_UNCORE_MC_DCLK]        = &knl_uncore_imc_dclk,
+       [KNL_PCI_UNCORE_EDC_UCLK]       = &knl_uncore_edc_uclk,
+       [KNL_PCI_UNCORE_EDC_ECLK]       = &knl_uncore_edc_eclk,
+       [KNL_PCI_UNCORE_M2PCIE]         = &knl_uncore_m2pcie,
+       [KNL_PCI_UNCORE_IRP]            = &knl_uncore_irp,
+       NULL,
+};
+
+/*
+ * KNL uses a common PCI device ID for multiple instances of an Uncore PMU
+ * device type. prior to KNL, each instance of a PMU device type had a unique
+ * device ID.
+ *
+ *     PCI Device ID   Uncore PMU Devices
+ *     ----------------------------------
+ *     0x7841          MC0 UClk, MC1 UClk
+ *     0x7843          MC0 DClk CH 0, MC0 DClk CH 1, MC0 DClk CH 2,
+ *                     MC1 DClk CH 0, MC1 DClk CH 1, MC1 DClk CH 2
+ *     0x7833          EDC0 UClk, EDC1 UClk, EDC2 UClk, EDC3 UClk,
+ *                     EDC4 UClk, EDC5 UClk, EDC6 UClk, EDC7 UClk
+ *     0x7835          EDC0 EClk, EDC1 EClk, EDC2 EClk, EDC3 EClk,
+ *                     EDC4 EClk, EDC5 EClk, EDC6 EClk, EDC7 EClk
+ *     0x7817          M2PCIe
+ *     0x7814          IRP
+*/
+
+static const struct pci_device_id knl_uncore_pci_ids[] = {
+       { /* MC UClk */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7841),
+               .driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_MC_UCLK, 0),
+       },
+       { /* MC DClk Channel */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7843),
+               .driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_MC_DCLK, 0),
+       },
+       { /* EDC UClk */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7833),
+               .driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_EDC_UCLK, 0),
+       },
+       { /* EDC EClk */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7835),
+               .driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_EDC_ECLK, 0),
+       },
+       { /* M2PCIe */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7817),
+               .driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_M2PCIE, 0),
+       },
+       { /* IRP */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7814),
+               .driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_IRP, 0),
+       },
+       { /* end: all zeroes */ }
+};
+
+static struct pci_driver knl_uncore_pci_driver = {
+       .name           = "knl_uncore",
+       .id_table       = knl_uncore_pci_ids,
+};
+
+int knl_uncore_pci_init(void)
+{
+       int ret;
+
+       /* All KNL PCI based PMON units are on the same PCI bus except IRP */
+       ret = snb_pci2phy_map_init(0x7814); /* IRP */
+       if (ret)
+               return ret;
+       ret = snb_pci2phy_map_init(0x7817); /* M2PCIe */
+       if (ret)
+               return ret;
+       uncore_pci_uncores = knl_pci_uncores;
+       uncore_pci_driver = &knl_uncore_pci_driver;
+       return 0;
+}
+
+/* end of KNL uncore support */
+
 /* Haswell-EP uncore support */
 static struct attribute *hswep_uncore_ubox_formats_attr[] = {
        &format_attr_event.attr,
@@ -2338,7 +2819,7 @@ int hswep_uncore_pci_init(void)
 }
 /* end of Haswell-EP uncore support */
 
-/* BDX-DE uncore support */
+/* BDX uncore support */
 
 static struct intel_uncore_type bdx_uncore_ubox = {
        .name                   = "ubox",
@@ -2360,13 +2841,14 @@ static struct event_constraint bdx_uncore_cbox_constraints[] = {
        UNCORE_EVENT_CONSTRAINT(0x09, 0x3),
        UNCORE_EVENT_CONSTRAINT(0x11, 0x1),
        UNCORE_EVENT_CONSTRAINT(0x36, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x3e, 0x1),
        EVENT_CONSTRAINT_END
 };
 
 static struct intel_uncore_type bdx_uncore_cbox = {
        .name                   = "cbox",
        .num_counters           = 4,
-       .num_boxes              = 8,
+       .num_boxes              = 24,
        .perf_ctr_bits          = 48,
        .event_ctl              = HSWEP_C0_MSR_PMON_CTL0,
        .perf_ctr               = HSWEP_C0_MSR_PMON_CTR0,
@@ -2379,9 +2861,24 @@ static struct intel_uncore_type bdx_uncore_cbox = {
        .format_group           = &hswep_uncore_cbox_format_group,
 };
 
+static struct intel_uncore_type bdx_uncore_sbox = {
+       .name                   = "sbox",
+       .num_counters           = 4,
+       .num_boxes              = 4,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = HSWEP_S0_MSR_PMON_CTL0,
+       .perf_ctr               = HSWEP_S0_MSR_PMON_CTR0,
+       .event_mask             = HSWEP_S_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = HSWEP_S0_MSR_PMON_BOX_CTL,
+       .msr_offset             = HSWEP_SBOX_MSR_OFFSET,
+       .ops                    = &hswep_uncore_sbox_msr_ops,
+       .format_group           = &hswep_uncore_sbox_format_group,
+};
+
 static struct intel_uncore_type *bdx_msr_uncores[] = {
        &bdx_uncore_ubox,
        &bdx_uncore_cbox,
+       &bdx_uncore_sbox,
        &hswep_uncore_pcu,
        NULL,
 };
@@ -2396,7 +2893,7 @@ void bdx_uncore_cpu_init(void)
 static struct intel_uncore_type bdx_uncore_ha = {
        .name           = "ha",
        .num_counters   = 4,
-       .num_boxes      = 1,
+       .num_boxes      = 2,
        .perf_ctr_bits  = 48,
        SNBEP_UNCORE_PCI_COMMON_INIT(),
 };
@@ -2404,7 +2901,7 @@ static struct intel_uncore_type bdx_uncore_ha = {
 static struct intel_uncore_type bdx_uncore_imc = {
        .name           = "imc",
        .num_counters   = 5,
-       .num_boxes      = 2,
+       .num_boxes      = 8,
        .perf_ctr_bits  = 48,
        .fixed_ctr_bits = 48,
        .fixed_ctr      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR,
@@ -2424,6 +2921,19 @@ static struct intel_uncore_type bdx_uncore_irp = {
        .format_group           = &snbep_uncore_format_group,
 };
 
+static struct intel_uncore_type bdx_uncore_qpi = {
+       .name                   = "qpi",
+       .num_counters           = 4,
+       .num_boxes              = 3,
+       .perf_ctr_bits          = 48,
+       .perf_ctr               = SNBEP_PCI_PMON_CTR0,
+       .event_ctl              = SNBEP_PCI_PMON_CTL0,
+       .event_mask             = SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_PCI_PMON_BOX_CTL,
+       .num_shared_regs        = 1,
+       .ops                    = &snbep_uncore_qpi_ops,
+       .format_group           = &snbep_uncore_qpi_format_group,
+};
 
 static struct event_constraint bdx_uncore_r2pcie_constraints[] = {
        UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
@@ -2432,6 +2942,8 @@ static struct event_constraint bdx_uncore_r2pcie_constraints[] = {
        UNCORE_EVENT_CONSTRAINT(0x23, 0x1),
        UNCORE_EVENT_CONSTRAINT(0x25, 0x1),
        UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x28, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2c, 0x3),
        UNCORE_EVENT_CONSTRAINT(0x2d, 0x3),
        EVENT_CONSTRAINT_END
 };
@@ -2445,18 +2957,65 @@ static struct intel_uncore_type bdx_uncore_r2pcie = {
        SNBEP_UNCORE_PCI_COMMON_INIT(),
 };
 
+static struct event_constraint bdx_uncore_r3qpi_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x01, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x07, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x08, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x09, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x0a, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x0e, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x13, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x14, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x15, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x1f, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x20, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x21, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x22, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x25, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x28, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x29, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2c, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2d, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2e, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2f, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x36, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x37, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x39, 0x3),
+       EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type bdx_uncore_r3qpi = {
+       .name           = "r3qpi",
+       .num_counters   = 3,
+       .num_boxes      = 3,
+       .perf_ctr_bits  = 48,
+       .constraints    = bdx_uncore_r3qpi_constraints,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
 enum {
        BDX_PCI_UNCORE_HA,
        BDX_PCI_UNCORE_IMC,
        BDX_PCI_UNCORE_IRP,
+       BDX_PCI_UNCORE_QPI,
        BDX_PCI_UNCORE_R2PCIE,
+       BDX_PCI_UNCORE_R3QPI,
 };
 
 static struct intel_uncore_type *bdx_pci_uncores[] = {
        [BDX_PCI_UNCORE_HA]     = &bdx_uncore_ha,
        [BDX_PCI_UNCORE_IMC]    = &bdx_uncore_imc,
        [BDX_PCI_UNCORE_IRP]    = &bdx_uncore_irp,
+       [BDX_PCI_UNCORE_QPI]    = &bdx_uncore_qpi,
        [BDX_PCI_UNCORE_R2PCIE] = &bdx_uncore_r2pcie,
+       [BDX_PCI_UNCORE_R3QPI]  = &bdx_uncore_r3qpi,
        NULL,
 };
 
@@ -2465,6 +3024,10 @@ static const struct pci_device_id bdx_uncore_pci_ids[] = {
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f30),
                .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_HA, 0),
        },
+       { /* Home Agent 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f38),
+               .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_HA, 1),
+       },
        { /* MC0 Channel 0 */
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fb0),
                .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 0),
@@ -2473,14 +3036,74 @@ static const struct pci_device_id bdx_uncore_pci_ids[] = {
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fb1),
                .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 1),
        },
+       { /* MC0 Channel 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fb4),
+               .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 2),
+       },
+       { /* MC0 Channel 3 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fb5),
+               .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 3),
+       },
+       { /* MC1 Channel 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fd0),
+               .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 4),
+       },
+       { /* MC1 Channel 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fd1),
+               .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 5),
+       },
+       { /* MC1 Channel 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fd4),
+               .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 6),
+       },
+       { /* MC1 Channel 3 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fd5),
+               .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 7),
+       },
        { /* IRP */
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f39),
                .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IRP, 0),
        },
+       { /* QPI0 Port 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f32),
+               .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_QPI, 0),
+       },
+       { /* QPI0 Port 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f33),
+               .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_QPI, 1),
+       },
+       { /* QPI1 Port 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f3a),
+               .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_QPI, 2),
+       },
        { /* R2PCIe */
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f34),
                .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_R2PCIE, 0),
        },
+       { /* R3QPI0 Link 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f36),
+               .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_R3QPI, 0),
+       },
+       { /* R3QPI0 Link 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f37),
+               .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_R3QPI, 1),
+       },
+       { /* R3QPI1 Link 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f3e),
+               .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_R3QPI, 2),
+       },
+       { /* QPI Port 0 filter  */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f86),
+               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV, 0),
+       },
+       { /* QPI Port 1 filter  */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f96),
+               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV, 1),
+       },
+       { /* QPI Port 2 filter  */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f46),
+               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV, 2),
+       },
        { /* end: all zeroes */ }
 };
 
@@ -2500,4 +3123,4 @@ int bdx_uncore_pci_init(void)
        return 0;
 }
 
-/* end of BDX-DE uncore support */
+/* end of BDX uncore support */
index 136ac74dee823005cea04ea9600a0c62cdf5685c..819d94982e078b8597f084f8409fcd3106361293 100644 (file)
@@ -33,28 +33,27 @@ static int __init x86_rdrand_setup(char *s)
 __setup("nordrand", x86_rdrand_setup);
 
 /*
- * Force a reseed cycle; we are architecturally guaranteed a reseed
- * after no more than 512 128-bit chunks of random data.  This also
- * acts as a test of the CPU capability.
+ * RDRAND has Built-In-Self-Test (BIST) that runs on every invocation.
+ * Run the instruction a few times as a sanity check.
+ * If it fails, it is simple to disable RDRAND here.
  */
-#define RESEED_LOOP ((512*128)/sizeof(unsigned long))
+#define SANITY_CHECK_LOOPS 8
 
 void x86_init_rdrand(struct cpuinfo_x86 *c)
 {
 #ifdef CONFIG_ARCH_RANDOM
        unsigned long tmp;
-       int i, count, ok;
+       int i;
 
        if (!cpu_has(c, X86_FEATURE_RDRAND))
-               return;         /* Nothing to do */
+               return;
 
-       for (count = i = 0; i < RESEED_LOOP; i++) {
-               ok = rdrand_long(&tmp);
-               if (ok)
-                       count++;
+       for (i = 0; i < SANITY_CHECK_LOOPS; i++) {
+               if (!rdrand_long(&tmp)) {
+                       clear_cpu_cap(c, X86_FEATURE_RDRAND);
+                       printk_once(KERN_WARNING "rdrand: disabled\n");
+                       return;
+               }
        }
-
-       if (count != RESEED_LOOP)
-               clear_cpu_cap(c, X86_FEATURE_RDRAND);
 #endif
 }
index 608fb26c72544c5ee0fd7793c0703f642c7ed60f..8cb57df9398d91a74eec678134844d8ac1052463 100644 (file)
@@ -31,32 +31,12 @@ void init_scattered_cpuid_features(struct cpuinfo_x86 *c)
        const struct cpuid_bit *cb;
 
        static const struct cpuid_bit cpuid_bits[] = {
-               { X86_FEATURE_DTHERM,           CR_EAX, 0, 0x00000006, 0 },
-               { X86_FEATURE_IDA,              CR_EAX, 1, 0x00000006, 0 },
-               { X86_FEATURE_ARAT,             CR_EAX, 2, 0x00000006, 0 },
-               { X86_FEATURE_PLN,              CR_EAX, 4, 0x00000006, 0 },
-               { X86_FEATURE_PTS,              CR_EAX, 6, 0x00000006, 0 },
-               { X86_FEATURE_HWP,              CR_EAX, 7, 0x00000006, 0 },
-               { X86_FEATURE_HWP_NOTIFY,       CR_EAX, 8, 0x00000006, 0 },
-               { X86_FEATURE_HWP_ACT_WINDOW,   CR_EAX, 9, 0x00000006, 0 },
-               { X86_FEATURE_HWP_EPP,          CR_EAX,10, 0x00000006, 0 },
-               { X86_FEATURE_HWP_PKG_REQ,      CR_EAX,11, 0x00000006, 0 },
                { X86_FEATURE_INTEL_PT,         CR_EBX,25, 0x00000007, 0 },
                { X86_FEATURE_APERFMPERF,       CR_ECX, 0, 0x00000006, 0 },
                { X86_FEATURE_EPB,              CR_ECX, 3, 0x00000006, 0 },
                { X86_FEATURE_HW_PSTATE,        CR_EDX, 7, 0x80000007, 0 },
                { X86_FEATURE_CPB,              CR_EDX, 9, 0x80000007, 0 },
                { X86_FEATURE_PROC_FEEDBACK,    CR_EDX,11, 0x80000007, 0 },
-               { X86_FEATURE_NPT,              CR_EDX, 0, 0x8000000a, 0 },
-               { X86_FEATURE_LBRV,             CR_EDX, 1, 0x8000000a, 0 },
-               { X86_FEATURE_SVML,             CR_EDX, 2, 0x8000000a, 0 },
-               { X86_FEATURE_NRIPS,            CR_EDX, 3, 0x8000000a, 0 },
-               { X86_FEATURE_TSCRATEMSR,       CR_EDX, 4, 0x8000000a, 0 },
-               { X86_FEATURE_VMCBCLEAN,        CR_EDX, 5, 0x8000000a, 0 },
-               { X86_FEATURE_FLUSHBYASID,      CR_EDX, 6, 0x8000000a, 0 },
-               { X86_FEATURE_DECODEASSISTS,    CR_EDX, 7, 0x8000000a, 0 },
-               { X86_FEATURE_PAUSEFILTER,      CR_EDX,10, 0x8000000a, 0 },
-               { X86_FEATURE_PFTHRESHOLD,      CR_EDX,12, 0x8000000a, 0 },
                { 0, 0, 0, 0, 0 }
        };
 
index 3fa0e5ad86b4456168acc1efc210130303308256..252da7aceca67ff580e8189ed267b2ce44d83373 100644 (file)
@@ -12,7 +12,7 @@ static void early_init_transmeta(struct cpuinfo_x86 *c)
        xlvl = cpuid_eax(0x80860000);
        if ((xlvl & 0xffff0000) == 0x80860000) {
                if (xlvl >= 0x80860001)
-                       c->x86_capability[2] = cpuid_edx(0x80860001);
+                       c->x86_capability[CPUID_8086_0001_EDX] = cpuid_edx(0x80860001);
        }
 }
 
@@ -82,7 +82,7 @@ static void init_transmeta(struct cpuinfo_x86 *c)
        /* Unhide possibly hidden capability flags */
        rdmsr(0x80860004, cap_mask, uk);
        wrmsr(0x80860004, ~0, uk);
-       c->x86_capability[0] = cpuid_edx(0x00000001);
+       c->x86_capability[CPUID_1_EDX] = cpuid_edx(0x00000001);
        wrmsr(0x80860004, cap_mask, uk);
 
        /* All Transmeta CPUs have a constant TSC */
index 2c1910f6717ed5278fc6d85d25c92360664feb68..58f34319b29ab64aee4bd21e6ff30367d478c262 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/cpu.h>
 #include <asm/reboot.h>
 #include <asm/virtext.h>
+#include <asm/intel_pt.h>
 
 /* Alignment required for elf header segment */
 #define ELF_CORE_HEADER_ALIGN   4096
@@ -125,6 +126,11 @@ static void kdump_nmi_callback(int cpu, struct pt_regs *regs)
        cpu_emergency_vmxoff();
        cpu_emergency_svm_disable();
 
+       /*
+        * Disable Intel PT to stop its logging
+        */
+       cpu_emergency_stop_pt();
+
        disable_local_APIC();
 }
 
@@ -169,6 +175,11 @@ void native_machine_crash_shutdown(struct pt_regs *regs)
        cpu_emergency_vmxoff();
        cpu_emergency_svm_disable();
 
+       /*
+        * Disable Intel PT to stop its logging
+        */
+       cpu_emergency_stop_pt();
+
 #ifdef CONFIG_X86_IO_APIC
        /* Prevent crash_kexec() from deadlocking on ioapic_lock. */
        ioapic_zap_locks();
index be39b5fde4b9619a566eb5deee4ee9456a3f5cc5..7b2978ab30df478669bbf10b2304e2fac04d1235 100644 (file)
@@ -12,7 +12,7 @@
  */
 static void fpu__init_cpu_ctx_switch(void)
 {
-       if (!cpu_has_eager_fpu)
+       if (!boot_cpu_has(X86_FEATURE_EAGER_FPU))
                stts();
        else
                clts();
@@ -143,9 +143,18 @@ static void __init fpu__init_system_generic(void)
 unsigned int xstate_size;
 EXPORT_SYMBOL_GPL(xstate_size);
 
-/* Enforce that 'MEMBER' is the last field of 'TYPE': */
+/* Get alignment of the TYPE. */
+#define TYPE_ALIGN(TYPE) offsetof(struct { char x; TYPE test; }, test)
+
+/*
+ * Enforce that 'MEMBER' is the last field of 'TYPE'.
+ *
+ * Align the computed size with alignment of the TYPE,
+ * because that's how C aligns structs.
+ */
 #define CHECK_MEMBER_AT_END_OF(TYPE, MEMBER) \
-       BUILD_BUG_ON(sizeof(TYPE) != offsetofend(TYPE, MEMBER))
+       BUILD_BUG_ON(sizeof(TYPE) != ALIGN(offsetofend(TYPE, MEMBER), \
+                                          TYPE_ALIGN(TYPE)))
 
 /*
  * We append the 'struct fpu' to the task_struct:
@@ -188,7 +197,7 @@ static void __init fpu__init_task_struct_size(void)
  */
 static void __init fpu__init_system_xstate_size_legacy(void)
 {
-       static int on_boot_cpu = 1;
+       static int on_boot_cpu __initdata = 1;
 
        WARN_ON_FPU(!on_boot_cpu);
        on_boot_cpu = 0;
@@ -278,7 +287,7 @@ __setup("eagerfpu=", eager_fpu_setup);
  */
 static void __init fpu__init_system_ctx_switch(void)
 {
-       static bool on_boot_cpu = 1;
+       static bool on_boot_cpu __initdata = 1;
 
        WARN_ON_FPU(!on_boot_cpu);
        on_boot_cpu = 0;
@@ -287,7 +296,7 @@ static void __init fpu__init_system_ctx_switch(void)
        current_thread_info()->status = 0;
 
        /* Auto enable eagerfpu for xsaveopt */
-       if (cpu_has_xsaveopt && eagerfpu != DISABLE)
+       if (boot_cpu_has(X86_FEATURE_XSAVEOPT) && eagerfpu != DISABLE)
                eagerfpu = ENABLE;
 
        if (xfeatures_mask & XFEATURE_MASK_EAGER) {
index 70fc312221fc6b6c3223673c0328dfdc73c59ea6..40f100285984eb9f73876115f263c53c85f86a59 100644 (file)
@@ -297,7 +297,7 @@ static void __init setup_xstate_comp(void)
  */
 static void __init setup_init_fpu_buf(void)
 {
-       static int on_boot_cpu = 1;
+       static int on_boot_cpu __initdata = 1;
 
        WARN_ON_FPU(!on_boot_cpu);
        on_boot_cpu = 0;
@@ -608,7 +608,7 @@ static void fpu__init_disable_system_xstate(void)
 void __init fpu__init_system_xstate(void)
 {
        unsigned int eax, ebx, ecx, edx;
-       static int on_boot_cpu = 1;
+       static int on_boot_cpu __initdata = 1;
        int err;
 
        WARN_ON_FPU(!on_boot_cpu);
index 50a3fad5b89f1ff42b05b4f7eeb60ea735d7daaa..2bcfb5f2bc449c3717308c9a75676af3b07e796f 100644 (file)
@@ -300,6 +300,10 @@ static int arch_build_bp_info(struct perf_event *bp)
                        return -EINVAL;
                if (bp->attr.bp_addr & (bp->attr.bp_len - 1))
                        return -EINVAL;
+
+               if (!boot_cpu_has(X86_FEATURE_BPEXT))
+                       return -EOPNOTSUPP;
+
                /*
                 * It's impossible to use a range breakpoint to fake out
                 * user vs kernel detection because bp_len - 1 can't
@@ -307,8 +311,6 @@ static int arch_build_bp_info(struct perf_event *bp)
                 * breakpoints, then we'll have to check for kprobe-blacklisted
                 * addresses anywhere in the range.
                 */
-               if (!cpu_has_bpext)
-                       return -EOPNOTSUPP;
                info->mask = bp->attr.bp_len - 1;
                info->len = X86_BREAKPOINT_LEN_1;
        }
index 2bd81e30242785a4eb02ea417dc1fe157656784a..72cef58693c7388cc69ceb9e0f8cd4149d3ade95 100644 (file)
@@ -45,6 +45,11 @@ early_param("no-kvmclock", parse_no_kvmclock);
 static struct pvclock_vsyscall_time_info *hv_clock;
 static struct pvclock_wall_clock wall_clock;
 
+struct pvclock_vsyscall_time_info *pvclock_pvti_cpu0_va(void)
+{
+       return hv_clock;
+}
+
 /*
  * The wallclock is the time of day when we booted. Since then, some time may
  * have elapsed since the hypervisor wrote the data. So we try to account for
@@ -305,7 +310,6 @@ int __init kvm_setup_vsyscall_timeinfo(void)
 {
 #ifdef CONFIG_X86_64
        int cpu;
-       int ret;
        u8 flags;
        struct pvclock_vcpu_time_info *vcpu_time;
        unsigned int size;
@@ -325,11 +329,6 @@ int __init kvm_setup_vsyscall_timeinfo(void)
                return 1;
        }
 
-       if ((ret = pvclock_init_vsyscall(hv_clock, size))) {
-               put_cpu();
-               return ret;
-       }
-
        put_cpu();
 
        kvm_clock.archdata.vclock_mode = VCLOCK_PVCLOCK;
index 697f90db0e37db9bbde8f076c998ccaed8e9c499..8a2cdd736fa4da82374fa9392e76b5716cc0f89a 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/mach_traps.h>
 #include <asm/nmi.h>
 #include <asm/x86_init.h>
+#include <asm/reboot.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/nmi.h>
@@ -231,7 +232,7 @@ pci_serr_error(unsigned char reason, struct pt_regs *regs)
 #endif
 
        if (panic_on_unrecovered_nmi)
-               panic("NMI: Not continuing");
+               nmi_panic(regs, "NMI: Not continuing");
 
        pr_emerg("Dazed and confused, but trying to continue\n");
 
@@ -255,8 +256,16 @@ io_check_error(unsigned char reason, struct pt_regs *regs)
                 reason, smp_processor_id());
        show_regs(regs);
 
-       if (panic_on_io_nmi)
-               panic("NMI IOCK error: Not continuing");
+       if (panic_on_io_nmi) {
+               nmi_panic(regs, "NMI IOCK error: Not continuing");
+
+               /*
+                * If we end up here, it means we have received an NMI while
+                * processing panic(). Simply return without delaying and
+                * re-enabling NMIs.
+                */
+               return;
+       }
 
        /* Re-enable the IOCK line, wait for a few seconds */
        reason = (reason & NMI_REASON_CLEAR_MASK) | NMI_REASON_CLEAR_IOCHK;
@@ -297,7 +306,7 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
 
        pr_emerg("Do you have a strange power saving mode enabled?\n");
        if (unknown_nmi_panic || panic_on_unrecovered_nmi)
-               panic("NMI: Not continuing");
+               nmi_panic(regs, "NMI: Not continuing");
 
        pr_emerg("Dazed and confused, but trying to continue\n");
 }
@@ -348,8 +357,19 @@ static void default_do_nmi(struct pt_regs *regs)
                return;
        }
 
-       /* Non-CPU-specific NMI: NMI sources can be processed on any CPU */
-       raw_spin_lock(&nmi_reason_lock);
+       /*
+        * Non-CPU-specific NMI: NMI sources can be processed on any CPU.
+        *
+        * Another CPU may be processing panic routines while holding
+        * nmi_reason_lock. Check if the CPU issued the IPI for crash dumping,
+        * and if so, call its callback directly.  If there is no CPU preparing
+        * crash dump, we simply loop here.
+        */
+       while (!raw_spin_trylock(&nmi_reason_lock)) {
+               run_crash_ipi_callback(regs);
+               cpu_relax();
+       }
+
        reason = x86_platform.get_nmi_reason();
 
        if (reason & NMI_REASON_MASK) {
index c2130aef3f9d25d6c6a47f3499b8096c5cfb8e80..f08ac28b8136da85e0866bf689b3b16faec1c157 100644 (file)
@@ -74,16 +74,6 @@ void __init default_banner(void)
 /* Undefined instruction for dealing with missing ops pointers. */
 static const unsigned char ud2a[] = { 0x0f, 0x0b };
 
-unsigned paravirt_patch_nop(void)
-{
-       return 0;
-}
-
-unsigned paravirt_patch_ignore(unsigned len)
-{
-       return len;
-}
-
 struct branch {
        unsigned char opcode;
        u32 delta;
@@ -133,7 +123,6 @@ static void *get_call_destination(u8 type)
                .pv_time_ops = pv_time_ops,
                .pv_cpu_ops = pv_cpu_ops,
                .pv_irq_ops = pv_irq_ops,
-               .pv_apic_ops = pv_apic_ops,
                .pv_mmu_ops = pv_mmu_ops,
 #ifdef CONFIG_PARAVIRT_SPINLOCKS
                .pv_lock_ops = pv_lock_ops,
@@ -152,8 +141,7 @@ unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf,
                /* If there's no function, patch it with a ud2a (BUG) */
                ret = paravirt_patch_insns(insnbuf, len, ud2a, ud2a+sizeof(ud2a));
        else if (opfunc == _paravirt_nop)
-               /* If the operation is a nop, then nop the callsite */
-               ret = paravirt_patch_nop();
+               ret = 0;
 
        /* identity functions just return their single argument */
        else if (opfunc == _paravirt_ident_32)
@@ -162,10 +150,6 @@ unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf,
                ret = paravirt_patch_ident_64(insnbuf, len);
 
        else if (type == PARAVIRT_PATCH(pv_cpu_ops.iret) ||
-#ifdef CONFIG_X86_32
-                type == PARAVIRT_PATCH(pv_cpu_ops.irq_enable_sysexit) ||
-#endif
-                type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret32) ||
                 type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret64))
                /* If operation requires a jmp, then jmp */
                ret = paravirt_patch_jmp(insnbuf, opfunc, addr, len);
@@ -220,8 +204,6 @@ static u64 native_steal_clock(int cpu)
 
 /* These are in entry.S */
 extern void native_iret(void);
-extern void native_irq_enable_sysexit(void);
-extern void native_usergs_sysret32(void);
 extern void native_usergs_sysret64(void);
 
 static struct resource reserve_ioports = {
@@ -379,13 +361,7 @@ __visible struct pv_cpu_ops pv_cpu_ops = {
 
        .load_sp0 = native_load_sp0,
 
-#if defined(CONFIG_X86_32)
-       .irq_enable_sysexit = native_irq_enable_sysexit,
-#endif
 #ifdef CONFIG_X86_64
-#ifdef CONFIG_IA32_EMULATION
-       .usergs_sysret32 = native_usergs_sysret32,
-#endif
        .usergs_sysret64 = native_usergs_sysret64,
 #endif
        .iret = native_iret,
@@ -403,12 +379,6 @@ NOKPROBE_SYMBOL(native_get_debugreg);
 NOKPROBE_SYMBOL(native_set_debugreg);
 NOKPROBE_SYMBOL(native_load_idt);
 
-struct pv_apic_ops pv_apic_ops = {
-#ifdef CONFIG_X86_LOCAL_APIC
-       .startup_ipi_hook = paravirt_nop,
-#endif
-};
-
 #if defined(CONFIG_X86_32) && !defined(CONFIG_X86_PAE)
 /* 32-bit pagetable entries */
 #define PTE_IDENT      __PV_IS_CALLEE_SAVE(_paravirt_ident_32)
@@ -444,9 +414,6 @@ struct pv_mmu_ops pv_mmu_ops = {
        .set_pmd = native_set_pmd,
        .set_pmd_at = native_set_pmd_at,
        .pte_update = paravirt_nop,
-       .pte_update_defer = paravirt_nop,
-       .pmd_update = paravirt_nop,
-       .pmd_update_defer = paravirt_nop,
 
        .ptep_modify_prot_start = __ptep_modify_prot_start,
        .ptep_modify_prot_commit = __ptep_modify_prot_commit,
@@ -492,6 +459,5 @@ struct pv_mmu_ops pv_mmu_ops = {
 EXPORT_SYMBOL_GPL(pv_time_ops);
 EXPORT_SYMBOL    (pv_cpu_ops);
 EXPORT_SYMBOL    (pv_mmu_ops);
-EXPORT_SYMBOL_GPL(pv_apic_ops);
 EXPORT_SYMBOL_GPL(pv_info);
 EXPORT_SYMBOL    (pv_irq_ops);
index c89f50a76e972d8f58cd4b686333163dcadfd8b3..158dc0650d5dfac1b8755910b30612d6cbb9fdbb 100644 (file)
@@ -5,7 +5,6 @@ DEF_NATIVE(pv_irq_ops, irq_enable, "sti");
 DEF_NATIVE(pv_irq_ops, restore_fl, "push %eax; popf");
 DEF_NATIVE(pv_irq_ops, save_fl, "pushf; pop %eax");
 DEF_NATIVE(pv_cpu_ops, iret, "iret");
-DEF_NATIVE(pv_cpu_ops, irq_enable_sysexit, "sti; sysexit");
 DEF_NATIVE(pv_mmu_ops, read_cr2, "mov %cr2, %eax");
 DEF_NATIVE(pv_mmu_ops, write_cr3, "mov %eax, %cr3");
 DEF_NATIVE(pv_mmu_ops, read_cr3, "mov %cr3, %eax");
@@ -46,7 +45,6 @@ unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
                PATCH_SITE(pv_irq_ops, restore_fl);
                PATCH_SITE(pv_irq_ops, save_fl);
                PATCH_SITE(pv_cpu_ops, iret);
-               PATCH_SITE(pv_cpu_ops, irq_enable_sysexit);
                PATCH_SITE(pv_mmu_ops, read_cr2);
                PATCH_SITE(pv_mmu_ops, read_cr3);
                PATCH_SITE(pv_mmu_ops, write_cr3);
index 8aa05583bc42dec102b3fffb63d2fa6a828eee4c..e70087a04cc8c7192f69d66d7cf035c2528d14a8 100644 (file)
@@ -13,9 +13,7 @@ DEF_NATIVE(pv_mmu_ops, flush_tlb_single, "invlpg (%rdi)");
 DEF_NATIVE(pv_cpu_ops, clts, "clts");
 DEF_NATIVE(pv_cpu_ops, wbinvd, "wbinvd");
 
-DEF_NATIVE(pv_cpu_ops, irq_enable_sysexit, "swapgs; sti; sysexit");
 DEF_NATIVE(pv_cpu_ops, usergs_sysret64, "swapgs; sysretq");
-DEF_NATIVE(pv_cpu_ops, usergs_sysret32, "swapgs; sysretl");
 DEF_NATIVE(pv_cpu_ops, swapgs, "swapgs");
 
 DEF_NATIVE(, mov32, "mov %edi, %eax");
@@ -55,7 +53,6 @@ unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
                PATCH_SITE(pv_irq_ops, save_fl);
                PATCH_SITE(pv_irq_ops, irq_enable);
                PATCH_SITE(pv_irq_ops, irq_disable);
-               PATCH_SITE(pv_cpu_ops, usergs_sysret32);
                PATCH_SITE(pv_cpu_ops, usergs_sysret64);
                PATCH_SITE(pv_cpu_ops, swapgs);
                PATCH_SITE(pv_mmu_ops, read_cr2);
index 0497f719977dff8ca0094b536a6b7e40ac371ef2..833b1d329c475130977b5a6d3c477d1637bd97d6 100644 (file)
@@ -180,13 +180,13 @@ static void calioc2_dump_error_regs(struct iommu_table *tbl);
 static void calgary_init_bitmap_from_tce_table(struct iommu_table *tbl);
 static void get_tce_space_from_tar(void);
 
-static struct cal_chipset_ops calgary_chip_ops = {
+static const struct cal_chipset_ops calgary_chip_ops = {
        .handle_quirks = calgary_handle_quirks,
        .tce_cache_blast = calgary_tce_cache_blast,
        .dump_error_regs = calgary_dump_error_regs
 };
 
-static struct cal_chipset_ops calioc2_chip_ops = {
+static const struct cal_chipset_ops calioc2_chip_ops = {
        .handle_quirks = calioc2_handle_quirks,
        .tce_cache_blast = calioc2_tce_cache_blast,
        .dump_error_regs = calioc2_dump_error_regs
index adf0392d549aa465e8f3e0ac336ea6f0e5967f1c..7c577a178859e9c33623969baffcc02f9c2a3851 100644 (file)
@@ -88,7 +88,7 @@ int __init pci_swiotlb_detect_4gb(void)
 {
        /* don't initialize swiotlb if iommu=off (no_iommu=1) */
 #ifdef CONFIG_X86_64
-       if (!no_iommu && max_pfn > MAX_DMA32_PFN)
+       if (!no_iommu && max_possible_pfn > MAX_DMA32_PFN)
                swiotlb = 1;
 #endif
        return swiotlb;
index e835d263a33b43ccf7601698cfeadc447ede491e..b9d99e0f82c4f072a15f7cb3fb3434d391281daf 100644 (file)
@@ -125,7 +125,7 @@ void release_thread(struct task_struct *dead_task)
                if (dead_task->mm->context.ldt) {
                        pr_warn("WARNING: dead process %s still has LDT? <%p/%d>\n",
                                dead_task->comm,
-                               dead_task->mm->context.ldt,
+                               dead_task->mm->context.ldt->entries,
                                dead_task->mm->context.ldt->size);
                        BUG();
                }
index 558f50edebca8f55a8c33e67bfcd21f9c78037a9..32e9d9cbb884ae10f0f5035c47bafb69f4517f80 100644 (file)
@@ -124,21 +124,6 @@ const char *regs_query_register_name(unsigned int offset)
        return NULL;
 }
 
-static const int arg_offs_table[] = {
-#ifdef CONFIG_X86_32
-       [0] = offsetof(struct pt_regs, ax),
-       [1] = offsetof(struct pt_regs, dx),
-       [2] = offsetof(struct pt_regs, cx)
-#else /* CONFIG_X86_64 */
-       [0] = offsetof(struct pt_regs, di),
-       [1] = offsetof(struct pt_regs, si),
-       [2] = offsetof(struct pt_regs, dx),
-       [3] = offsetof(struct pt_regs, cx),
-       [4] = offsetof(struct pt_regs, r8),
-       [5] = offsetof(struct pt_regs, r9)
-#endif
-};
-
 /*
  * does not yet catch signals sent when the child dies.
  * in exit.c or in signal.c.
index 2f355d229a587771680b28080d92fd06f345d7e7..99bfc025111d3dd62bc7c1753d126e97fb4e48ac 100644 (file)
@@ -140,27 +140,3 @@ void pvclock_read_wallclock(struct pvclock_wall_clock *wall_clock,
 
        set_normalized_timespec(ts, now.tv_sec, now.tv_nsec);
 }
-
-#ifdef CONFIG_X86_64
-/*
- * Initialize the generic pvclock vsyscall state.  This will allocate
- * a/some page(s) for the per-vcpu pvclock information, set up a
- * fixmap mapping for the page(s)
- */
-
-int __init pvclock_init_vsyscall(struct pvclock_vsyscall_time_info *i,
-                                int size)
-{
-       int idx;
-
-       WARN_ON (size != PVCLOCK_VSYSCALL_NR_PAGES*PAGE_SIZE);
-
-       for (idx = 0; idx <= (PVCLOCK_FIXMAP_END-PVCLOCK_FIXMAP_BEGIN); idx++) {
-               __set_fixmap(PVCLOCK_FIXMAP_BEGIN + idx,
-                            __pa(i) + (idx*PAGE_SIZE),
-                            PAGE_KERNEL_VVAR);
-       }
-
-       return 0;
-}
-#endif
index 02693dd9a0790b804a515294714d59ed68688ba8..d64889aa2d46d50fec76d7c653ac31094c8b0a30 100644 (file)
@@ -718,6 +718,7 @@ static int crashing_cpu;
 static nmi_shootdown_cb shootdown_callback;
 
 static atomic_t waiting_for_crash_ipi;
+static int crash_ipi_issued;
 
 static int crash_nmi_callback(unsigned int val, struct pt_regs *regs)
 {
@@ -780,6 +781,9 @@ void nmi_shootdown_cpus(nmi_shootdown_cb callback)
 
        smp_send_nmi_allbutself();
 
+       /* Kick CPUs looping in NMI context. */
+       WRITE_ONCE(crash_ipi_issued, 1);
+
        msecs = 1000; /* Wait at most a second for the other cpus to stop */
        while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
                mdelay(1);
@@ -788,9 +792,35 @@ void nmi_shootdown_cpus(nmi_shootdown_cb callback)
 
        /* Leave the nmi callback set */
 }
+
+/*
+ * Check if the crash dumping IPI got issued and if so, call its callback
+ * directly. This function is used when we have already been in NMI handler.
+ * It doesn't return.
+ */
+void run_crash_ipi_callback(struct pt_regs *regs)
+{
+       if (crash_ipi_issued)
+               crash_nmi_callback(0, regs);
+}
+
+/* Override the weak function in kernel/panic.c */
+void nmi_panic_self_stop(struct pt_regs *regs)
+{
+       while (1) {
+               /* If no CPU is preparing crash dump, we simply loop here. */
+               run_crash_ipi_callback(regs);
+               cpu_relax();
+       }
+}
+
 #else /* !CONFIG_SMP */
 void nmi_shootdown_cpus(nmi_shootdown_cb callback)
 {
        /* No other CPUs to shoot down */
 }
+
+void run_crash_ipi_callback(struct pt_regs *regs)
+{
+}
 #endif
index cd9685235df91b69f5e39885e55850964c67e8fc..4af8d063fb362cd2bf92b97a48fa8c1d5d95fd3b 100644 (file)
@@ -200,6 +200,9 @@ static __init int add_rtc_cmos(void)
        }
 #endif
 
+       if (paravirt_enabled() && !paravirt_has(RTC))
+               return -ENODEV;
+
        platform_device_register(&rtc_device);
        dev_info(&rtc_device.dev,
                 "registered platform RTC device (no PNP device found)\n");
index d2bbe343fda74a87307675b3a65704e2cc96769b..d3d80e6d42a20ea665325b4cf2a5e7be3c43289a 100644 (file)
@@ -1048,6 +1048,8 @@ void __init setup_arch(char **cmdline_p)
        if (mtrr_trim_uncached_memory(max_pfn))
                max_pfn = e820_end_of_ram_pfn();
 
+       max_possible_pfn = max_pfn;
+
 #ifdef CONFIG_X86_32
        /* max_low_pfn get updated here */
        find_low_pfn_range();
index 12c8286206ce27c1627b7202836d7d5419a2b4b6..658777cf38512872b4e5d049a8618e4bbd1b869b 100644 (file)
@@ -125,12 +125,12 @@ static void native_smp_send_reschedule(int cpu)
                WARN_ON(1);
                return;
        }
-       apic->send_IPI_mask(cpumask_of(cpu), RESCHEDULE_VECTOR);
+       apic->send_IPI(cpu, RESCHEDULE_VECTOR);
 }
 
 void native_send_call_func_single_ipi(int cpu)
 {
-       apic->send_IPI_mask(cpumask_of(cpu), CALL_FUNCTION_SINGLE_VECTOR);
+       apic->send_IPI(cpu, CALL_FUNCTION_SINGLE_VECTOR);
 }
 
 void native_send_call_func_ipi(const struct cpumask *mask)
index fbabe4fcc7fbb71802c756289ac01df9b11599ec..24d57f77b3c19615840ac4f09c8c0fd299864698 100644 (file)
@@ -304,7 +304,7 @@ do {                                                                        \
 
 static bool match_smt(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
 {
-       if (cpu_has_topoext) {
+       if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
                int cpu1 = c->cpu_index, cpu2 = o->cpu_index;
 
                if (c->phys_proc_id == o->phys_proc_id &&
@@ -629,13 +629,6 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
        else
                num_starts = 0;
 
-       /*
-        * Paravirt / VMI wants a startup IPI hook here to set up the
-        * target processor state.
-        */
-       startup_ipi_hook(phys_apicid, (unsigned long) start_secondary,
-                        stack_start);
-
        /*
         * Run STARTUP IPI loop.
         */
index c7c4d9c51e99fe582b71ab1f2e3ca9ffaae2226c..3d743da828d38acff0013600ed582c8b14ef81b3 100644 (file)
@@ -1185,8 +1185,6 @@ void __init tsc_init(void)
        u64 lpj;
        int cpu;
 
-       x86_init.timers.tsc_pre_init();
-
        if (!cpu_has_tsc) {
                setup_clear_cpu_cap(X86_FEATURE_TSC_DEADLINE_TIMER);
                return;
index 5246193519614dbd8d3a602544e8117376df05f7..483231ebbb0b2e254bbd749997e7b3feea62bb44 100644 (file)
@@ -357,8 +357,10 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus)
        tss = &per_cpu(cpu_tss, get_cpu());
        /* make room for real-mode segments */
        tsk->thread.sp0 += 16;
-       if (cpu_has_sep)
+
+       if (static_cpu_has_safe(X86_FEATURE_SEP))
                tsk->thread.sysenter_cs = 0;
+
        load_sp0(tss, &tsk->thread);
        put_cpu();
 
index 3839628d962e4f1baad89c124724413d8f17d8b2..dad5fe9633a37e03215892c60386a779745fdb61 100644 (file)
@@ -68,7 +68,6 @@ struct x86_init_ops x86_init __initdata = {
 
        .timers = {
                .setup_percpu_clockev   = setup_boot_APIC_clock,
-               .tsc_pre_init           = x86_init_noop,
                .timer_init             = hpet_time_init,
                .wallclock_init         = x86_init_noop,
        },
index 3f5c48ddba453064ff6dbe91731d1d0c7776be53..c8eda1498121fc6ee82c2facad7464eb712aa75b 100644 (file)
@@ -2,6 +2,7 @@
 #define ARCH_X86_KVM_CPUID_H
 
 #include "x86.h"
+#include <asm/cpu.h>
 
 int kvm_update_cpuid(struct kvm_vcpu *vcpu);
 struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu,
@@ -178,4 +179,37 @@ static inline bool guest_cpuid_has_nrips(struct kvm_vcpu *vcpu)
 }
 #undef BIT_NRIPS
 
+static inline int guest_cpuid_family(struct kvm_vcpu *vcpu)
+{
+       struct kvm_cpuid_entry2 *best;
+
+       best = kvm_find_cpuid_entry(vcpu, 0x1, 0);
+       if (!best)
+               return -1;
+
+       return x86_family(best->eax);
+}
+
+static inline int guest_cpuid_model(struct kvm_vcpu *vcpu)
+{
+       struct kvm_cpuid_entry2 *best;
+
+       best = kvm_find_cpuid_entry(vcpu, 0x1, 0);
+       if (!best)
+               return -1;
+
+       return x86_model(best->eax);
+}
+
+static inline int guest_cpuid_stepping(struct kvm_vcpu *vcpu)
+{
+       struct kvm_cpuid_entry2 *best;
+
+       best = kvm_find_cpuid_entry(vcpu, 0x1, 0);
+       if (!best)
+               return -1;
+
+       return x86_stepping(best->eax);
+}
+
 #endif
index 62cf8c915e95df1577d1d226bae9dc04f51b52e3..c58ba67175acde5b8b3e12dbaf84df46fb44f62c 100644 (file)
 
 #include "x86.h"
 #include "lapic.h"
+#include "ioapic.h"
 #include "hyperv.h"
 
 #include <linux/kvm_host.h>
+#include <linux/highmem.h>
+#include <asm/apicdef.h>
 #include <trace/events/kvm.h>
 
 #include "trace.h"
 
+static inline u64 synic_read_sint(struct kvm_vcpu_hv_synic *synic, int sint)
+{
+       return atomic64_read(&synic->sint[sint]);
+}
+
+static inline int synic_get_sint_vector(u64 sint_value)
+{
+       if (sint_value & HV_SYNIC_SINT_MASKED)
+               return -1;
+       return sint_value & HV_SYNIC_SINT_VECTOR_MASK;
+}
+
+static bool synic_has_vector_connected(struct kvm_vcpu_hv_synic *synic,
+                                     int vector)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(synic->sint); i++) {
+               if (synic_get_sint_vector(synic_read_sint(synic, i)) == vector)
+                       return true;
+       }
+       return false;
+}
+
+static bool synic_has_vector_auto_eoi(struct kvm_vcpu_hv_synic *synic,
+                                    int vector)
+{
+       int i;
+       u64 sint_value;
+
+       for (i = 0; i < ARRAY_SIZE(synic->sint); i++) {
+               sint_value = synic_read_sint(synic, i);
+               if (synic_get_sint_vector(sint_value) == vector &&
+                   sint_value & HV_SYNIC_SINT_AUTO_EOI)
+                       return true;
+       }
+       return false;
+}
+
+static int synic_set_sint(struct kvm_vcpu_hv_synic *synic, int sint,
+                         u64 data, bool host)
+{
+       int vector;
+
+       vector = data & HV_SYNIC_SINT_VECTOR_MASK;
+       if (vector < 16 && !host)
+               return 1;
+       /*
+        * Guest may configure multiple SINTs to use the same vector, so
+        * we maintain a bitmap of vectors handled by synic, and a
+        * bitmap of vectors with auto-eoi behavior.  The bitmaps are
+        * updated here, and atomically queried on fast paths.
+        */
+
+       atomic64_set(&synic->sint[sint], data);
+
+       if (synic_has_vector_connected(synic, vector))
+               __set_bit(vector, synic->vec_bitmap);
+       else
+               __clear_bit(vector, synic->vec_bitmap);
+
+       if (synic_has_vector_auto_eoi(synic, vector))
+               __set_bit(vector, synic->auto_eoi_bitmap);
+       else
+               __clear_bit(vector, synic->auto_eoi_bitmap);
+
+       /* Load SynIC vectors into EOI exit bitmap */
+       kvm_make_request(KVM_REQ_SCAN_IOAPIC, synic_to_vcpu(synic));
+       return 0;
+}
+
+static struct kvm_vcpu_hv_synic *synic_get(struct kvm *kvm, u32 vcpu_id)
+{
+       struct kvm_vcpu *vcpu;
+       struct kvm_vcpu_hv_synic *synic;
+
+       if (vcpu_id >= atomic_read(&kvm->online_vcpus))
+               return NULL;
+       vcpu = kvm_get_vcpu(kvm, vcpu_id);
+       if (!vcpu)
+               return NULL;
+       synic = vcpu_to_synic(vcpu);
+       return (synic->active) ? synic : NULL;
+}
+
+static void synic_clear_sint_msg_pending(struct kvm_vcpu_hv_synic *synic,
+                                       u32 sint)
+{
+       struct kvm_vcpu *vcpu = synic_to_vcpu(synic);
+       struct page *page;
+       gpa_t gpa;
+       struct hv_message *msg;
+       struct hv_message_page *msg_page;
+
+       gpa = synic->msg_page & PAGE_MASK;
+       page = kvm_vcpu_gfn_to_page(vcpu, gpa >> PAGE_SHIFT);
+       if (is_error_page(page)) {
+               vcpu_err(vcpu, "Hyper-V SynIC can't get msg page, gpa 0x%llx\n",
+                        gpa);
+               return;
+       }
+       msg_page = kmap_atomic(page);
+
+       msg = &msg_page->sint_message[sint];
+       msg->header.message_flags.msg_pending = 0;
+
+       kunmap_atomic(msg_page);
+       kvm_release_page_dirty(page);
+       kvm_vcpu_mark_page_dirty(vcpu, gpa >> PAGE_SHIFT);
+}
+
+static void kvm_hv_notify_acked_sint(struct kvm_vcpu *vcpu, u32 sint)
+{
+       struct kvm *kvm = vcpu->kvm;
+       struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu);
+       struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu);
+       struct kvm_vcpu_hv_stimer *stimer;
+       int gsi, idx, stimers_pending;
+
+       trace_kvm_hv_notify_acked_sint(vcpu->vcpu_id, sint);
+
+       if (synic->msg_page & HV_SYNIC_SIMP_ENABLE)
+               synic_clear_sint_msg_pending(synic, sint);
+
+       /* Try to deliver pending Hyper-V SynIC timers messages */
+       stimers_pending = 0;
+       for (idx = 0; idx < ARRAY_SIZE(hv_vcpu->stimer); idx++) {
+               stimer = &hv_vcpu->stimer[idx];
+               if (stimer->msg_pending &&
+                   (stimer->config & HV_STIMER_ENABLE) &&
+                   HV_STIMER_SINT(stimer->config) == sint) {
+                       set_bit(stimer->index,
+                               hv_vcpu->stimer_pending_bitmap);
+                       stimers_pending++;
+               }
+       }
+       if (stimers_pending)
+               kvm_make_request(KVM_REQ_HV_STIMER, vcpu);
+
+       idx = srcu_read_lock(&kvm->irq_srcu);
+       gsi = atomic_read(&synic->sint_to_gsi[sint]);
+       if (gsi != -1)
+               kvm_notify_acked_gsi(kvm, gsi);
+       srcu_read_unlock(&kvm->irq_srcu, idx);
+}
+
+static void synic_exit(struct kvm_vcpu_hv_synic *synic, u32 msr)
+{
+       struct kvm_vcpu *vcpu = synic_to_vcpu(synic);
+       struct kvm_vcpu_hv *hv_vcpu = &vcpu->arch.hyperv;
+
+       hv_vcpu->exit.type = KVM_EXIT_HYPERV_SYNIC;
+       hv_vcpu->exit.u.synic.msr = msr;
+       hv_vcpu->exit.u.synic.control = synic->control;
+       hv_vcpu->exit.u.synic.evt_page = synic->evt_page;
+       hv_vcpu->exit.u.synic.msg_page = synic->msg_page;
+
+       kvm_make_request(KVM_REQ_HV_EXIT, vcpu);
+}
+
+static int synic_set_msr(struct kvm_vcpu_hv_synic *synic,
+                        u32 msr, u64 data, bool host)
+{
+       struct kvm_vcpu *vcpu = synic_to_vcpu(synic);
+       int ret;
+
+       if (!synic->active)
+               return 1;
+
+       trace_kvm_hv_synic_set_msr(vcpu->vcpu_id, msr, data, host);
+
+       ret = 0;
+       switch (msr) {
+       case HV_X64_MSR_SCONTROL:
+               synic->control = data;
+               if (!host)
+                       synic_exit(synic, msr);
+               break;
+       case HV_X64_MSR_SVERSION:
+               if (!host) {
+                       ret = 1;
+                       break;
+               }
+               synic->version = data;
+               break;
+       case HV_X64_MSR_SIEFP:
+               if (data & HV_SYNIC_SIEFP_ENABLE)
+                       if (kvm_clear_guest(vcpu->kvm,
+                                           data & PAGE_MASK, PAGE_SIZE)) {
+                               ret = 1;
+                               break;
+                       }
+               synic->evt_page = data;
+               if (!host)
+                       synic_exit(synic, msr);
+               break;
+       case HV_X64_MSR_SIMP:
+               if (data & HV_SYNIC_SIMP_ENABLE)
+                       if (kvm_clear_guest(vcpu->kvm,
+                                           data & PAGE_MASK, PAGE_SIZE)) {
+                               ret = 1;
+                               break;
+                       }
+               synic->msg_page = data;
+               if (!host)
+                       synic_exit(synic, msr);
+               break;
+       case HV_X64_MSR_EOM: {
+               int i;
+
+               for (i = 0; i < ARRAY_SIZE(synic->sint); i++)
+                       kvm_hv_notify_acked_sint(vcpu, i);
+               break;
+       }
+       case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15:
+               ret = synic_set_sint(synic, msr - HV_X64_MSR_SINT0, data, host);
+               break;
+       default:
+               ret = 1;
+               break;
+       }
+       return ret;
+}
+
+static int synic_get_msr(struct kvm_vcpu_hv_synic *synic, u32 msr, u64 *pdata)
+{
+       int ret;
+
+       if (!synic->active)
+               return 1;
+
+       ret = 0;
+       switch (msr) {
+       case HV_X64_MSR_SCONTROL:
+               *pdata = synic->control;
+               break;
+       case HV_X64_MSR_SVERSION:
+               *pdata = synic->version;
+               break;
+       case HV_X64_MSR_SIEFP:
+               *pdata = synic->evt_page;
+               break;
+       case HV_X64_MSR_SIMP:
+               *pdata = synic->msg_page;
+               break;
+       case HV_X64_MSR_EOM:
+               *pdata = 0;
+               break;
+       case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15:
+               *pdata = atomic64_read(&synic->sint[msr - HV_X64_MSR_SINT0]);
+               break;
+       default:
+               ret = 1;
+               break;
+       }
+       return ret;
+}
+
+int synic_set_irq(struct kvm_vcpu_hv_synic *synic, u32 sint)
+{
+       struct kvm_vcpu *vcpu = synic_to_vcpu(synic);
+       struct kvm_lapic_irq irq;
+       int ret, vector;
+
+       if (sint >= ARRAY_SIZE(synic->sint))
+               return -EINVAL;
+
+       vector = synic_get_sint_vector(synic_read_sint(synic, sint));
+       if (vector < 0)
+               return -ENOENT;
+
+       memset(&irq, 0, sizeof(irq));
+       irq.dest_id = kvm_apic_id(vcpu->arch.apic);
+       irq.dest_mode = APIC_DEST_PHYSICAL;
+       irq.delivery_mode = APIC_DM_FIXED;
+       irq.vector = vector;
+       irq.level = 1;
+
+       ret = kvm_irq_delivery_to_apic(vcpu->kvm, NULL, &irq, NULL);
+       trace_kvm_hv_synic_set_irq(vcpu->vcpu_id, sint, irq.vector, ret);
+       return ret;
+}
+
+int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint)
+{
+       struct kvm_vcpu_hv_synic *synic;
+
+       synic = synic_get(kvm, vcpu_id);
+       if (!synic)
+               return -EINVAL;
+
+       return synic_set_irq(synic, sint);
+}
+
+void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector)
+{
+       struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu);
+       int i;
+
+       trace_kvm_hv_synic_send_eoi(vcpu->vcpu_id, vector);
+
+       for (i = 0; i < ARRAY_SIZE(synic->sint); i++)
+               if (synic_get_sint_vector(synic_read_sint(synic, i)) == vector)
+                       kvm_hv_notify_acked_sint(vcpu, i);
+}
+
+static int kvm_hv_set_sint_gsi(struct kvm *kvm, u32 vcpu_id, u32 sint, int gsi)
+{
+       struct kvm_vcpu_hv_synic *synic;
+
+       synic = synic_get(kvm, vcpu_id);
+       if (!synic)
+               return -EINVAL;
+
+       if (sint >= ARRAY_SIZE(synic->sint_to_gsi))
+               return -EINVAL;
+
+       atomic_set(&synic->sint_to_gsi[sint], gsi);
+       return 0;
+}
+
+void kvm_hv_irq_routing_update(struct kvm *kvm)
+{
+       struct kvm_irq_routing_table *irq_rt;
+       struct kvm_kernel_irq_routing_entry *e;
+       u32 gsi;
+
+       irq_rt = srcu_dereference_check(kvm->irq_routing, &kvm->irq_srcu,
+                                       lockdep_is_held(&kvm->irq_lock));
+
+       for (gsi = 0; gsi < irq_rt->nr_rt_entries; gsi++) {
+               hlist_for_each_entry(e, &irq_rt->map[gsi], link) {
+                       if (e->type == KVM_IRQ_ROUTING_HV_SINT)
+                               kvm_hv_set_sint_gsi(kvm, e->hv_sint.vcpu,
+                                                   e->hv_sint.sint, gsi);
+               }
+       }
+}
+
+static void synic_init(struct kvm_vcpu_hv_synic *synic)
+{
+       int i;
+
+       memset(synic, 0, sizeof(*synic));
+       synic->version = HV_SYNIC_VERSION_1;
+       for (i = 0; i < ARRAY_SIZE(synic->sint); i++) {
+               atomic64_set(&synic->sint[i], HV_SYNIC_SINT_MASKED);
+               atomic_set(&synic->sint_to_gsi[i], -1);
+       }
+}
+
+static u64 get_time_ref_counter(struct kvm *kvm)
+{
+       return div_u64(get_kernel_ns() + kvm->arch.kvmclock_offset, 100);
+}
+
+static void stimer_mark_pending(struct kvm_vcpu_hv_stimer *stimer,
+                               bool vcpu_kick)
+{
+       struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer);
+
+       set_bit(stimer->index,
+               vcpu_to_hv_vcpu(vcpu)->stimer_pending_bitmap);
+       kvm_make_request(KVM_REQ_HV_STIMER, vcpu);
+       if (vcpu_kick)
+               kvm_vcpu_kick(vcpu);
+}
+
+static void stimer_cleanup(struct kvm_vcpu_hv_stimer *stimer)
+{
+       struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer);
+
+       trace_kvm_hv_stimer_cleanup(stimer_to_vcpu(stimer)->vcpu_id,
+                                   stimer->index);
+
+       hrtimer_cancel(&stimer->timer);
+       clear_bit(stimer->index,
+                 vcpu_to_hv_vcpu(vcpu)->stimer_pending_bitmap);
+       stimer->msg_pending = false;
+       stimer->exp_time = 0;
+}
+
+static enum hrtimer_restart stimer_timer_callback(struct hrtimer *timer)
+{
+       struct kvm_vcpu_hv_stimer *stimer;
+
+       stimer = container_of(timer, struct kvm_vcpu_hv_stimer, timer);
+       trace_kvm_hv_stimer_callback(stimer_to_vcpu(stimer)->vcpu_id,
+                                    stimer->index);
+       stimer_mark_pending(stimer, true);
+
+       return HRTIMER_NORESTART;
+}
+
+/*
+ * stimer_start() assumptions:
+ * a) stimer->count is not equal to 0
+ * b) stimer->config has HV_STIMER_ENABLE flag
+ */
+static int stimer_start(struct kvm_vcpu_hv_stimer *stimer)
+{
+       u64 time_now;
+       ktime_t ktime_now;
+
+       time_now = get_time_ref_counter(stimer_to_vcpu(stimer)->kvm);
+       ktime_now = ktime_get();
+
+       if (stimer->config & HV_STIMER_PERIODIC) {
+               if (stimer->exp_time) {
+                       if (time_now >= stimer->exp_time) {
+                               u64 remainder;
+
+                               div64_u64_rem(time_now - stimer->exp_time,
+                                             stimer->count, &remainder);
+                               stimer->exp_time =
+                                       time_now + (stimer->count - remainder);
+                       }
+               } else
+                       stimer->exp_time = time_now + stimer->count;
+
+               trace_kvm_hv_stimer_start_periodic(
+                                       stimer_to_vcpu(stimer)->vcpu_id,
+                                       stimer->index,
+                                       time_now, stimer->exp_time);
+
+               hrtimer_start(&stimer->timer,
+                             ktime_add_ns(ktime_now,
+                                          100 * (stimer->exp_time - time_now)),
+                             HRTIMER_MODE_ABS);
+               return 0;
+       }
+       stimer->exp_time = stimer->count;
+       if (time_now >= stimer->count) {
+               /*
+                * Expire timer according to Hypervisor Top-Level Functional
+                * specification v4(15.3.1):
+                * "If a one shot is enabled and the specified count is in
+                * the past, it will expire immediately."
+                */
+               stimer_mark_pending(stimer, false);
+               return 0;
+       }
+
+       trace_kvm_hv_stimer_start_one_shot(stimer_to_vcpu(stimer)->vcpu_id,
+                                          stimer->index,
+                                          time_now, stimer->count);
+
+       hrtimer_start(&stimer->timer,
+                     ktime_add_ns(ktime_now, 100 * (stimer->count - time_now)),
+                     HRTIMER_MODE_ABS);
+       return 0;
+}
+
+static int stimer_set_config(struct kvm_vcpu_hv_stimer *stimer, u64 config,
+                            bool host)
+{
+       trace_kvm_hv_stimer_set_config(stimer_to_vcpu(stimer)->vcpu_id,
+                                      stimer->index, config, host);
+
+       stimer_cleanup(stimer);
+       if ((stimer->config & HV_STIMER_ENABLE) && HV_STIMER_SINT(config) == 0)
+               config &= ~HV_STIMER_ENABLE;
+       stimer->config = config;
+       stimer_mark_pending(stimer, false);
+       return 0;
+}
+
+static int stimer_set_count(struct kvm_vcpu_hv_stimer *stimer, u64 count,
+                           bool host)
+{
+       trace_kvm_hv_stimer_set_count(stimer_to_vcpu(stimer)->vcpu_id,
+                                     stimer->index, count, host);
+
+       stimer_cleanup(stimer);
+       stimer->count = count;
+       if (stimer->count == 0)
+               stimer->config &= ~HV_STIMER_ENABLE;
+       else if (stimer->config & HV_STIMER_AUTOENABLE)
+               stimer->config |= HV_STIMER_ENABLE;
+       stimer_mark_pending(stimer, false);
+       return 0;
+}
+
+static int stimer_get_config(struct kvm_vcpu_hv_stimer *stimer, u64 *pconfig)
+{
+       *pconfig = stimer->config;
+       return 0;
+}
+
+static int stimer_get_count(struct kvm_vcpu_hv_stimer *stimer, u64 *pcount)
+{
+       *pcount = stimer->count;
+       return 0;
+}
+
+static int synic_deliver_msg(struct kvm_vcpu_hv_synic *synic, u32 sint,
+                            struct hv_message *src_msg)
+{
+       struct kvm_vcpu *vcpu = synic_to_vcpu(synic);
+       struct page *page;
+       gpa_t gpa;
+       struct hv_message *dst_msg;
+       int r;
+       struct hv_message_page *msg_page;
+
+       if (!(synic->msg_page & HV_SYNIC_SIMP_ENABLE))
+               return -ENOENT;
+
+       gpa = synic->msg_page & PAGE_MASK;
+       page = kvm_vcpu_gfn_to_page(vcpu, gpa >> PAGE_SHIFT);
+       if (is_error_page(page))
+               return -EFAULT;
+
+       msg_page = kmap_atomic(page);
+       dst_msg = &msg_page->sint_message[sint];
+       if (sync_cmpxchg(&dst_msg->header.message_type, HVMSG_NONE,
+                        src_msg->header.message_type) != HVMSG_NONE) {
+               dst_msg->header.message_flags.msg_pending = 1;
+               r = -EAGAIN;
+       } else {
+               memcpy(&dst_msg->u.payload, &src_msg->u.payload,
+                      src_msg->header.payload_size);
+               dst_msg->header.message_type = src_msg->header.message_type;
+               dst_msg->header.payload_size = src_msg->header.payload_size;
+               r = synic_set_irq(synic, sint);
+               if (r >= 1)
+                       r = 0;
+               else if (r == 0)
+                       r = -EFAULT;
+       }
+       kunmap_atomic(msg_page);
+       kvm_release_page_dirty(page);
+       kvm_vcpu_mark_page_dirty(vcpu, gpa >> PAGE_SHIFT);
+       return r;
+}
+
+static int stimer_send_msg(struct kvm_vcpu_hv_stimer *stimer)
+{
+       struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer);
+       struct hv_message *msg = &stimer->msg;
+       struct hv_timer_message_payload *payload =
+                       (struct hv_timer_message_payload *)&msg->u.payload;
+
+       payload->expiration_time = stimer->exp_time;
+       payload->delivery_time = get_time_ref_counter(vcpu->kvm);
+       return synic_deliver_msg(vcpu_to_synic(vcpu),
+                                HV_STIMER_SINT(stimer->config), msg);
+}
+
+static void stimer_expiration(struct kvm_vcpu_hv_stimer *stimer)
+{
+       int r;
+
+       stimer->msg_pending = true;
+       r = stimer_send_msg(stimer);
+       trace_kvm_hv_stimer_expiration(stimer_to_vcpu(stimer)->vcpu_id,
+                                      stimer->index, r);
+       if (!r) {
+               stimer->msg_pending = false;
+               if (!(stimer->config & HV_STIMER_PERIODIC))
+                       stimer->config &= ~HV_STIMER_ENABLE;
+       }
+}
+
+void kvm_hv_process_stimers(struct kvm_vcpu *vcpu)
+{
+       struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu);
+       struct kvm_vcpu_hv_stimer *stimer;
+       u64 time_now, exp_time;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(hv_vcpu->stimer); i++)
+               if (test_and_clear_bit(i, hv_vcpu->stimer_pending_bitmap)) {
+                       stimer = &hv_vcpu->stimer[i];
+                       if (stimer->config & HV_STIMER_ENABLE) {
+                               exp_time = stimer->exp_time;
+
+                               if (exp_time) {
+                                       time_now =
+                                               get_time_ref_counter(vcpu->kvm);
+                                       if (time_now >= exp_time)
+                                               stimer_expiration(stimer);
+                               }
+
+                               if ((stimer->config & HV_STIMER_ENABLE) &&
+                                   stimer->count)
+                                       stimer_start(stimer);
+                               else
+                                       stimer_cleanup(stimer);
+                       }
+               }
+}
+
+void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+       struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(hv_vcpu->stimer); i++)
+               stimer_cleanup(&hv_vcpu->stimer[i]);
+}
+
+static void stimer_prepare_msg(struct kvm_vcpu_hv_stimer *stimer)
+{
+       struct hv_message *msg = &stimer->msg;
+       struct hv_timer_message_payload *payload =
+                       (struct hv_timer_message_payload *)&msg->u.payload;
+
+       memset(&msg->header, 0, sizeof(msg->header));
+       msg->header.message_type = HVMSG_TIMER_EXPIRED;
+       msg->header.payload_size = sizeof(*payload);
+
+       payload->timer_index = stimer->index;
+       payload->expiration_time = 0;
+       payload->delivery_time = 0;
+}
+
+static void stimer_init(struct kvm_vcpu_hv_stimer *stimer, int timer_index)
+{
+       memset(stimer, 0, sizeof(*stimer));
+       stimer->index = timer_index;
+       hrtimer_init(&stimer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+       stimer->timer.function = stimer_timer_callback;
+       stimer_prepare_msg(stimer);
+}
+
+void kvm_hv_vcpu_init(struct kvm_vcpu *vcpu)
+{
+       struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu);
+       int i;
+
+       synic_init(&hv_vcpu->synic);
+
+       bitmap_zero(hv_vcpu->stimer_pending_bitmap, HV_SYNIC_STIMER_COUNT);
+       for (i = 0; i < ARRAY_SIZE(hv_vcpu->stimer); i++)
+               stimer_init(&hv_vcpu->stimer[i], i);
+}
+
+int kvm_hv_activate_synic(struct kvm_vcpu *vcpu)
+{
+       /*
+        * Hyper-V SynIC auto EOI SINT's are
+        * not compatible with APICV, so deactivate APICV
+        */
+       kvm_vcpu_deactivate_apicv(vcpu);
+       vcpu_to_synic(vcpu)->active = true;
+       return 0;
+}
+
 static bool kvm_hv_msr_partition_wide(u32 msr)
 {
        bool r = false;
@@ -226,6 +878,31 @@ static int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host)
                        return 1;
                hv->runtime_offset = data - current_task_runtime_100ns();
                break;
+       case HV_X64_MSR_SCONTROL:
+       case HV_X64_MSR_SVERSION:
+       case HV_X64_MSR_SIEFP:
+       case HV_X64_MSR_SIMP:
+       case HV_X64_MSR_EOM:
+       case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15:
+               return synic_set_msr(vcpu_to_synic(vcpu), msr, data, host);
+       case HV_X64_MSR_STIMER0_CONFIG:
+       case HV_X64_MSR_STIMER1_CONFIG:
+       case HV_X64_MSR_STIMER2_CONFIG:
+       case HV_X64_MSR_STIMER3_CONFIG: {
+               int timer_index = (msr - HV_X64_MSR_STIMER0_CONFIG)/2;
+
+               return stimer_set_config(vcpu_to_stimer(vcpu, timer_index),
+                                        data, host);
+       }
+       case HV_X64_MSR_STIMER0_COUNT:
+       case HV_X64_MSR_STIMER1_COUNT:
+       case HV_X64_MSR_STIMER2_COUNT:
+       case HV_X64_MSR_STIMER3_COUNT: {
+               int timer_index = (msr - HV_X64_MSR_STIMER0_COUNT)/2;
+
+               return stimer_set_count(vcpu_to_stimer(vcpu, timer_index),
+                                       data, host);
+       }
        default:
                vcpu_unimpl(vcpu, "Hyper-V uhandled wrmsr: 0x%x data 0x%llx\n",
                            msr, data);
@@ -248,11 +925,9 @@ static int kvm_hv_get_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
        case HV_X64_MSR_HYPERCALL:
                data = hv->hv_hypercall;
                break;
-       case HV_X64_MSR_TIME_REF_COUNT: {
-               data =
-                    div_u64(get_kernel_ns() + kvm->arch.kvmclock_offset, 100);
+       case HV_X64_MSR_TIME_REF_COUNT:
+               data = get_time_ref_counter(kvm);
                break;
-       }
        case HV_X64_MSR_REFERENCE_TSC:
                data = hv->hv_tsc_page;
                break;
@@ -304,6 +979,31 @@ static int kvm_hv_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
        case HV_X64_MSR_VP_RUNTIME:
                data = current_task_runtime_100ns() + hv->runtime_offset;
                break;
+       case HV_X64_MSR_SCONTROL:
+       case HV_X64_MSR_SVERSION:
+       case HV_X64_MSR_SIEFP:
+       case HV_X64_MSR_SIMP:
+       case HV_X64_MSR_EOM:
+       case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15:
+               return synic_get_msr(vcpu_to_synic(vcpu), msr, pdata);
+       case HV_X64_MSR_STIMER0_CONFIG:
+       case HV_X64_MSR_STIMER1_CONFIG:
+       case HV_X64_MSR_STIMER2_CONFIG:
+       case HV_X64_MSR_STIMER3_CONFIG: {
+               int timer_index = (msr - HV_X64_MSR_STIMER0_CONFIG)/2;
+
+               return stimer_get_config(vcpu_to_stimer(vcpu, timer_index),
+                                        pdata);
+       }
+       case HV_X64_MSR_STIMER0_COUNT:
+       case HV_X64_MSR_STIMER1_COUNT:
+       case HV_X64_MSR_STIMER2_COUNT:
+       case HV_X64_MSR_STIMER3_COUNT: {
+               int timer_index = (msr - HV_X64_MSR_STIMER0_COUNT)/2;
+
+               return stimer_get_count(vcpu_to_stimer(vcpu, timer_index),
+                                       pdata);
+       }
        default:
                vcpu_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr);
                return 1;
index c7bce559f67b3e90044ea2c96b00280f9c978ebe..60eccd4bd1d365f45a700a08f84e7935b8461634 100644 (file)
 #ifndef __ARCH_X86_KVM_HYPERV_H__
 #define __ARCH_X86_KVM_HYPERV_H__
 
+static inline struct kvm_vcpu_hv *vcpu_to_hv_vcpu(struct kvm_vcpu *vcpu)
+{
+       return &vcpu->arch.hyperv;
+}
+
+static inline struct kvm_vcpu *hv_vcpu_to_vcpu(struct kvm_vcpu_hv *hv_vcpu)
+{
+       struct kvm_vcpu_arch *arch;
+
+       arch = container_of(hv_vcpu, struct kvm_vcpu_arch, hyperv);
+       return container_of(arch, struct kvm_vcpu, arch);
+}
+
+static inline struct kvm_vcpu_hv_synic *vcpu_to_synic(struct kvm_vcpu *vcpu)
+{
+       return &vcpu->arch.hyperv.synic;
+}
+
+static inline struct kvm_vcpu *synic_to_vcpu(struct kvm_vcpu_hv_synic *synic)
+{
+       return hv_vcpu_to_vcpu(container_of(synic, struct kvm_vcpu_hv, synic));
+}
+
 int kvm_hv_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host);
 int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);
+
 bool kvm_hv_hypercall_enabled(struct kvm *kvm);
 int kvm_hv_hypercall(struct kvm_vcpu *vcpu);
 
+void kvm_hv_irq_routing_update(struct kvm *kvm);
+int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint);
+void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector);
+int kvm_hv_activate_synic(struct kvm_vcpu *vcpu);
+
+void kvm_hv_vcpu_init(struct kvm_vcpu *vcpu);
+void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu);
+
+static inline struct kvm_vcpu_hv_stimer *vcpu_to_stimer(struct kvm_vcpu *vcpu,
+                                                       int timer_index)
+{
+       return &vcpu_to_hv_vcpu(vcpu)->stimer[timer_index];
+}
+
+static inline struct kvm_vcpu *stimer_to_vcpu(struct kvm_vcpu_hv_stimer *stimer)
+{
+       struct kvm_vcpu_hv *hv_vcpu;
+
+       hv_vcpu = container_of(stimer - stimer->index, struct kvm_vcpu_hv,
+                              stimer[0]);
+       return hv_vcpu_to_vcpu(hv_vcpu);
+}
+
+static inline bool kvm_hv_has_stimer_pending(struct kvm_vcpu *vcpu)
+{
+       return !bitmap_empty(vcpu->arch.hyperv.stimer_pending_bitmap,
+                            HV_SYNIC_STIMER_COUNT);
+}
+
+void kvm_hv_process_stimers(struct kvm_vcpu *vcpu);
+
 #endif
index 08116ff227cc67acaaf452322b1f95db8e051bfd..b0ea42b78ccdb50879a10c440d5e3a7fe194fbe9 100644 (file)
@@ -420,6 +420,7 @@ void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val, int hpet_legacy_s
        u8 saved_mode;
        if (hpet_legacy_start) {
                /* save existing mode for later reenablement */
+               WARN_ON(channel != 0);
                saved_mode = kvm->arch.vpit->pit_state.channels[0].mode;
                kvm->arch.vpit->pit_state.channels[0].mode = 0xff; /* disable timer */
                pit_load_count(kvm, channel, val);
index 88d0a92d3f94676d2e68cdb19b2bdd35b49a7d15..1facfd60b04ac5eed05112b0cc3412396c8aa86d 100644 (file)
@@ -233,7 +233,7 @@ static void kvm_ioapic_inject_all(struct kvm_ioapic *ioapic, unsigned long irr)
 }
 
 
-void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
+void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, ulong *ioapic_handled_vectors)
 {
        struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic;
        union kvm_ioapic_redirect_entry *e;
@@ -250,7 +250,7 @@ void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
                            (e->fields.trig_mode == IOAPIC_EDGE_TRIG &&
                             kvm_apic_pending_eoi(vcpu, e->fields.vector)))
                                __set_bit(e->fields.vector,
-                                       (unsigned long *)eoi_exit_bitmap);
+                                         ioapic_handled_vectors);
                }
        }
        spin_unlock(&ioapic->lock);
index 084617d37c74d0264926cdb26bef3fb57c06965e..2d16dc251d81a45cff53ae2a9d629e8ee7ecb732 100644 (file)
@@ -121,7 +121,8 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
                struct kvm_lapic_irq *irq, unsigned long *dest_map);
 int kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state);
 int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state);
-void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
-void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
-
+void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu,
+                          ulong *ioapic_handled_vectors);
+void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu,
+                           ulong *ioapic_handled_vectors);
 #endif
index 097060e33bd6a67b0743a4cb3918b1baef765496..3982b479bb5fe46ae147b01d0cf91933ea8be455 100644 (file)
@@ -76,7 +76,7 @@ int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v)
        if (kvm_cpu_has_extint(v))
                return 1;
 
-       if (kvm_vcpu_apic_vid_enabled(v))
+       if (kvm_vcpu_apicv_active(v))
                return 0;
 
        return kvm_apic_has_interrupt(v) != -1; /* LAPIC */
index 84b96d319909414fd3aba1e7b7888486843f86b8..8fc89efb5250fda6d8b9baaa6f4d35af1e8844ad 100644 (file)
@@ -33,6 +33,8 @@
 
 #include "lapic.h"
 
+#include "hyperv.h"
+
 static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e,
                           struct kvm *kvm, int irq_source_id, int level,
                           bool line_status)
@@ -219,6 +221,16 @@ void kvm_fire_mask_notifiers(struct kvm *kvm, unsigned irqchip, unsigned pin,
        srcu_read_unlock(&kvm->irq_srcu, idx);
 }
 
+static int kvm_hv_set_sint(struct kvm_kernel_irq_routing_entry *e,
+                   struct kvm *kvm, int irq_source_id, int level,
+                   bool line_status)
+{
+       if (!level)
+               return -1;
+
+       return kvm_hv_synic_set_irq(kvm, e->hv_sint.vcpu, e->hv_sint.sint);
+}
+
 int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e,
                          const struct kvm_irq_routing_entry *ue)
 {
@@ -257,6 +269,11 @@ int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e,
                e->msi.address_hi = ue->u.msi.address_hi;
                e->msi.data = ue->u.msi.data;
                break;
+       case KVM_IRQ_ROUTING_HV_SINT:
+               e->set = kvm_hv_set_sint;
+               e->hv_sint.vcpu = ue->u.hv_sint.vcpu;
+               e->hv_sint.sint = ue->u.hv_sint.sint;
+               break;
        default:
                goto out;
        }
@@ -332,14 +349,15 @@ int kvm_setup_empty_irq_routing(struct kvm *kvm)
        return kvm_set_irq_routing(kvm, empty_routing, 0, 0);
 }
 
-void kvm_arch_irq_routing_update(struct kvm *kvm)
+void kvm_arch_post_irq_routing_update(struct kvm *kvm)
 {
        if (ioapic_in_kernel(kvm) || !irqchip_in_kernel(kvm))
                return;
        kvm_make_scan_ioapic_request(kvm);
 }
 
-void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
+void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu,
+                           ulong *ioapic_handled_vectors)
 {
        struct kvm *kvm = vcpu->kvm;
        struct kvm_kernel_irq_routing_entry *entry;
@@ -369,9 +387,26 @@ void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
                                u32 vector = entry->msi.data & 0xff;
 
                                __set_bit(vector,
-                                         (unsigned long *) eoi_exit_bitmap);
+                                         ioapic_handled_vectors);
                        }
                }
        }
        srcu_read_unlock(&kvm->irq_srcu, idx);
 }
+
+int kvm_arch_set_irq(struct kvm_kernel_irq_routing_entry *irq, struct kvm *kvm,
+                    int irq_source_id, int level, bool line_status)
+{
+       switch (irq->type) {
+       case KVM_IRQ_ROUTING_HV_SINT:
+               return kvm_hv_set_sint(irq, kvm, irq_source_id, level,
+                                      line_status);
+       default:
+               return -EWOULDBLOCK;
+       }
+}
+
+void kvm_arch_irq_routing_update(struct kvm *kvm)
+{
+       kvm_hv_irq_routing_update(kvm);
+}
index 4d30b865be30641f4964a3279939020e9f1a057a..36591faed13be04d12c13fa520d46ca9df0dfcf8 100644 (file)
@@ -41,6 +41,7 @@
 #include "trace.h"
 #include "x86.h"
 #include "cpuid.h"
+#include "hyperv.h"
 
 #ifndef CONFIG_X86_64
 #define mod_64(x, y) ((x) - (y) * div64_u64(x, y))
@@ -128,11 +129,6 @@ static inline int apic_enabled(struct kvm_lapic *apic)
        (LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY | \
         APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER)
 
-static inline int kvm_apic_id(struct kvm_lapic *apic)
-{
-       return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
-}
-
 /* The logical map is definitely wrong if we have multiple
  * modes at the same time.  (Physical map is always right.)
  */
@@ -379,7 +375,8 @@ static inline int apic_find_highest_irr(struct kvm_lapic *apic)
        if (!apic->irr_pending)
                return -1;
 
-       kvm_x86_ops->sync_pir_to_irr(apic->vcpu);
+       if (apic->vcpu->arch.apicv_active)
+               kvm_x86_ops->sync_pir_to_irr(apic->vcpu);
        result = apic_search_irr(apic);
        ASSERT(result == -1 || result >= 16);
 
@@ -392,7 +389,7 @@ static inline void apic_clear_irr(int vec, struct kvm_lapic *apic)
 
        vcpu = apic->vcpu;
 
-       if (unlikely(kvm_vcpu_apic_vid_enabled(vcpu))) {
+       if (unlikely(vcpu->arch.apicv_active)) {
                /* try to update RVI */
                apic_clear_vector(vec, apic->regs + APIC_IRR);
                kvm_make_request(KVM_REQ_EVENT, vcpu);
@@ -418,7 +415,7 @@ static inline void apic_set_isr(int vec, struct kvm_lapic *apic)
         * because the processor can modify ISR under the hood.  Instead
         * just set SVI.
         */
-       if (unlikely(kvm_x86_ops->hwapic_isr_update))
+       if (unlikely(vcpu->arch.apicv_active))
                kvm_x86_ops->hwapic_isr_update(vcpu->kvm, vec);
        else {
                ++apic->isr_count;
@@ -466,7 +463,7 @@ static inline void apic_clear_isr(int vec, struct kvm_lapic *apic)
         * on the other hand isr_count and highest_isr_cache are unused
         * and must be left alone.
         */
-       if (unlikely(kvm_x86_ops->hwapic_isr_update))
+       if (unlikely(vcpu->arch.apicv_active))
                kvm_x86_ops->hwapic_isr_update(vcpu->kvm,
                                               apic_find_highest_isr(apic));
        else {
@@ -852,7 +849,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
                                apic_clear_vector(vector, apic->regs + APIC_TMR);
                }
 
-               if (kvm_x86_ops->deliver_posted_interrupt)
+               if (vcpu->arch.apicv_active)
                        kvm_x86_ops->deliver_posted_interrupt(vcpu, vector);
                else {
                        apic_set_irr(vector, apic);
@@ -932,7 +929,7 @@ int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2)
 
 static bool kvm_ioapic_handles_vector(struct kvm_lapic *apic, int vector)
 {
-       return test_bit(vector, (ulong *)apic->vcpu->arch.eoi_exit_bitmap);
+       return test_bit(vector, apic->vcpu->arch.ioapic_handled_vectors);
 }
 
 static void kvm_ioapic_send_eoi(struct kvm_lapic *apic, int vector)
@@ -974,6 +971,9 @@ static int apic_set_eoi(struct kvm_lapic *apic)
        apic_clear_isr(vector, apic);
        apic_update_ppr(apic);
 
+       if (test_bit(vector, vcpu_to_synic(apic->vcpu)->vec_bitmap))
+               kvm_hv_synic_send_eoi(apic->vcpu, vector);
+
        kvm_ioapic_send_eoi(apic, vector);
        kvm_make_request(KVM_REQ_EVENT, apic->vcpu);
        return vector;
@@ -1225,7 +1225,7 @@ static bool lapic_timer_int_injected(struct kvm_vcpu *vcpu)
                int vec = reg & APIC_VECTOR_MASK;
                void *bitmap = apic->regs + APIC_ISR;
 
-               if (kvm_x86_ops->deliver_posted_interrupt)
+               if (vcpu->arch.apicv_active)
                        bitmap = apic->regs + APIC_IRR;
 
                if (apic_test_vector(vec, bitmap))
@@ -1693,8 +1693,8 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
                apic_set_reg(apic, APIC_ISR + 0x10 * i, 0);
                apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
        }
-       apic->irr_pending = kvm_vcpu_apic_vid_enabled(vcpu);
-       apic->isr_count = kvm_x86_ops->hwapic_isr_update ? 1 : 0;
+       apic->irr_pending = vcpu->arch.apicv_active;
+       apic->isr_count = vcpu->arch.apicv_active ? 1 : 0;
        apic->highest_isr_cache = -1;
        update_divide_count(apic);
        atomic_set(&apic->lapic_timer.pending, 0);
@@ -1883,6 +1883,12 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
        apic_set_isr(vector, apic);
        apic_update_ppr(apic);
        apic_clear_irr(vector, apic);
+
+       if (test_bit(vector, vcpu_to_synic(vcpu)->auto_eoi_bitmap)) {
+               apic_clear_isr(vector, apic);
+               apic_update_ppr(apic);
+       }
+
        return vector;
 }
 
@@ -1906,15 +1912,15 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
        update_divide_count(apic);
        start_apic_timer(apic);
        apic->irr_pending = true;
-       apic->isr_count = kvm_x86_ops->hwapic_isr_update ?
+       apic->isr_count = vcpu->arch.apicv_active ?
                                1 : count_vectors(apic->regs + APIC_ISR);
        apic->highest_isr_cache = -1;
-       if (kvm_x86_ops->hwapic_irr_update)
+       if (vcpu->arch.apicv_active) {
                kvm_x86_ops->hwapic_irr_update(vcpu,
                                apic_find_highest_irr(apic));
-       if (unlikely(kvm_x86_ops->hwapic_isr_update))
                kvm_x86_ops->hwapic_isr_update(vcpu->kvm,
                                apic_find_highest_isr(apic));
+       }
        kvm_make_request(KVM_REQ_EVENT, vcpu);
        if (ioapic_in_kernel(vcpu->kvm))
                kvm_rtc_eoi_tracking_restore_one(vcpu);
index fde8e35d585050e7e2d26b9df326e7542b3d7f38..41bdb35b4b67ab10a2ebcd943d2d75d48431ff46 100644 (file)
@@ -143,9 +143,9 @@ static inline int apic_x2apic_mode(struct kvm_lapic *apic)
        return apic->vcpu->arch.apic_base & X2APIC_ENABLE;
 }
 
-static inline bool kvm_vcpu_apic_vid_enabled(struct kvm_vcpu *vcpu)
+static inline bool kvm_vcpu_apicv_active(struct kvm_vcpu *vcpu)
 {
-       return kvm_x86_ops->cpu_uses_apicv(vcpu);
+       return vcpu->arch.apic && vcpu->arch.apicv_active;
 }
 
 static inline bool kvm_apic_has_events(struct kvm_vcpu *vcpu)
@@ -164,6 +164,11 @@ static inline int kvm_lapic_latched_init(struct kvm_vcpu *vcpu)
        return kvm_vcpu_has_lapic(vcpu) && test_bit(KVM_APIC_INIT, &vcpu->arch.apic->pending_events);
 }
 
+static inline int kvm_apic_id(struct kvm_lapic *apic)
+{
+       return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
+}
+
 bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector);
 
 void wait_lapic_expire(struct kvm_vcpu *vcpu);
index e7c2c1428a691676a6a1fdadee044ab45124acc2..420a5ca3c0ee445d83f8b155726806fbe90f0810 100644 (file)
@@ -311,11 +311,6 @@ static int is_large_pte(u64 pte)
        return pte & PT_PAGE_SIZE_MASK;
 }
 
-static int is_rmap_spte(u64 pte)
-{
-       return is_shadow_present_pte(pte);
-}
-
 static int is_last_spte(u64 pte, int level)
 {
        if (level == PT_PAGE_TABLE_LEVEL)
@@ -540,7 +535,7 @@ static bool mmu_spte_update(u64 *sptep, u64 new_spte)
        u64 old_spte = *sptep;
        bool ret = false;
 
-       WARN_ON(!is_rmap_spte(new_spte));
+       WARN_ON(!is_shadow_present_pte(new_spte));
 
        if (!is_shadow_present_pte(old_spte)) {
                mmu_spte_set(sptep, new_spte);
@@ -595,7 +590,7 @@ static int mmu_spte_clear_track_bits(u64 *sptep)
        else
                old_spte = __update_clear_spte_slow(sptep, 0ull);
 
-       if (!is_rmap_spte(old_spte))
+       if (!is_shadow_present_pte(old_spte))
                return 0;
 
        pfn = spte_to_pfn(old_spte);
@@ -909,36 +904,35 @@ static int mapping_level(struct kvm_vcpu *vcpu, gfn_t large_gfn,
 }
 
 /*
- * Pte mapping structures:
+ * About rmap_head encoding:
  *
- * If pte_list bit zero is zero, then pte_list point to the spte.
- *
- * If pte_list bit zero is one, (then pte_list & ~1) points to a struct
+ * If the bit zero of rmap_head->val is clear, then it points to the only spte
+ * in this rmap chain. Otherwise, (rmap_head->val & ~1) points to a struct
  * pte_list_desc containing more mappings.
- *
- * Returns the number of pte entries before the spte was added or zero if
- * the spte was not added.
- *
+ */
+
+/*
+ * Returns the number of pointers in the rmap chain, not counting the new one.
  */
 static int pte_list_add(struct kvm_vcpu *vcpu, u64 *spte,
-                       unsigned long *pte_list)
+                       struct kvm_rmap_head *rmap_head)
 {
        struct pte_list_desc *desc;
        int i, count = 0;
 
-       if (!*pte_list) {
+       if (!rmap_head->val) {
                rmap_printk("pte_list_add: %p %llx 0->1\n", spte, *spte);
-               *pte_list = (unsigned long)spte;
-       } else if (!(*pte_list & 1)) {
+               rmap_head->val = (unsigned long)spte;
+       } else if (!(rmap_head->val & 1)) {
                rmap_printk("pte_list_add: %p %llx 1->many\n", spte, *spte);
                desc = mmu_alloc_pte_list_desc(vcpu);
-               desc->sptes[0] = (u64 *)*pte_list;
+               desc->sptes[0] = (u64 *)rmap_head->val;
                desc->sptes[1] = spte;
-               *pte_list = (unsigned long)desc | 1;
+               rmap_head->val = (unsigned long)desc | 1;
                ++count;
        } else {
                rmap_printk("pte_list_add: %p %llx many->many\n", spte, *spte);
-               desc = (struct pte_list_desc *)(*pte_list & ~1ul);
+               desc = (struct pte_list_desc *)(rmap_head->val & ~1ul);
                while (desc->sptes[PTE_LIST_EXT-1] && desc->more) {
                        desc = desc->more;
                        count += PTE_LIST_EXT;
@@ -955,8 +949,9 @@ static int pte_list_add(struct kvm_vcpu *vcpu, u64 *spte,
 }
 
 static void
-pte_list_desc_remove_entry(unsigned long *pte_list, struct pte_list_desc *desc,
-                          int i, struct pte_list_desc *prev_desc)
+pte_list_desc_remove_entry(struct kvm_rmap_head *rmap_head,
+                          struct pte_list_desc *desc, int i,
+                          struct pte_list_desc *prev_desc)
 {
        int j;
 
@@ -967,43 +962,43 @@ pte_list_desc_remove_entry(unsigned long *pte_list, struct pte_list_desc *desc,
        if (j != 0)
                return;
        if (!prev_desc && !desc->more)
-               *pte_list = (unsigned long)desc->sptes[0];
+               rmap_head->val = (unsigned long)desc->sptes[0];
        else
                if (prev_desc)
                        prev_desc->more = desc->more;
                else
-                       *pte_list = (unsigned long)desc->more | 1;
+                       rmap_head->val = (unsigned long)desc->more | 1;
        mmu_free_pte_list_desc(desc);
 }
 
-static void pte_list_remove(u64 *spte, unsigned long *pte_list)
+static void pte_list_remove(u64 *spte, struct kvm_rmap_head *rmap_head)
 {
        struct pte_list_desc *desc;
        struct pte_list_desc *prev_desc;
        int i;
 
-       if (!*pte_list) {
+       if (!rmap_head->val) {
                printk(KERN_ERR "pte_list_remove: %p 0->BUG\n", spte);
                BUG();
-       } else if (!(*pte_list & 1)) {
+       } else if (!(rmap_head->val & 1)) {
                rmap_printk("pte_list_remove:  %p 1->0\n", spte);
-               if ((u64 *)*pte_list != spte) {
+               if ((u64 *)rmap_head->val != spte) {
                        printk(KERN_ERR "pte_list_remove:  %p 1->BUG\n", spte);
                        BUG();
                }
-               *pte_list = 0;
+               rmap_head->val = 0;
        } else {
                rmap_printk("pte_list_remove:  %p many->many\n", spte);
-               desc = (struct pte_list_desc *)(*pte_list & ~1ul);
+               desc = (struct pte_list_desc *)(rmap_head->val & ~1ul);
                prev_desc = NULL;
                while (desc) {
-                       for (i = 0; i < PTE_LIST_EXT && desc->sptes[i]; ++i)
+                       for (i = 0; i < PTE_LIST_EXT && desc->sptes[i]; ++i) {
                                if (desc->sptes[i] == spte) {
-                                       pte_list_desc_remove_entry(pte_list,
-                                                              desc, i,
-                                                              prev_desc);
+                                       pte_list_desc_remove_entry(rmap_head,
+                                                       desc, i, prev_desc);
                                        return;
                                }
+                       }
                        prev_desc = desc;
                        desc = desc->more;
                }
@@ -1012,28 +1007,8 @@ static void pte_list_remove(u64 *spte, unsigned long *pte_list)
        }
 }
 
-typedef void (*pte_list_walk_fn) (u64 *spte);
-static void pte_list_walk(unsigned long *pte_list, pte_list_walk_fn fn)
-{
-       struct pte_list_desc *desc;
-       int i;
-
-       if (!*pte_list)
-               return;
-
-       if (!(*pte_list & 1))
-               return fn((u64 *)*pte_list);
-
-       desc = (struct pte_list_desc *)(*pte_list & ~1ul);
-       while (desc) {
-               for (i = 0; i < PTE_LIST_EXT && desc->sptes[i]; ++i)
-                       fn(desc->sptes[i]);
-               desc = desc->more;
-       }
-}
-
-static unsigned long *__gfn_to_rmap(gfn_t gfn, int level,
-                                   struct kvm_memory_slot *slot)
+static struct kvm_rmap_head *__gfn_to_rmap(gfn_t gfn, int level,
+                                          struct kvm_memory_slot *slot)
 {
        unsigned long idx;
 
@@ -1041,10 +1016,8 @@ static unsigned long *__gfn_to_rmap(gfn_t gfn, int level,
        return &slot->arch.rmap[level - PT_PAGE_TABLE_LEVEL][idx];
 }
 
-/*
- * Take gfn and return the reverse mapping to it.
- */
-static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn, struct kvm_mmu_page *sp)
+static struct kvm_rmap_head *gfn_to_rmap(struct kvm *kvm, gfn_t gfn,
+                                        struct kvm_mmu_page *sp)
 {
        struct kvm_memslots *slots;
        struct kvm_memory_slot *slot;
@@ -1065,24 +1038,24 @@ static bool rmap_can_add(struct kvm_vcpu *vcpu)
 static int rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
 {
        struct kvm_mmu_page *sp;
-       unsigned long *rmapp;
+       struct kvm_rmap_head *rmap_head;
 
        sp = page_header(__pa(spte));
        kvm_mmu_page_set_gfn(sp, spte - sp->spt, gfn);
-       rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp);
-       return pte_list_add(vcpu, spte, rmapp);
+       rmap_head = gfn_to_rmap(vcpu->kvm, gfn, sp);
+       return pte_list_add(vcpu, spte, rmap_head);
 }
 
 static void rmap_remove(struct kvm *kvm, u64 *spte)
 {
        struct kvm_mmu_page *sp;
        gfn_t gfn;
-       unsigned long *rmapp;
+       struct kvm_rmap_head *rmap_head;
 
        sp = page_header(__pa(spte));
        gfn = kvm_mmu_page_get_gfn(sp, spte - sp->spt);
-       rmapp = gfn_to_rmap(kvm, gfn, sp);
-       pte_list_remove(spte, rmapp);
+       rmap_head = gfn_to_rmap(kvm, gfn, sp);
+       pte_list_remove(spte, rmap_head);
 }
 
 /*
@@ -1102,19 +1075,26 @@ struct rmap_iterator {
  *
  * Returns sptep if found, NULL otherwise.
  */
-static u64 *rmap_get_first(unsigned long rmap, struct rmap_iterator *iter)
+static u64 *rmap_get_first(struct kvm_rmap_head *rmap_head,
+                          struct rmap_iterator *iter)
 {
-       if (!rmap)
+       u64 *sptep;
+
+       if (!rmap_head->val)
                return NULL;
 
-       if (!(rmap & 1)) {
+       if (!(rmap_head->val & 1)) {
                iter->desc = NULL;
-               return (u64 *)rmap;
+               sptep = (u64 *)rmap_head->val;
+               goto out;
        }
 
-       iter->desc = (struct pte_list_desc *)(rmap & ~1ul);
+       iter->desc = (struct pte_list_desc *)(rmap_head->val & ~1ul);
        iter->pos = 0;
-       return iter->desc->sptes[iter->pos];
+       sptep = iter->desc->sptes[iter->pos];
+out:
+       BUG_ON(!is_shadow_present_pte(*sptep));
+       return sptep;
 }
 
 /*
@@ -1124,14 +1104,14 @@ static u64 *rmap_get_first(unsigned long rmap, struct rmap_iterator *iter)
  */
 static u64 *rmap_get_next(struct rmap_iterator *iter)
 {
+       u64 *sptep;
+
        if (iter->desc) {
                if (iter->pos < PTE_LIST_EXT - 1) {
-                       u64 *sptep;
-
                        ++iter->pos;
                        sptep = iter->desc->sptes[iter->pos];
                        if (sptep)
-                               return sptep;
+                               goto out;
                }
 
                iter->desc = iter->desc->more;
@@ -1139,17 +1119,20 @@ static u64 *rmap_get_next(struct rmap_iterator *iter)
                if (iter->desc) {
                        iter->pos = 0;
                        /* desc->sptes[0] cannot be NULL */
-                       return iter->desc->sptes[iter->pos];
+                       sptep = iter->desc->sptes[iter->pos];
+                       goto out;
                }
        }
 
        return NULL;
+out:
+       BUG_ON(!is_shadow_present_pte(*sptep));
+       return sptep;
 }
 
-#define for_each_rmap_spte(_rmap_, _iter_, _spte_)                         \
-          for (_spte_ = rmap_get_first(*_rmap_, _iter_);                   \
-               _spte_ && ({BUG_ON(!is_shadow_present_pte(*_spte_)); 1;});  \
-                       _spte_ = rmap_get_next(_iter_))
+#define for_each_rmap_spte(_rmap_head_, _iter_, _spte_)                        \
+       for (_spte_ = rmap_get_first(_rmap_head_, _iter_);              \
+            _spte_; _spte_ = rmap_get_next(_iter_))
 
 static void drop_spte(struct kvm *kvm, u64 *sptep)
 {
@@ -1207,14 +1190,15 @@ static bool spte_write_protect(struct kvm *kvm, u64 *sptep, bool pt_protect)
        return mmu_spte_update(sptep, spte);
 }
 
-static bool __rmap_write_protect(struct kvm *kvm, unsigned long *rmapp,
+static bool __rmap_write_protect(struct kvm *kvm,
+                                struct kvm_rmap_head *rmap_head,
                                 bool pt_protect)
 {
        u64 *sptep;
        struct rmap_iterator iter;
        bool flush = false;
 
-       for_each_rmap_spte(rmapp, &iter, sptep)
+       for_each_rmap_spte(rmap_head, &iter, sptep)
                flush |= spte_write_protect(kvm, sptep, pt_protect);
 
        return flush;
@@ -1231,13 +1215,13 @@ static bool spte_clear_dirty(struct kvm *kvm, u64 *sptep)
        return mmu_spte_update(sptep, spte);
 }
 
-static bool __rmap_clear_dirty(struct kvm *kvm, unsigned long *rmapp)
+static bool __rmap_clear_dirty(struct kvm *kvm, struct kvm_rmap_head *rmap_head)
 {
        u64 *sptep;
        struct rmap_iterator iter;
        bool flush = false;
 
-       for_each_rmap_spte(rmapp, &iter, sptep)
+       for_each_rmap_spte(rmap_head, &iter, sptep)
                flush |= spte_clear_dirty(kvm, sptep);
 
        return flush;
@@ -1254,13 +1238,13 @@ static bool spte_set_dirty(struct kvm *kvm, u64 *sptep)
        return mmu_spte_update(sptep, spte);
 }
 
-static bool __rmap_set_dirty(struct kvm *kvm, unsigned long *rmapp)
+static bool __rmap_set_dirty(struct kvm *kvm, struct kvm_rmap_head *rmap_head)
 {
        u64 *sptep;
        struct rmap_iterator iter;
        bool flush = false;
 
-       for_each_rmap_spte(rmapp, &iter, sptep)
+       for_each_rmap_spte(rmap_head, &iter, sptep)
                flush |= spte_set_dirty(kvm, sptep);
 
        return flush;
@@ -1280,12 +1264,12 @@ static void kvm_mmu_write_protect_pt_masked(struct kvm *kvm,
                                     struct kvm_memory_slot *slot,
                                     gfn_t gfn_offset, unsigned long mask)
 {
-       unsigned long *rmapp;
+       struct kvm_rmap_head *rmap_head;
 
        while (mask) {
-               rmapp = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask),
-                                     PT_PAGE_TABLE_LEVEL, slot);
-               __rmap_write_protect(kvm, rmapp, false);
+               rmap_head = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask),
+                                         PT_PAGE_TABLE_LEVEL, slot);
+               __rmap_write_protect(kvm, rmap_head, false);
 
                /* clear the first set bit */
                mask &= mask - 1;
@@ -1305,12 +1289,12 @@ void kvm_mmu_clear_dirty_pt_masked(struct kvm *kvm,
                                     struct kvm_memory_slot *slot,
                                     gfn_t gfn_offset, unsigned long mask)
 {
-       unsigned long *rmapp;
+       struct kvm_rmap_head *rmap_head;
 
        while (mask) {
-               rmapp = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask),
-                                     PT_PAGE_TABLE_LEVEL, slot);
-               __rmap_clear_dirty(kvm, rmapp);
+               rmap_head = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask),
+                                         PT_PAGE_TABLE_LEVEL, slot);
+               __rmap_clear_dirty(kvm, rmap_head);
 
                /* clear the first set bit */
                mask &= mask - 1;
@@ -1342,28 +1326,27 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
 static bool rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn)
 {
        struct kvm_memory_slot *slot;
-       unsigned long *rmapp;
+       struct kvm_rmap_head *rmap_head;
        int i;
        bool write_protected = false;
 
        slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn);
 
        for (i = PT_PAGE_TABLE_LEVEL; i <= PT_MAX_HUGEPAGE_LEVEL; ++i) {
-               rmapp = __gfn_to_rmap(gfn, i, slot);
-               write_protected |= __rmap_write_protect(vcpu->kvm, rmapp, true);
+               rmap_head = __gfn_to_rmap(gfn, i, slot);
+               write_protected |= __rmap_write_protect(vcpu->kvm, rmap_head, true);
        }
 
        return write_protected;
 }
 
-static bool kvm_zap_rmapp(struct kvm *kvm, unsigned long *rmapp)
+static bool kvm_zap_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head)
 {
        u64 *sptep;
        struct rmap_iterator iter;
        bool flush = false;
 
-       while ((sptep = rmap_get_first(*rmapp, &iter))) {
-               BUG_ON(!(*sptep & PT_PRESENT_MASK));
+       while ((sptep = rmap_get_first(rmap_head, &iter))) {
                rmap_printk("%s: spte %p %llx.\n", __func__, sptep, *sptep);
 
                drop_spte(kvm, sptep);
@@ -1373,14 +1356,14 @@ static bool kvm_zap_rmapp(struct kvm *kvm, unsigned long *rmapp)
        return flush;
 }
 
-static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
+static int kvm_unmap_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
                           struct kvm_memory_slot *slot, gfn_t gfn, int level,
                           unsigned long data)
 {
-       return kvm_zap_rmapp(kvm, rmapp);
+       return kvm_zap_rmapp(kvm, rmap_head);
 }
 
-static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp,
+static int kvm_set_pte_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
                             struct kvm_memory_slot *slot, gfn_t gfn, int level,
                             unsigned long data)
 {
@@ -1395,7 +1378,7 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp,
        new_pfn = pte_pfn(*ptep);
 
 restart:
-       for_each_rmap_spte(rmapp, &iter, sptep) {
+       for_each_rmap_spte(rmap_head, &iter, sptep) {
                rmap_printk("kvm_set_pte_rmapp: spte %p %llx gfn %llx (%d)\n",
                             sptep, *sptep, gfn, level);
 
@@ -1433,11 +1416,11 @@ struct slot_rmap_walk_iterator {
 
        /* output fields. */
        gfn_t gfn;
-       unsigned long *rmap;
+       struct kvm_rmap_head *rmap;
        int level;
 
        /* private field. */
-       unsigned long *end_rmap;
+       struct kvm_rmap_head *end_rmap;
 };
 
 static void
@@ -1496,7 +1479,7 @@ static int kvm_handle_hva_range(struct kvm *kvm,
                                unsigned long end,
                                unsigned long data,
                                int (*handler)(struct kvm *kvm,
-                                              unsigned long *rmapp,
+                                              struct kvm_rmap_head *rmap_head,
                                               struct kvm_memory_slot *slot,
                                               gfn_t gfn,
                                               int level,
@@ -1540,7 +1523,8 @@ static int kvm_handle_hva_range(struct kvm *kvm,
 
 static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
                          unsigned long data,
-                         int (*handler)(struct kvm *kvm, unsigned long *rmapp,
+                         int (*handler)(struct kvm *kvm,
+                                        struct kvm_rmap_head *rmap_head,
                                         struct kvm_memory_slot *slot,
                                         gfn_t gfn, int level,
                                         unsigned long data))
@@ -1563,7 +1547,7 @@ void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
        kvm_handle_hva(kvm, hva, (unsigned long)&pte, kvm_set_pte_rmapp);
 }
 
-static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
+static int kvm_age_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
                         struct kvm_memory_slot *slot, gfn_t gfn, int level,
                         unsigned long data)
 {
@@ -1573,18 +1557,19 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
 
        BUG_ON(!shadow_accessed_mask);
 
-       for_each_rmap_spte(rmapp, &iter, sptep)
+       for_each_rmap_spte(rmap_head, &iter, sptep) {
                if (*sptep & shadow_accessed_mask) {
                        young = 1;
                        clear_bit((ffs(shadow_accessed_mask) - 1),
                                 (unsigned long *)sptep);
                }
+       }
 
        trace_kvm_age_page(gfn, level, slot, young);
        return young;
 }
 
-static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
+static int kvm_test_age_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
                              struct kvm_memory_slot *slot, gfn_t gfn,
                              int level, unsigned long data)
 {
@@ -1600,11 +1585,12 @@ static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
        if (!shadow_accessed_mask)
                goto out;
 
-       for_each_rmap_spte(rmapp, &iter, sptep)
+       for_each_rmap_spte(rmap_head, &iter, sptep) {
                if (*sptep & shadow_accessed_mask) {
                        young = 1;
                        break;
                }
+       }
 out:
        return young;
 }
@@ -1613,14 +1599,14 @@ out:
 
 static void rmap_recycle(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
 {
-       unsigned long *rmapp;
+       struct kvm_rmap_head *rmap_head;
        struct kvm_mmu_page *sp;
 
        sp = page_header(__pa(spte));
 
-       rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp);
+       rmap_head = gfn_to_rmap(vcpu->kvm, gfn, sp);
 
-       kvm_unmap_rmapp(vcpu->kvm, rmapp, NULL, gfn, sp->role.level, 0);
+       kvm_unmap_rmapp(vcpu->kvm, rmap_head, NULL, gfn, sp->role.level, 0);
        kvm_flush_remote_tlbs(vcpu->kvm);
 }
 
@@ -1720,8 +1706,7 @@ static void drop_parent_pte(struct kvm_mmu_page *sp,
        mmu_spte_clear_no_track(parent_pte);
 }
 
-static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
-                                              u64 *parent_pte, int direct)
+static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, int direct)
 {
        struct kvm_mmu_page *sp;
 
@@ -1737,8 +1722,6 @@ static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
         * this feature. See the comments in kvm_zap_obsolete_pages().
         */
        list_add(&sp->link, &vcpu->kvm->arch.active_mmu_pages);
-       sp->parent_ptes = 0;
-       mmu_page_add_parent_pte(vcpu, sp, parent_pte);
        kvm_mod_used_mmu_pages(vcpu->kvm, +1);
        return sp;
 }
@@ -1746,7 +1729,12 @@ static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
 static void mark_unsync(u64 *spte);
 static void kvm_mmu_mark_parents_unsync(struct kvm_mmu_page *sp)
 {
-       pte_list_walk(&sp->parent_ptes, mark_unsync);
+       u64 *sptep;
+       struct rmap_iterator iter;
+
+       for_each_rmap_spte(&sp->parent_ptes, &iter, sptep) {
+               mark_unsync(sptep);
+       }
 }
 
 static void mark_unsync(u64 *spte)
@@ -1806,6 +1794,13 @@ static int mmu_pages_add(struct kvm_mmu_pages *pvec, struct kvm_mmu_page *sp,
        return (pvec->nr == KVM_PAGE_ARRAY_NR);
 }
 
+static inline void clear_unsync_child_bit(struct kvm_mmu_page *sp, int idx)
+{
+       --sp->unsync_children;
+       WARN_ON((int)sp->unsync_children < 0);
+       __clear_bit(idx, sp->unsync_child_bitmap);
+}
+
 static int __mmu_unsync_walk(struct kvm_mmu_page *sp,
                           struct kvm_mmu_pages *pvec)
 {
@@ -1815,8 +1810,10 @@ static int __mmu_unsync_walk(struct kvm_mmu_page *sp,
                struct kvm_mmu_page *child;
                u64 ent = sp->spt[i];
 
-               if (!is_shadow_present_pte(ent) || is_large_pte(ent))
-                       goto clear_child_bitmap;
+               if (!is_shadow_present_pte(ent) || is_large_pte(ent)) {
+                       clear_unsync_child_bit(sp, i);
+                       continue;
+               }
 
                child = page_header(ent & PT64_BASE_ADDR_MASK);
 
@@ -1825,28 +1822,21 @@ static int __mmu_unsync_walk(struct kvm_mmu_page *sp,
                                return -ENOSPC;
 
                        ret = __mmu_unsync_walk(child, pvec);
-                       if (!ret)
-                               goto clear_child_bitmap;
-                       else if (ret > 0)
+                       if (!ret) {
+                               clear_unsync_child_bit(sp, i);
+                               continue;
+                       } else if (ret > 0) {
                                nr_unsync_leaf += ret;
-                       else
+                       else
                                return ret;
                } else if (child->unsync) {
                        nr_unsync_leaf++;
                        if (mmu_pages_add(pvec, child, i))
                                return -ENOSPC;
                } else
-                        goto clear_child_bitmap;
-
-               continue;
-
-clear_child_bitmap:
-               __clear_bit(i, sp->unsync_child_bitmap);
-               sp->unsync_children--;
-               WARN_ON((int)sp->unsync_children < 0);
+                       clear_unsync_child_bit(sp, i);
        }
 
-
        return nr_unsync_leaf;
 }
 
@@ -2009,9 +1999,7 @@ static void mmu_pages_clear_parents(struct mmu_page_path *parents)
                if (!sp)
                        return;
 
-               --sp->unsync_children;
-               WARN_ON((int)sp->unsync_children < 0);
-               __clear_bit(idx, sp->unsync_child_bitmap);
+               clear_unsync_child_bit(sp, idx);
                level++;
        } while (level < PT64_ROOT_LEVEL-1 && !sp->unsync_children);
 }
@@ -2053,14 +2041,6 @@ static void mmu_sync_children(struct kvm_vcpu *vcpu,
        }
 }
 
-static void init_shadow_page_table(struct kvm_mmu_page *sp)
-{
-       int i;
-
-       for (i = 0; i < PT64_ENT_PER_PAGE; ++i)
-               sp->spt[i] = 0ull;
-}
-
 static void __clear_sp_write_flooding_count(struct kvm_mmu_page *sp)
 {
        sp->write_flooding_count = 0;
@@ -2083,8 +2063,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
                                             gva_t gaddr,
                                             unsigned level,
                                             int direct,
-                                            unsigned access,
-                                            u64 *parent_pte)
+                                            unsigned access)
 {
        union kvm_mmu_page_role role;
        unsigned quadrant;
@@ -2116,21 +2095,18 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
                if (sp->unsync && kvm_sync_page_transient(vcpu, sp))
                        break;
 
-               mmu_page_add_parent_pte(vcpu, sp, parent_pte);
-               if (sp->unsync_children) {
+               if (sp->unsync_children)
                        kvm_make_request(KVM_REQ_MMU_SYNC, vcpu);
-                       kvm_mmu_mark_parents_unsync(sp);
-               } else if (sp->unsync)
-                       kvm_mmu_mark_parents_unsync(sp);
 
                __clear_sp_write_flooding_count(sp);
                trace_kvm_mmu_get_page(sp, false);
                return sp;
        }
+
        ++vcpu->kvm->stat.mmu_cache_miss;
-       sp = kvm_mmu_alloc_page(vcpu, parent_pte, direct);
-       if (!sp)
-               return sp;
+
+       sp = kvm_mmu_alloc_page(vcpu, direct);
+
        sp->gfn = gfn;
        sp->role = role;
        hlist_add_head(&sp->hash_link,
@@ -2144,7 +2120,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
                account_shadowed(vcpu->kvm, sp);
        }
        sp->mmu_valid_gen = vcpu->kvm->arch.mmu_valid_gen;
-       init_shadow_page_table(sp);
+       clear_page(sp->spt);
        trace_kvm_mmu_get_page(sp, true);
        return sp;
 }
@@ -2198,7 +2174,8 @@ static void shadow_walk_next(struct kvm_shadow_walk_iterator *iterator)
        return __shadow_walk_next(iterator, *iterator->sptep);
 }
 
-static void link_shadow_page(u64 *sptep, struct kvm_mmu_page *sp, bool accessed)
+static void link_shadow_page(struct kvm_vcpu *vcpu, u64 *sptep,
+                            struct kvm_mmu_page *sp)
 {
        u64 spte;
 
@@ -2206,12 +2183,14 @@ static void link_shadow_page(u64 *sptep, struct kvm_mmu_page *sp, bool accessed)
                        VMX_EPT_WRITABLE_MASK != PT_WRITABLE_MASK);
 
        spte = __pa(sp->spt) | PT_PRESENT_MASK | PT_WRITABLE_MASK |
-              shadow_user_mask | shadow_x_mask;
-
-       if (accessed)
-               spte |= shadow_accessed_mask;
+              shadow_user_mask | shadow_x_mask | shadow_accessed_mask;
 
        mmu_spte_set(sptep, spte);
+
+       mmu_page_add_parent_pte(vcpu, sp, sptep);
+
+       if (sp->unsync_children || sp->unsync)
+               mark_unsync(sptep);
 }
 
 static void validate_direct_spte(struct kvm_vcpu *vcpu, u64 *sptep,
@@ -2270,17 +2249,12 @@ static void kvm_mmu_page_unlink_children(struct kvm *kvm,
                mmu_page_zap_pte(kvm, sp, sp->spt + i);
 }
 
-static void kvm_mmu_put_page(struct kvm_mmu_page *sp, u64 *parent_pte)
-{
-       mmu_page_remove_parent_pte(sp, parent_pte);
-}
-
 static void kvm_mmu_unlink_parents(struct kvm *kvm, struct kvm_mmu_page *sp)
 {
        u64 *sptep;
        struct rmap_iterator iter;
 
-       while ((sptep = rmap_get_first(sp->parent_ptes, &iter)))
+       while ((sptep = rmap_get_first(&sp->parent_ptes, &iter)))
                drop_parent_pte(sp, sptep);
 }
 
@@ -2564,18 +2538,18 @@ done:
        return ret;
 }
 
-static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
-                        unsigned pte_access, int write_fault, int *emulate,
-                        int level, gfn_t gfn, pfn_t pfn, bool speculative,
-                        bool host_writable)
+static bool mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, unsigned pte_access,
+                        int write_fault, int level, gfn_t gfn, pfn_t pfn,
+                        bool speculative, bool host_writable)
 {
        int was_rmapped = 0;
        int rmap_count;
+       bool emulate = false;
 
        pgprintk("%s: spte %llx write_fault %d gfn %llx\n", __func__,
                 *sptep, write_fault, gfn);
 
-       if (is_rmap_spte(*sptep)) {
+       if (is_shadow_present_pte(*sptep)) {
                /*
                 * If we overwrite a PTE page pointer with a 2MB PMD, unlink
                 * the parent of the now unreachable PTE.
@@ -2600,12 +2574,12 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
        if (set_spte(vcpu, sptep, pte_access, level, gfn, pfn, speculative,
              true, host_writable)) {
                if (write_fault)
-                       *emulate = 1;
+                       emulate = true;
                kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
        }
 
-       if (unlikely(is_mmio_spte(*sptep) && emulate))
-               *emulate = 1;
+       if (unlikely(is_mmio_spte(*sptep)))
+               emulate = true;
 
        pgprintk("%s: setting spte %llx\n", __func__, *sptep);
        pgprintk("instantiating %s PTE (%s) at %llx (%llx) addr %p\n",
@@ -2624,6 +2598,8 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
        }
 
        kvm_release_pfn_clean(pfn);
+
+       return emulate;
 }
 
 static pfn_t pte_prefetch_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn,
@@ -2658,9 +2634,8 @@ static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu,
                return -1;
 
        for (i = 0; i < ret; i++, gfn++, start++)
-               mmu_set_spte(vcpu, start, access, 0, NULL,
-                            sp->role.level, gfn, page_to_pfn(pages[i]),
-                            true, true);
+               mmu_set_spte(vcpu, start, access, 0, sp->role.level, gfn,
+                            page_to_pfn(pages[i]), true, true);
 
        return 0;
 }
@@ -2708,9 +2683,8 @@ static void direct_pte_prefetch(struct kvm_vcpu *vcpu, u64 *sptep)
        __direct_pte_prefetch(vcpu, sp, sptep);
 }
 
-static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
-                       int map_writable, int level, gfn_t gfn, pfn_t pfn,
-                       bool prefault)
+static int __direct_map(struct kvm_vcpu *vcpu, int write, int map_writable,
+                       int level, gfn_t gfn, pfn_t pfn, bool prefault)
 {
        struct kvm_shadow_walk_iterator iterator;
        struct kvm_mmu_page *sp;
@@ -2722,9 +2696,9 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
 
        for_each_shadow_entry(vcpu, (u64)gfn << PAGE_SHIFT, iterator) {
                if (iterator.level == level) {
-                       mmu_set_spte(vcpu, iterator.sptep, ACC_ALL,
-                                    write, &emulate, level, gfn, pfn,
-                                    prefault, map_writable);
+                       emulate = mmu_set_spte(vcpu, iterator.sptep, ACC_ALL,
+                                              write, level, gfn, pfn, prefault,
+                                              map_writable);
                        direct_pte_prefetch(vcpu, iterator.sptep);
                        ++vcpu->stat.pf_fixed;
                        break;
@@ -2737,10 +2711,9 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
                        base_addr &= PT64_LVL_ADDR_MASK(iterator.level);
                        pseudo_gfn = base_addr >> PAGE_SHIFT;
                        sp = kvm_mmu_get_page(vcpu, pseudo_gfn, iterator.addr,
-                                             iterator.level - 1,
-                                             1, ACC_ALL, iterator.sptep);
+                                             iterator.level - 1, 1, ACC_ALL);
 
-                       link_shadow_page(iterator.sptep, sp, true);
+                       link_shadow_page(vcpu, iterator.sptep, sp);
                }
        }
        return emulate;
@@ -2919,7 +2892,7 @@ static bool fast_page_fault(struct kvm_vcpu *vcpu, gva_t gva, int level,
         * If the mapping has been changed, let the vcpu fault on the
         * same address again.
         */
-       if (!is_rmap_spte(spte)) {
+       if (!is_shadow_present_pte(spte)) {
                ret = true;
                goto exit;
        }
@@ -3018,11 +2991,9 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, u32 error_code,
        make_mmu_pages_available(vcpu);
        if (likely(!force_pt_level))
                transparent_hugepage_adjust(vcpu, &gfn, &pfn, &level);
-       r = __direct_map(vcpu, v, write, map_writable, level, gfn, pfn,
-                        prefault);
+       r = __direct_map(vcpu, write, map_writable, level, gfn, pfn, prefault);
        spin_unlock(&vcpu->kvm->mmu_lock);
 
-
        return r;
 
 out_unlock:
@@ -3097,8 +3068,7 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu)
        if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) {
                spin_lock(&vcpu->kvm->mmu_lock);
                make_mmu_pages_available(vcpu);
-               sp = kvm_mmu_get_page(vcpu, 0, 0, PT64_ROOT_LEVEL,
-                                     1, ACC_ALL, NULL);
+               sp = kvm_mmu_get_page(vcpu, 0, 0, PT64_ROOT_LEVEL, 1, ACC_ALL);
                ++sp->root_count;
                spin_unlock(&vcpu->kvm->mmu_lock);
                vcpu->arch.mmu.root_hpa = __pa(sp->spt);
@@ -3110,9 +3080,7 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu)
                        spin_lock(&vcpu->kvm->mmu_lock);
                        make_mmu_pages_available(vcpu);
                        sp = kvm_mmu_get_page(vcpu, i << (30 - PAGE_SHIFT),
-                                             i << 30,
-                                             PT32_ROOT_LEVEL, 1, ACC_ALL,
-                                             NULL);
+                                       i << 30, PT32_ROOT_LEVEL, 1, ACC_ALL);
                        root = __pa(sp->spt);
                        ++sp->root_count;
                        spin_unlock(&vcpu->kvm->mmu_lock);
@@ -3149,7 +3117,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
                spin_lock(&vcpu->kvm->mmu_lock);
                make_mmu_pages_available(vcpu);
                sp = kvm_mmu_get_page(vcpu, root_gfn, 0, PT64_ROOT_LEVEL,
-                                     0, ACC_ALL, NULL);
+                                     0, ACC_ALL);
                root = __pa(sp->spt);
                ++sp->root_count;
                spin_unlock(&vcpu->kvm->mmu_lock);
@@ -3182,9 +3150,8 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
                }
                spin_lock(&vcpu->kvm->mmu_lock);
                make_mmu_pages_available(vcpu);
-               sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30,
-                                     PT32_ROOT_LEVEL, 0,
-                                     ACC_ALL, NULL);
+               sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30, PT32_ROOT_LEVEL,
+                                     0, ACC_ALL);
                root = __pa(sp->spt);
                ++sp->root_count;
                spin_unlock(&vcpu->kvm->mmu_lock);
@@ -3531,8 +3498,7 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code,
        make_mmu_pages_available(vcpu);
        if (likely(!force_pt_level))
                transparent_hugepage_adjust(vcpu, &gfn, &pfn, &level);
-       r = __direct_map(vcpu, gpa, write, map_writable,
-                        level, gfn, pfn, prefault);
+       r = __direct_map(vcpu, write, map_writable, level, gfn, pfn, prefault);
        spin_unlock(&vcpu->kvm->mmu_lock);
 
        return r;
@@ -4058,10 +4024,12 @@ static void init_kvm_nested_mmu(struct kvm_vcpu *vcpu)
        g_context->inject_page_fault = kvm_inject_page_fault;
 
        /*
-        * Note that arch.mmu.gva_to_gpa translates l2_gva to l1_gpa. The
-        * translation of l2_gpa to l1_gpa addresses is done using the
-        * arch.nested_mmu.gva_to_gpa function. Basically the gva_to_gpa
-        * functions between mmu and nested_mmu are swapped.
+        * Note that arch.mmu.gva_to_gpa translates l2_gpa to l1_gpa using
+        * L1's nested page tables (e.g. EPT12). The nested translation
+        * of l2_gva to l1_gpa is done by arch.nested_mmu.gva_to_gpa using
+        * L2's page tables as the first level of translation and L1's
+        * nested page tables as the second level of translation. Basically
+        * the gva_to_gpa functions between mmu and nested_mmu are swapped.
         */
        if (!is_paging(vcpu)) {
                g_context->nx = false;
@@ -4495,7 +4463,7 @@ void kvm_mmu_setup(struct kvm_vcpu *vcpu)
 }
 
 /* The return value indicates if tlb flush on all vcpus is needed. */
-typedef bool (*slot_level_handler) (struct kvm *kvm, unsigned long *rmap);
+typedef bool (*slot_level_handler) (struct kvm *kvm, struct kvm_rmap_head *rmap_head);
 
 /* The caller should hold mmu-lock before calling this function. */
 static bool
@@ -4589,9 +4557,10 @@ void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end)
        spin_unlock(&kvm->mmu_lock);
 }
 
-static bool slot_rmap_write_protect(struct kvm *kvm, unsigned long *rmapp)
+static bool slot_rmap_write_protect(struct kvm *kvm,
+                                   struct kvm_rmap_head *rmap_head)
 {
-       return __rmap_write_protect(kvm, rmapp, false);
+       return __rmap_write_protect(kvm, rmap_head, false);
 }
 
 void kvm_mmu_slot_remove_write_access(struct kvm *kvm,
@@ -4627,7 +4596,7 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm,
 }
 
 static bool kvm_mmu_zap_collapsible_spte(struct kvm *kvm,
-               unsigned long *rmapp)
+                                        struct kvm_rmap_head *rmap_head)
 {
        u64 *sptep;
        struct rmap_iterator iter;
@@ -4636,7 +4605,7 @@ static bool kvm_mmu_zap_collapsible_spte(struct kvm *kvm,
        struct kvm_mmu_page *sp;
 
 restart:
-       for_each_rmap_spte(rmapp, &iter, sptep) {
+       for_each_rmap_spte(rmap_head, &iter, sptep) {
                sp = page_header(__pa(sptep));
                pfn = spte_to_pfn(*sptep);
 
index 03d518e499a6d5a6184b19ae86b70adfcb3955ba..1cee3ec20dd2be5cf92dff8d34a4e4857477f617 100644 (file)
@@ -129,7 +129,7 @@ static void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level)
 static void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
 {
        static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 10);
-       unsigned long *rmapp;
+       struct kvm_rmap_head *rmap_head;
        struct kvm_mmu_page *rev_sp;
        struct kvm_memslots *slots;
        struct kvm_memory_slot *slot;
@@ -150,8 +150,8 @@ static void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
                return;
        }
 
-       rmapp = __gfn_to_rmap(gfn, rev_sp->role.level, slot);
-       if (!*rmapp) {
+       rmap_head = __gfn_to_rmap(gfn, rev_sp->role.level, slot);
+       if (!rmap_head->val) {
                if (!__ratelimit(&ratelimit_state))
                        return;
                audit_printk(kvm, "no rmap for writable spte %llx\n",
@@ -183,7 +183,7 @@ static void check_mappings_rmap(struct kvm *kvm, struct kvm_mmu_page *sp)
                return;
 
        for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
-               if (!is_rmap_spte(sp->spt[i]))
+               if (!is_shadow_present_pte(sp->spt[i]))
                        continue;
 
                inspect_spte_has_rmap(kvm, sp->spt + i);
@@ -192,7 +192,7 @@ static void check_mappings_rmap(struct kvm *kvm, struct kvm_mmu_page *sp)
 
 static void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp)
 {
-       unsigned long *rmapp;
+       struct kvm_rmap_head *rmap_head;
        u64 *sptep;
        struct rmap_iterator iter;
        struct kvm_memslots *slots;
@@ -203,13 +203,14 @@ static void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp)
 
        slots = kvm_memslots_for_spte_role(kvm, sp->role);
        slot = __gfn_to_memslot(slots, sp->gfn);
-       rmapp = __gfn_to_rmap(sp->gfn, PT_PAGE_TABLE_LEVEL, slot);
+       rmap_head = __gfn_to_rmap(sp->gfn, PT_PAGE_TABLE_LEVEL, slot);
 
-       for_each_rmap_spte(rmapp, &iter, sptep)
+       for_each_rmap_spte(rmap_head, &iter, sptep) {
                if (is_writable_pte(*sptep))
                        audit_printk(kvm, "shadow page has writable "
                                     "mappings: gfn %llx role %x\n",
                                     sp->gfn, sp->role.word);
+       }
 }
 
 static void audit_sp(struct kvm *kvm, struct kvm_mmu_page *sp)
index 3058a22a658d25db2bb8ecf4a37657bc1f873c1d..91e939b486d178bc9f51a1668034add0e38bd096 100644 (file)
@@ -475,8 +475,8 @@ FNAME(prefetch_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
         * we call mmu_set_spte() with host_writable = true because
         * pte_prefetch_gfn_to_pfn always gets a writable pfn.
         */
-       mmu_set_spte(vcpu, spte, pte_access, 0, NULL, PT_PAGE_TABLE_LEVEL,
-                    gfn, pfn, true, true);
+       mmu_set_spte(vcpu, spte, pte_access, 0, PT_PAGE_TABLE_LEVEL, gfn, pfn,
+                    true, true);
 
        return true;
 }
@@ -556,7 +556,7 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
        struct kvm_mmu_page *sp = NULL;
        struct kvm_shadow_walk_iterator it;
        unsigned direct_access, access = gw->pt_access;
-       int top_level, emulate = 0;
+       int top_level, emulate;
 
        direct_access = gw->pte_access;
 
@@ -587,7 +587,7 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
                if (!is_shadow_present_pte(*it.sptep)) {
                        table_gfn = gw->table_gfn[it.level - 2];
                        sp = kvm_mmu_get_page(vcpu, table_gfn, addr, it.level-1,
-                                             false, access, it.sptep);
+                                             false, access);
                }
 
                /*
@@ -598,7 +598,7 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
                        goto out_gpte_changed;
 
                if (sp)
-                       link_shadow_page(it.sptep, sp, PT_GUEST_ACCESSED_MASK);
+                       link_shadow_page(vcpu, it.sptep, sp);
        }
 
        for (;
@@ -617,20 +617,18 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
                direct_gfn = gw->gfn & ~(KVM_PAGES_PER_HPAGE(it.level) - 1);
 
                sp = kvm_mmu_get_page(vcpu, direct_gfn, addr, it.level-1,
-                                     true, direct_access, it.sptep);
-               link_shadow_page(it.sptep, sp, PT_GUEST_ACCESSED_MASK);
+                                     true, direct_access);
+               link_shadow_page(vcpu, it.sptep, sp);
        }
 
        clear_sp_write_flooding_count(it.sptep);
-       mmu_set_spte(vcpu, it.sptep, gw->pte_access, write_fault, &emulate,
-                    it.level, gw->gfn, pfn, prefault, map_writable);
+       emulate = mmu_set_spte(vcpu, it.sptep, gw->pte_access, write_fault,
+                              it.level, gw->gfn, pfn, prefault, map_writable);
        FNAME(pte_prefetch)(vcpu, gw, it.sptep);
 
        return emulate;
 
 out_gpte_changed:
-       if (sp)
-               kvm_mmu_put_page(sp, it.sptep);
        kvm_release_pfn_clean(pfn);
        return 0;
 }
index 899c40f826dd9a5f10c57e0758153cdbb1d9f1a6..c13a64b7d7899a4aab5d7bb72e2b499f40271829 100644 (file)
@@ -86,6 +86,7 @@ static const u32 host_save_user_msrs[] = {
        MSR_FS_BASE,
 #endif
        MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
+       MSR_TSC_AUX,
 };
 
 #define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs)
@@ -135,6 +136,7 @@ struct vcpu_svm {
        uint64_t asid_generation;
        uint64_t sysenter_esp;
        uint64_t sysenter_eip;
+       uint64_t tsc_aux;
 
        u64 next_rip;
 
@@ -1238,6 +1240,9 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
                        wrmsrl(MSR_AMD64_TSC_RATIO, tsc_ratio);
                }
        }
+       /* This assumes that the kernel never uses MSR_TSC_AUX */
+       if (static_cpu_has(X86_FEATURE_RDTSCP))
+               wrmsrl(MSR_TSC_AUX, svm->tsc_aux);
 }
 
 static void svm_vcpu_put(struct kvm_vcpu *vcpu)
@@ -3024,6 +3029,11 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case MSR_IA32_SYSENTER_ESP:
                msr_info->data = svm->sysenter_esp;
                break;
+       case MSR_TSC_AUX:
+               if (!boot_cpu_has(X86_FEATURE_RDTSCP))
+                       return 1;
+               msr_info->data = svm->tsc_aux;
+               break;
        /*
         * Nobody will change the following 5 values in the VMCB so we can
         * safely return them on rdmsr. They will always be 0 until LBRV is
@@ -3053,6 +3063,23 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case MSR_IA32_UCODE_REV:
                msr_info->data = 0x01000065;
                break;
+       case MSR_F15H_IC_CFG: {
+
+               int family, model;
+
+               family = guest_cpuid_family(vcpu);
+               model  = guest_cpuid_model(vcpu);
+
+               if (family < 0 || model < 0)
+                       return kvm_get_msr_common(vcpu, msr_info);
+
+               msr_info->data = 0;
+
+               if (family == 0x15 &&
+                   (model >= 0x2 && model < 0x20))
+                       msr_info->data = 0x1E;
+               }
+               break;
        default:
                return kvm_get_msr_common(vcpu, msr_info);
        }
@@ -3145,6 +3172,18 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
                svm->sysenter_esp = data;
                svm->vmcb->save.sysenter_esp = data;
                break;
+       case MSR_TSC_AUX:
+               if (!boot_cpu_has(X86_FEATURE_RDTSCP))
+                       return 1;
+
+               /*
+                * This is rare, so we update the MSR here instead of using
+                * direct_access_msrs.  Doing that would require a rdmsr in
+                * svm_vcpu_put.
+                */
+               svm->tsc_aux = data;
+               wrmsrl(MSR_TSC_AUX, svm->tsc_aux);
+               break;
        case MSR_IA32_DEBUGCTLMSR:
                if (!boot_cpu_has(X86_FEATURE_LBRV)) {
                        vcpu_unimpl(vcpu, "%s: MSR_IA32_DEBUGCTL 0x%llx, nop\n",
@@ -3561,12 +3600,16 @@ static void svm_set_virtual_x2apic_mode(struct kvm_vcpu *vcpu, bool set)
        return;
 }
 
-static int svm_cpu_uses_apicv(struct kvm_vcpu *vcpu)
+static bool svm_get_enable_apicv(void)
 {
-       return 0;
+       return false;
 }
 
-static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu)
+static void svm_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
+{
+}
+
+static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
 {
        return;
 }
@@ -4037,7 +4080,7 @@ static int svm_get_lpage_level(void)
 
 static bool svm_rdtscp_supported(void)
 {
-       return false;
+       return boot_cpu_has(X86_FEATURE_RDTSCP);
 }
 
 static bool svm_invpcid_supported(void)
@@ -4328,7 +4371,8 @@ static struct kvm_x86_ops svm_x86_ops = {
        .enable_irq_window = enable_irq_window,
        .update_cr8_intercept = update_cr8_intercept,
        .set_virtual_x2apic_mode = svm_set_virtual_x2apic_mode,
-       .cpu_uses_apicv = svm_cpu_uses_apicv,
+       .get_enable_apicv = svm_get_enable_apicv,
+       .refresh_apicv_exec_ctrl = svm_refresh_apicv_exec_ctrl,
        .load_eoi_exitmap = svm_load_eoi_exitmap,
        .sync_pir_to_irr = svm_sync_pir_to_irr,
 
index 120302511802ad3afa7175dfa8b61e9d9104a1fc..ad9f6a23f13961feca86340c9cda300608da8b8e 100644 (file)
@@ -268,7 +268,7 @@ TRACE_EVENT(kvm_inj_virq,
 #define kvm_trace_sym_exc                                              \
        EXS(DE), EXS(DB), EXS(BP), EXS(OF), EXS(BR), EXS(UD), EXS(NM),  \
        EXS(DF), EXS(TS), EXS(NP), EXS(SS), EXS(GP), EXS(PF),           \
-       EXS(MF), EXS(MC)
+       EXS(MF), EXS(AC), EXS(MC)
 
 /*
  * Tracepoint for kvm interrupt injection:
@@ -1025,6 +1025,269 @@ TRACE_EVENT(kvm_pi_irte_update,
                  __entry->pi_desc_addr)
 );
 
+/*
+ * Tracepoint for kvm_hv_notify_acked_sint.
+ */
+TRACE_EVENT(kvm_hv_notify_acked_sint,
+       TP_PROTO(int vcpu_id, u32 sint),
+       TP_ARGS(vcpu_id, sint),
+
+       TP_STRUCT__entry(
+               __field(int, vcpu_id)
+               __field(u32, sint)
+       ),
+
+       TP_fast_assign(
+               __entry->vcpu_id = vcpu_id;
+               __entry->sint = sint;
+       ),
+
+       TP_printk("vcpu_id %d sint %u", __entry->vcpu_id, __entry->sint)
+);
+
+/*
+ * Tracepoint for synic_set_irq.
+ */
+TRACE_EVENT(kvm_hv_synic_set_irq,
+       TP_PROTO(int vcpu_id, u32 sint, int vector, int ret),
+       TP_ARGS(vcpu_id, sint, vector, ret),
+
+       TP_STRUCT__entry(
+               __field(int, vcpu_id)
+               __field(u32, sint)
+               __field(int, vector)
+               __field(int, ret)
+       ),
+
+       TP_fast_assign(
+               __entry->vcpu_id = vcpu_id;
+               __entry->sint = sint;
+               __entry->vector = vector;
+               __entry->ret = ret;
+       ),
+
+       TP_printk("vcpu_id %d sint %u vector %d ret %d",
+                 __entry->vcpu_id, __entry->sint, __entry->vector,
+                 __entry->ret)
+);
+
+/*
+ * Tracepoint for kvm_hv_synic_send_eoi.
+ */
+TRACE_EVENT(kvm_hv_synic_send_eoi,
+       TP_PROTO(int vcpu_id, int vector),
+       TP_ARGS(vcpu_id, vector),
+
+       TP_STRUCT__entry(
+               __field(int, vcpu_id)
+               __field(u32, sint)
+               __field(int, vector)
+               __field(int, ret)
+       ),
+
+       TP_fast_assign(
+               __entry->vcpu_id = vcpu_id;
+               __entry->vector = vector;
+       ),
+
+       TP_printk("vcpu_id %d vector %d", __entry->vcpu_id, __entry->vector)
+);
+
+/*
+ * Tracepoint for synic_set_msr.
+ */
+TRACE_EVENT(kvm_hv_synic_set_msr,
+       TP_PROTO(int vcpu_id, u32 msr, u64 data, bool host),
+       TP_ARGS(vcpu_id, msr, data, host),
+
+       TP_STRUCT__entry(
+               __field(int, vcpu_id)
+               __field(u32, msr)
+               __field(u64, data)
+               __field(bool, host)
+       ),
+
+       TP_fast_assign(
+               __entry->vcpu_id = vcpu_id;
+               __entry->msr = msr;
+               __entry->data = data;
+               __entry->host = host
+       ),
+
+       TP_printk("vcpu_id %d msr 0x%x data 0x%llx host %d",
+                 __entry->vcpu_id, __entry->msr, __entry->data, __entry->host)
+);
+
+/*
+ * Tracepoint for stimer_set_config.
+ */
+TRACE_EVENT(kvm_hv_stimer_set_config,
+       TP_PROTO(int vcpu_id, int timer_index, u64 config, bool host),
+       TP_ARGS(vcpu_id, timer_index, config, host),
+
+       TP_STRUCT__entry(
+               __field(int, vcpu_id)
+               __field(int, timer_index)
+               __field(u64, config)
+               __field(bool, host)
+       ),
+
+       TP_fast_assign(
+               __entry->vcpu_id = vcpu_id;
+               __entry->timer_index = timer_index;
+               __entry->config = config;
+               __entry->host = host;
+       ),
+
+       TP_printk("vcpu_id %d timer %d config 0x%llx host %d",
+                 __entry->vcpu_id, __entry->timer_index, __entry->config,
+                 __entry->host)
+);
+
+/*
+ * Tracepoint for stimer_set_count.
+ */
+TRACE_EVENT(kvm_hv_stimer_set_count,
+       TP_PROTO(int vcpu_id, int timer_index, u64 count, bool host),
+       TP_ARGS(vcpu_id, timer_index, count, host),
+
+       TP_STRUCT__entry(
+               __field(int, vcpu_id)
+               __field(int, timer_index)
+               __field(u64, count)
+               __field(bool, host)
+       ),
+
+       TP_fast_assign(
+               __entry->vcpu_id = vcpu_id;
+               __entry->timer_index = timer_index;
+               __entry->count = count;
+               __entry->host = host;
+       ),
+
+       TP_printk("vcpu_id %d timer %d count %llu host %d",
+                 __entry->vcpu_id, __entry->timer_index, __entry->count,
+                 __entry->host)
+);
+
+/*
+ * Tracepoint for stimer_start(periodic timer case).
+ */
+TRACE_EVENT(kvm_hv_stimer_start_periodic,
+       TP_PROTO(int vcpu_id, int timer_index, u64 time_now, u64 exp_time),
+       TP_ARGS(vcpu_id, timer_index, time_now, exp_time),
+
+       TP_STRUCT__entry(
+               __field(int, vcpu_id)
+               __field(int, timer_index)
+               __field(u64, time_now)
+               __field(u64, exp_time)
+       ),
+
+       TP_fast_assign(
+               __entry->vcpu_id = vcpu_id;
+               __entry->timer_index = timer_index;
+               __entry->time_now = time_now;
+               __entry->exp_time = exp_time;
+       ),
+
+       TP_printk("vcpu_id %d timer %d time_now %llu exp_time %llu",
+                 __entry->vcpu_id, __entry->timer_index, __entry->time_now,
+                 __entry->exp_time)
+);
+
+/*
+ * Tracepoint for stimer_start(one-shot timer case).
+ */
+TRACE_EVENT(kvm_hv_stimer_start_one_shot,
+       TP_PROTO(int vcpu_id, int timer_index, u64 time_now, u64 count),
+       TP_ARGS(vcpu_id, timer_index, time_now, count),
+
+       TP_STRUCT__entry(
+               __field(int, vcpu_id)
+               __field(int, timer_index)
+               __field(u64, time_now)
+               __field(u64, count)
+       ),
+
+       TP_fast_assign(
+               __entry->vcpu_id = vcpu_id;
+               __entry->timer_index = timer_index;
+               __entry->time_now = time_now;
+               __entry->count = count;
+       ),
+
+       TP_printk("vcpu_id %d timer %d time_now %llu count %llu",
+                 __entry->vcpu_id, __entry->timer_index, __entry->time_now,
+                 __entry->count)
+);
+
+/*
+ * Tracepoint for stimer_timer_callback.
+ */
+TRACE_EVENT(kvm_hv_stimer_callback,
+       TP_PROTO(int vcpu_id, int timer_index),
+       TP_ARGS(vcpu_id, timer_index),
+
+       TP_STRUCT__entry(
+               __field(int, vcpu_id)
+               __field(int, timer_index)
+       ),
+
+       TP_fast_assign(
+               __entry->vcpu_id = vcpu_id;
+               __entry->timer_index = timer_index;
+       ),
+
+       TP_printk("vcpu_id %d timer %d",
+                 __entry->vcpu_id, __entry->timer_index)
+);
+
+/*
+ * Tracepoint for stimer_expiration.
+ */
+TRACE_EVENT(kvm_hv_stimer_expiration,
+       TP_PROTO(int vcpu_id, int timer_index, int msg_send_result),
+       TP_ARGS(vcpu_id, timer_index, msg_send_result),
+
+       TP_STRUCT__entry(
+               __field(int, vcpu_id)
+               __field(int, timer_index)
+               __field(int, msg_send_result)
+       ),
+
+       TP_fast_assign(
+               __entry->vcpu_id = vcpu_id;
+               __entry->timer_index = timer_index;
+               __entry->msg_send_result = msg_send_result;
+       ),
+
+       TP_printk("vcpu_id %d timer %d msg send result %d",
+                 __entry->vcpu_id, __entry->timer_index,
+                 __entry->msg_send_result)
+);
+
+/*
+ * Tracepoint for stimer_cleanup.
+ */
+TRACE_EVENT(kvm_hv_stimer_cleanup,
+       TP_PROTO(int vcpu_id, int timer_index),
+       TP_ARGS(vcpu_id, timer_index),
+
+       TP_STRUCT__entry(
+               __field(int, vcpu_id)
+               __field(int, timer_index)
+       ),
+
+       TP_fast_assign(
+               __entry->vcpu_id = vcpu_id;
+               __entry->timer_index = timer_index;
+       ),
+
+       TP_printk("vcpu_id %d timer %d",
+                 __entry->vcpu_id, __entry->timer_index)
+);
+
 #endif /* _TRACE_KVM_H */
 
 #undef TRACE_INCLUDE_PATH
index 44976a596fa65d2ca90421a7f7f06cfb2d0b17be..04d61d496b14e36cef0c8818cce52fe36b6597db 100644 (file)
@@ -19,6 +19,7 @@
 #include "irq.h"
 #include "mmu.h"
 #include "cpuid.h"
+#include "lapic.h"
 
 #include <linux/kvm_host.h>
 #include <linux/module.h>
@@ -862,7 +863,6 @@ static void kvm_cpu_vmxon(u64 addr);
 static void kvm_cpu_vmxoff(void);
 static bool vmx_mpx_supported(void);
 static bool vmx_xsaves_supported(void);
-static int vmx_cpu_uses_apicv(struct kvm_vcpu *vcpu);
 static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr);
 static void vmx_set_segment(struct kvm_vcpu *vcpu,
                            struct kvm_segment *var, int seg);
@@ -870,7 +870,6 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu,
                            struct kvm_segment *var, int seg);
 static bool guest_state_valid(struct kvm_vcpu *vcpu);
 static u32 vmx_segment_access_rights(struct kvm_segment *var);
-static void vmx_sync_pir_to_irr_dummy(struct kvm_vcpu *vcpu);
 static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx);
 static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx);
 static int alloc_identity_pagetable(struct kvm *kvm);
@@ -1448,7 +1447,51 @@ static inline void ept_sync_context(u64 eptp)
        }
 }
 
-static __always_inline unsigned long vmcs_readl(unsigned long field)
+static __always_inline void vmcs_check16(unsigned long field)
+{
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2000,
+                        "16-bit accessor invalid for 64-bit field");
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2001,
+                        "16-bit accessor invalid for 64-bit high field");
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x4000,
+                        "16-bit accessor invalid for 32-bit high field");
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x6000,
+                        "16-bit accessor invalid for natural width field");
+}
+
+static __always_inline void vmcs_check32(unsigned long field)
+{
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0,
+                        "32-bit accessor invalid for 16-bit field");
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x6000,
+                        "32-bit accessor invalid for natural width field");
+}
+
+static __always_inline void vmcs_check64(unsigned long field)
+{
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0,
+                        "64-bit accessor invalid for 16-bit field");
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2001,
+                        "64-bit accessor invalid for 64-bit high field");
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x4000,
+                        "64-bit accessor invalid for 32-bit field");
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x6000,
+                        "64-bit accessor invalid for natural width field");
+}
+
+static __always_inline void vmcs_checkl(unsigned long field)
+{
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0,
+                        "Natural width accessor invalid for 16-bit field");
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2000,
+                        "Natural width accessor invalid for 64-bit field");
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2001,
+                        "Natural width accessor invalid for 64-bit high field");
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x4000,
+                        "Natural width accessor invalid for 32-bit field");
+}
+
+static __always_inline unsigned long __vmcs_readl(unsigned long field)
 {
        unsigned long value;
 
@@ -1459,23 +1502,32 @@ static __always_inline unsigned long vmcs_readl(unsigned long field)
 
 static __always_inline u16 vmcs_read16(unsigned long field)
 {
-       return vmcs_readl(field);
+       vmcs_check16(field);
+       return __vmcs_readl(field);
 }
 
 static __always_inline u32 vmcs_read32(unsigned long field)
 {
-       return vmcs_readl(field);
+       vmcs_check32(field);
+       return __vmcs_readl(field);
 }
 
 static __always_inline u64 vmcs_read64(unsigned long field)
 {
+       vmcs_check64(field);
 #ifdef CONFIG_X86_64
-       return vmcs_readl(field);
+       return __vmcs_readl(field);
 #else
-       return vmcs_readl(field) | ((u64)vmcs_readl(field+1) << 32);
+       return __vmcs_readl(field) | ((u64)__vmcs_readl(field+1) << 32);
 #endif
 }
 
+static __always_inline unsigned long vmcs_readl(unsigned long field)
+{
+       vmcs_checkl(field);
+       return __vmcs_readl(field);
+}
+
 static noinline void vmwrite_error(unsigned long field, unsigned long value)
 {
        printk(KERN_ERR "vmwrite error: reg %lx value %lx (err %d)\n",
@@ -1483,7 +1535,7 @@ static noinline void vmwrite_error(unsigned long field, unsigned long value)
        dump_stack();
 }
 
-static void vmcs_writel(unsigned long field, unsigned long value)
+static __always_inline void __vmcs_writel(unsigned long field, unsigned long value)
 {
        u8 error;
 
@@ -1493,33 +1545,46 @@ static void vmcs_writel(unsigned long field, unsigned long value)
                vmwrite_error(field, value);
 }
 
-static void vmcs_write16(unsigned long field, u16 value)
+static __always_inline void vmcs_write16(unsigned long field, u16 value)
 {
-       vmcs_writel(field, value);
+       vmcs_check16(field);
+       __vmcs_writel(field, value);
 }
 
-static void vmcs_write32(unsigned long field, u32 value)
+static __always_inline void vmcs_write32(unsigned long field, u32 value)
 {
-       vmcs_writel(field, value);
+       vmcs_check32(field);
+       __vmcs_writel(field, value);
 }
 
-static void vmcs_write64(unsigned long field, u64 value)
+static __always_inline void vmcs_write64(unsigned long field, u64 value)
 {
-       vmcs_writel(field, value);
+       vmcs_check64(field);
+       __vmcs_writel(field, value);
 #ifndef CONFIG_X86_64
        asm volatile ("");
-       vmcs_writel(field+1, value >> 32);
+       __vmcs_writel(field+1, value >> 32);
 #endif
 }
 
-static void vmcs_clear_bits(unsigned long field, u32 mask)
+static __always_inline void vmcs_writel(unsigned long field, unsigned long value)
 {
-       vmcs_writel(field, vmcs_readl(field) & ~mask);
+       vmcs_checkl(field);
+       __vmcs_writel(field, value);
 }
 
-static void vmcs_set_bits(unsigned long field, u32 mask)
+static __always_inline void vmcs_clear_bits(unsigned long field, u32 mask)
 {
-       vmcs_writel(field, vmcs_readl(field) | mask);
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x2000,
+                        "vmcs_clear_bits does not support 64-bit fields");
+       __vmcs_writel(field, __vmcs_readl(field) & ~mask);
+}
+
+static __always_inline void vmcs_set_bits(unsigned long field, u32 mask)
+{
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x2000,
+                        "vmcs_set_bits does not support 64-bit fields");
+       __vmcs_writel(field, __vmcs_readl(field) | mask);
 }
 
 static inline void vm_entry_controls_init(struct vcpu_vmx *vmx, u32 val)
@@ -2498,7 +2563,7 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
        vmx->nested.nested_vmx_pinbased_ctls_high |=
                PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR |
                PIN_BASED_VMX_PREEMPTION_TIMER;
-       if (vmx_cpu_uses_apicv(&vmx->vcpu))
+       if (kvm_vcpu_apicv_active(&vmx->vcpu))
                vmx->nested.nested_vmx_pinbased_ctls_high |=
                        PIN_BASED_POSTED_INTR;
 
@@ -4462,9 +4527,9 @@ static void vmx_disable_intercept_msr_write_x2apic(u32 msr)
                        msr, MSR_TYPE_W);
 }
 
-static int vmx_cpu_uses_apicv(struct kvm_vcpu *vcpu)
+static bool vmx_get_enable_apicv(void)
 {
-       return enable_apicv && lapic_in_kernel(vcpu);
+       return enable_apicv;
 }
 
 static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
@@ -4586,11 +4651,6 @@ static void vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu)
        kvm_apic_update_irr(vcpu, vmx->pi_desc.pir);
 }
 
-static void vmx_sync_pir_to_irr_dummy(struct kvm_vcpu *vcpu)
-{
-       return;
-}
-
 /*
  * Set up the vmcs's constant host-state fields, i.e., host-state fields that
  * will not change in the lifetime of the guest.
@@ -4660,11 +4720,18 @@ static u32 vmx_pin_based_exec_ctrl(struct vcpu_vmx *vmx)
 {
        u32 pin_based_exec_ctrl = vmcs_config.pin_based_exec_ctrl;
 
-       if (!vmx_cpu_uses_apicv(&vmx->vcpu))
+       if (!kvm_vcpu_apicv_active(&vmx->vcpu))
                pin_based_exec_ctrl &= ~PIN_BASED_POSTED_INTR;
        return pin_based_exec_ctrl;
 }
 
+static void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+       vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, vmx_pin_based_exec_ctrl(vmx));
+}
+
 static u32 vmx_exec_control(struct vcpu_vmx *vmx)
 {
        u32 exec_control = vmcs_config.cpu_based_exec_ctrl;
@@ -4703,7 +4770,7 @@ static u32 vmx_secondary_exec_control(struct vcpu_vmx *vmx)
                exec_control &= ~SECONDARY_EXEC_UNRESTRICTED_GUEST;
        if (!ple_gap)
                exec_control &= ~SECONDARY_EXEC_PAUSE_LOOP_EXITING;
-       if (!vmx_cpu_uses_apicv(&vmx->vcpu))
+       if (!kvm_vcpu_apicv_active(&vmx->vcpu))
                exec_control &= ~(SECONDARY_EXEC_APIC_REGISTER_VIRT |
                                  SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY);
        exec_control &= ~SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE;
@@ -4767,7 +4834,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
                vmcs_write32(SECONDARY_VM_EXEC_CONTROL,
                                vmx_secondary_exec_control(vmx));
 
-       if (vmx_cpu_uses_apicv(&vmx->vcpu)) {
+       if (kvm_vcpu_apicv_active(&vmx->vcpu)) {
                vmcs_write64(EOI_EXIT_BITMAP0, 0);
                vmcs_write64(EOI_EXIT_BITMAP1, 0);
                vmcs_write64(EOI_EXIT_BITMAP2, 0);
@@ -4775,7 +4842,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
 
                vmcs_write16(GUEST_INTR_STATUS, 0);
 
-               vmcs_write64(POSTED_INTR_NV, POSTED_INTR_VECTOR);
+               vmcs_write16(POSTED_INTR_NV, POSTED_INTR_VECTOR);
                vmcs_write64(POSTED_INTR_DESC_ADDR, __pa((&vmx->pi_desc)));
        }
 
@@ -4867,7 +4934,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
 
        seg_setup(VCPU_SREG_CS);
        vmcs_write16(GUEST_CS_SELECTOR, 0xf000);
-       vmcs_write32(GUEST_CS_BASE, 0xffff0000);
+       vmcs_writel(GUEST_CS_BASE, 0xffff0000ul);
 
        seg_setup(VCPU_SREG_DS);
        seg_setup(VCPU_SREG_ES);
@@ -4903,7 +4970,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
 
        vmcs_write32(GUEST_ACTIVITY_STATE, GUEST_ACTIVITY_ACTIVE);
        vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 0);
-       vmcs_write32(GUEST_PENDING_DBG_EXCEPTIONS, 0);
+       vmcs_writel(GUEST_PENDING_DBG_EXCEPTIONS, 0);
 
        setup_msrs(vmx);
 
@@ -4919,7 +4986,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
 
        kvm_make_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu);
 
-       if (vmx_cpu_uses_apicv(vcpu))
+       if (kvm_vcpu_apicv_active(vcpu))
                memset(&vmx->pi_desc, 0, sizeof(struct pi_desc));
 
        if (vmx->vpid != 0)
@@ -6203,15 +6270,6 @@ static __init int hardware_setup(void)
                kvm_tsc_scaling_ratio_frac_bits = 48;
        }
 
-       if (enable_apicv)
-               kvm_x86_ops->update_cr8_intercept = NULL;
-       else {
-               kvm_x86_ops->hwapic_irr_update = NULL;
-               kvm_x86_ops->hwapic_isr_update = NULL;
-               kvm_x86_ops->deliver_posted_interrupt = NULL;
-               kvm_x86_ops->sync_pir_to_irr = vmx_sync_pir_to_irr_dummy;
-       }
-
        vmx_disable_intercept_for_msr(MSR_FS_BASE, false);
        vmx_disable_intercept_for_msr(MSR_GS_BASE, false);
        vmx_disable_intercept_for_msr(MSR_KERNEL_GS_BASE, true);
@@ -7901,7 +7959,7 @@ static void dump_vmcs(void)
        u32 pin_based_exec_ctrl = vmcs_read32(PIN_BASED_VM_EXEC_CONTROL);
        u32 secondary_exec_control = 0;
        unsigned long cr4 = vmcs_readl(GUEST_CR4);
-       u64 efer = vmcs_readl(GUEST_IA32_EFER);
+       u64 efer = vmcs_read64(GUEST_IA32_EFER);
        int i, n;
 
        if (cpu_has_secondary_exec_ctrls())
@@ -7917,10 +7975,10 @@ static void dump_vmcs(void)
        if ((secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT) &&
            (cr4 & X86_CR4_PAE) && !(efer & EFER_LMA))
        {
-               pr_err("PDPTR0 = 0x%016lx  PDPTR1 = 0x%016lx\n",
-                      vmcs_readl(GUEST_PDPTR0), vmcs_readl(GUEST_PDPTR1));
-               pr_err("PDPTR2 = 0x%016lx  PDPTR3 = 0x%016lx\n",
-                      vmcs_readl(GUEST_PDPTR2), vmcs_readl(GUEST_PDPTR3));
+               pr_err("PDPTR0 = 0x%016llx  PDPTR1 = 0x%016llx\n",
+                      vmcs_read64(GUEST_PDPTR0), vmcs_read64(GUEST_PDPTR1));
+               pr_err("PDPTR2 = 0x%016llx  PDPTR3 = 0x%016llx\n",
+                      vmcs_read64(GUEST_PDPTR2), vmcs_read64(GUEST_PDPTR3));
        }
        pr_err("RSP = 0x%016lx  RIP = 0x%016lx\n",
               vmcs_readl(GUEST_RSP), vmcs_readl(GUEST_RIP));
@@ -7941,16 +7999,16 @@ static void dump_vmcs(void)
        vmx_dump_sel("TR:  ", GUEST_TR_SELECTOR);
        if ((vmexit_ctl & (VM_EXIT_SAVE_IA32_PAT | VM_EXIT_SAVE_IA32_EFER)) ||
            (vmentry_ctl & (VM_ENTRY_LOAD_IA32_PAT | VM_ENTRY_LOAD_IA32_EFER)))
-               pr_err("EFER =     0x%016llx  PAT = 0x%016lx\n",
-                      efer, vmcs_readl(GUEST_IA32_PAT));
-       pr_err("DebugCtl = 0x%016lx  DebugExceptions = 0x%016lx\n",
-              vmcs_readl(GUEST_IA32_DEBUGCTL),
+               pr_err("EFER =     0x%016llx  PAT = 0x%016llx\n",
+                      efer, vmcs_read64(GUEST_IA32_PAT));
+       pr_err("DebugCtl = 0x%016llx  DebugExceptions = 0x%016lx\n",
+              vmcs_read64(GUEST_IA32_DEBUGCTL),
               vmcs_readl(GUEST_PENDING_DBG_EXCEPTIONS));
        if (vmentry_ctl & VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL)
-               pr_err("PerfGlobCtl = 0x%016lx\n",
-                      vmcs_readl(GUEST_IA32_PERF_GLOBAL_CTRL));
+               pr_err("PerfGlobCtl = 0x%016llx\n",
+                      vmcs_read64(GUEST_IA32_PERF_GLOBAL_CTRL));
        if (vmentry_ctl & VM_ENTRY_LOAD_BNDCFGS)
-               pr_err("BndCfgS = 0x%016lx\n", vmcs_readl(GUEST_BNDCFGS));
+               pr_err("BndCfgS = 0x%016llx\n", vmcs_read64(GUEST_BNDCFGS));
        pr_err("Interruptibility = %08x  ActivityState = %08x\n",
               vmcs_read32(GUEST_INTERRUPTIBILITY_INFO),
               vmcs_read32(GUEST_ACTIVITY_STATE));
@@ -7979,11 +8037,12 @@ static void dump_vmcs(void)
               vmcs_read32(HOST_IA32_SYSENTER_CS),
               vmcs_readl(HOST_IA32_SYSENTER_EIP));
        if (vmexit_ctl & (VM_EXIT_LOAD_IA32_PAT | VM_EXIT_LOAD_IA32_EFER))
-               pr_err("EFER = 0x%016lx  PAT = 0x%016lx\n",
-                      vmcs_readl(HOST_IA32_EFER), vmcs_readl(HOST_IA32_PAT));
+               pr_err("EFER = 0x%016llx  PAT = 0x%016llx\n",
+                      vmcs_read64(HOST_IA32_EFER),
+                      vmcs_read64(HOST_IA32_PAT));
        if (vmexit_ctl & VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL)
-               pr_err("PerfGlobCtl = 0x%016lx\n",
-                      vmcs_readl(HOST_IA32_PERF_GLOBAL_CTRL));
+               pr_err("PerfGlobCtl = 0x%016llx\n",
+                      vmcs_read64(HOST_IA32_PERF_GLOBAL_CTRL));
 
        pr_err("*** Control State ***\n");
        pr_err("PinBased=%08x CPUBased=%08x SecondaryExec=%08x\n",
@@ -8006,16 +8065,16 @@ static void dump_vmcs(void)
        pr_err("IDTVectoring: info=%08x errcode=%08x\n",
               vmcs_read32(IDT_VECTORING_INFO_FIELD),
               vmcs_read32(IDT_VECTORING_ERROR_CODE));
-       pr_err("TSC Offset = 0x%016lx\n", vmcs_readl(TSC_OFFSET));
+       pr_err("TSC Offset = 0x%016llx\n", vmcs_read64(TSC_OFFSET));
        if (secondary_exec_control & SECONDARY_EXEC_TSC_SCALING)
-               pr_err("TSC Multiplier = 0x%016lx\n",
-                      vmcs_readl(TSC_MULTIPLIER));
+               pr_err("TSC Multiplier = 0x%016llx\n",
+                      vmcs_read64(TSC_MULTIPLIER));
        if (cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW)
                pr_err("TPR Threshold = 0x%02x\n", vmcs_read32(TPR_THRESHOLD));
        if (pin_based_exec_ctrl & PIN_BASED_POSTED_INTR)
                pr_err("PostedIntrVec = 0x%02x\n", vmcs_read16(POSTED_INTR_NV));
        if ((secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT))
-               pr_err("EPT pointer = 0x%016lx\n", vmcs_readl(EPT_POINTER));
+               pr_err("EPT pointer = 0x%016llx\n", vmcs_read64(EPT_POINTER));
        n = vmcs_read32(CR3_TARGET_COUNT);
        for (i = 0; i + 1 < n; i += 4)
                pr_err("CR3 target%u=%016lx target%u=%016lx\n",
@@ -8154,7 +8213,7 @@ static void vmx_set_virtual_x2apic_mode(struct kvm_vcpu *vcpu, bool set)
         * apicv
         */
        if (!cpu_has_vmx_virtualize_x2apic_mode() ||
-                               !vmx_cpu_uses_apicv(vcpu))
+                               !kvm_vcpu_apicv_active(vcpu))
                return;
 
        if (!cpu_need_tpr_shadow(vcpu))
@@ -8259,10 +8318,9 @@ static void vmx_hwapic_irr_update(struct kvm_vcpu *vcpu, int max_irr)
        }
 }
 
-static void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu)
+static void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
 {
-       u64 *eoi_exit_bitmap = vcpu->arch.eoi_exit_bitmap;
-       if (!vmx_cpu_uses_apicv(vcpu))
+       if (!kvm_vcpu_apicv_active(vcpu))
                return;
 
        vmcs_write64(EOI_EXIT_BITMAP0, eoi_exit_bitmap[0]);
@@ -8932,7 +8990,8 @@ static void vmx_cpuid_update(struct kvm_vcpu *vcpu)
                        best->ebx &= ~bit(X86_FEATURE_INVPCID);
        }
 
-       vmcs_set_secondary_exec_control(secondary_exec_ctl);
+       if (cpu_has_secondary_exec_ctrls())
+               vmcs_set_secondary_exec_control(secondary_exec_ctl);
 
        if (static_cpu_has(X86_FEATURE_PCOMMIT) && nested) {
                if (guest_cpuid_has_pcommit(vcpu))
@@ -9508,7 +9567,7 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
                 */
                vmx->nested.posted_intr_nv = vmcs12->posted_intr_nv;
                vmx->nested.pi_pending = false;
-               vmcs_write64(POSTED_INTR_NV, POSTED_INTR_VECTOR);
+               vmcs_write16(POSTED_INTR_NV, POSTED_INTR_VECTOR);
                vmcs_write64(POSTED_INTR_DESC_ADDR,
                        page_to_phys(vmx->nested.pi_desc_page) +
                        (unsigned long)(vmcs12->posted_intr_desc_addr &
@@ -10169,7 +10228,7 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
         * Additionally, restore L2's PDPTR to vmcs12.
         */
        if (enable_ept) {
-               vmcs12->guest_cr3 = vmcs_read64(GUEST_CR3);
+               vmcs12->guest_cr3 = vmcs_readl(GUEST_CR3);
                vmcs12->guest_pdptr0 = vmcs_read64(GUEST_PDPTR0);
                vmcs12->guest_pdptr1 = vmcs_read64(GUEST_PDPTR1);
                vmcs12->guest_pdptr2 = vmcs_read64(GUEST_PDPTR2);
@@ -10805,7 +10864,8 @@ static struct kvm_x86_ops vmx_x86_ops = {
        .update_cr8_intercept = update_cr8_intercept,
        .set_virtual_x2apic_mode = vmx_set_virtual_x2apic_mode,
        .set_apic_access_page_addr = vmx_set_apic_access_page_addr,
-       .cpu_uses_apicv = vmx_cpu_uses_apicv,
+       .get_enable_apicv = vmx_get_enable_apicv,
+       .refresh_apicv_exec_ctrl = vmx_refresh_apicv_exec_ctrl,
        .load_eoi_exitmap = vmx_load_eoi_exitmap,
        .hwapic_irr_update = vmx_hwapic_irr_update,
        .hwapic_isr_update = vmx_hwapic_isr_update,
index 7ffc224bbe4127a90ef7741f09ae94f75e17feec..f53f5b13c677c8bdde6c35e33bdb665bf4c2a732 100644 (file)
@@ -951,7 +951,7 @@ static u32 msrs_to_save[] = {
        MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
 #endif
        MSR_IA32_TSC, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA,
-       MSR_IA32_FEATURE_CONTROL, MSR_IA32_BNDCFGS
+       MSR_IA32_FEATURE_CONTROL, MSR_IA32_BNDCFGS, MSR_TSC_AUX,
 };
 
 static unsigned num_msrs_to_save;
@@ -966,6 +966,8 @@ static u32 emulated_msrs[] = {
        HV_X64_MSR_RESET,
        HV_X64_MSR_VP_INDEX,
        HV_X64_MSR_VP_RUNTIME,
+       HV_X64_MSR_SCONTROL,
+       HV_X64_MSR_STIMER0_CONFIG,
        HV_X64_MSR_APIC_ASSIST_PAGE, MSR_KVM_ASYNC_PF_EN, MSR_KVM_STEAL_TIME,
        MSR_KVM_PV_EOI_EN,
 
@@ -1167,7 +1169,8 @@ static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
 
        ++version;
 
-       kvm_write_guest(kvm, wall_clock, &version, sizeof(version));
+       if (kvm_write_guest(kvm, wall_clock, &version, sizeof(version)))
+               return;
 
        /*
         * The guest calculates current wall clock time by adding
@@ -1683,6 +1686,11 @@ static void pvclock_update_vm_gtod_copy(struct kvm *kvm)
 #endif
 }
 
+void kvm_make_mclock_inprogress_request(struct kvm *kvm)
+{
+       kvm_make_all_cpus_request(kvm, KVM_REQ_MCLOCK_INPROGRESS);
+}
+
 static void kvm_gen_update_masterclock(struct kvm *kvm)
 {
 #ifdef CONFIG_X86_64
@@ -2198,6 +2206,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
        case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
        case HV_X64_MSR_CRASH_CTL:
+       case HV_X64_MSR_STIMER0_CONFIG ... HV_X64_MSR_STIMER3_COUNT:
                return kvm_hv_set_msr_common(vcpu, msr, data,
                                             msr_info->host_initiated);
        case MSR_IA32_BBL_CR_CTL3:
@@ -2402,6 +2411,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
        case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
        case HV_X64_MSR_CRASH_CTL:
+       case HV_X64_MSR_STIMER0_CONFIG ... HV_X64_MSR_STIMER3_COUNT:
                return kvm_hv_get_msr_common(vcpu,
                                             msr_info->index, &msr_info->data);
                break;
@@ -2541,6 +2551,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_HYPERV:
        case KVM_CAP_HYPERV_VAPIC:
        case KVM_CAP_HYPERV_SPIN:
+       case KVM_CAP_HYPERV_SYNIC:
        case KVM_CAP_PCI_SEGMENT:
        case KVM_CAP_DEBUGREGS:
        case KVM_CAP_X86_ROBUST_SINGLESTEP:
@@ -2693,6 +2704,11 @@ static bool need_emulate_wbinvd(struct kvm_vcpu *vcpu)
        return kvm_arch_has_noncoherent_dma(vcpu->kvm);
 }
 
+static inline void kvm_migrate_timers(struct kvm_vcpu *vcpu)
+{
+       set_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests);
+}
+
 void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
        /* Address WBINVD may be executed by guest */
@@ -2748,7 +2764,9 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
                                    struct kvm_lapic_state *s)
 {
-       kvm_x86_ops->sync_pir_to_irr(vcpu);
+       if (vcpu->arch.apicv_active)
+               kvm_x86_ops->sync_pir_to_irr(vcpu);
+
        memcpy(s->regs, vcpu->arch.apic->regs, sizeof *s);
 
        return 0;
@@ -3191,6 +3209,20 @@ static int kvm_set_guest_paused(struct kvm_vcpu *vcpu)
        return 0;
 }
 
+static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
+                                    struct kvm_enable_cap *cap)
+{
+       if (cap->flags)
+               return -EINVAL;
+
+       switch (cap->cap) {
+       case KVM_CAP_HYPERV_SYNIC:
+               return kvm_hv_activate_synic(vcpu);
+       default:
+               return -EINVAL;
+       }
+}
+
 long kvm_arch_vcpu_ioctl(struct file *filp,
                         unsigned int ioctl, unsigned long arg)
 {
@@ -3455,6 +3487,15 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
                r = kvm_set_guest_paused(vcpu);
                goto out;
        }
+       case KVM_ENABLE_CAP: {
+               struct kvm_enable_cap cap;
+
+               r = -EFAULT;
+               if (copy_from_user(&cap, argp, sizeof(cap)))
+                       goto out;
+               r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap);
+               break;
+       }
        default:
                r = -EINVAL;
        }
@@ -3606,7 +3647,8 @@ static int kvm_vm_ioctl_set_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
               sizeof(kvm->arch.vpit->pit_state.channels));
        kvm->arch.vpit->pit_state.flags = ps->flags;
        for (i = 0; i < 3; i++)
-               kvm_pit_load_count(kvm, i, kvm->arch.vpit->pit_state.channels[i].count, start);
+               kvm_pit_load_count(kvm, i, kvm->arch.vpit->pit_state.channels[i].count,
+                                  start && i == 0);
        mutex_unlock(&kvm->arch.vpit->pit_state.lock);
        return 0;
 }
@@ -4005,16 +4047,17 @@ static void kvm_init_msr_list(void)
 
                /*
                 * Even MSRs that are valid in the host may not be exposed
-                * to the guests in some cases.  We could work around this
-                * in VMX with the generic MSR save/load machinery, but it
-                * is not really worthwhile since it will really only
-                * happen with nested virtualization.
+                * to the guests in some cases.
                 */
                switch (msrs_to_save[i]) {
                case MSR_IA32_BNDCFGS:
                        if (!kvm_x86_ops->mpx_supported())
                                continue;
                        break;
+               case MSR_TSC_AUX:
+                       if (!kvm_x86_ops->rdtscp_supported())
+                               continue;
+                       break;
                default:
                        break;
                }
@@ -5871,6 +5914,12 @@ static void kvm_pv_kick_cpu_op(struct kvm *kvm, unsigned long flags, int apicid)
        kvm_irq_delivery_to_apic(kvm, NULL, &lapic_irq, NULL);
 }
 
+void kvm_vcpu_deactivate_apicv(struct kvm_vcpu *vcpu)
+{
+       vcpu->arch.apicv_active = false;
+       kvm_x86_ops->refresh_apicv_exec_ctrl(vcpu);
+}
+
 int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
 {
        unsigned long nr, a0, a1, a2, a3, ret;
@@ -5964,6 +6013,9 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu)
        if (!vcpu->arch.apic)
                return;
 
+       if (vcpu->arch.apicv_active)
+               return;
+
        if (!vcpu->arch.apic->vapic_addr)
                max_irr = kvm_lapic_find_highest_irr(vcpu);
        else
@@ -6300,20 +6352,30 @@ static void process_smi(struct kvm_vcpu *vcpu)
        kvm_mmu_reset_context(vcpu);
 }
 
+void kvm_make_scan_ioapic_request(struct kvm *kvm)
+{
+       kvm_make_all_cpus_request(kvm, KVM_REQ_SCAN_IOAPIC);
+}
+
 static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
 {
+       u64 eoi_exit_bitmap[4];
+
        if (!kvm_apic_hw_enabled(vcpu->arch.apic))
                return;
 
-       memset(vcpu->arch.eoi_exit_bitmap, 0, 256 / 8);
+       bitmap_zero(vcpu->arch.ioapic_handled_vectors, 256);
 
        if (irqchip_split(vcpu->kvm))
-               kvm_scan_ioapic_routes(vcpu, vcpu->arch.eoi_exit_bitmap);
+               kvm_scan_ioapic_routes(vcpu, vcpu->arch.ioapic_handled_vectors);
        else {
-               kvm_x86_ops->sync_pir_to_irr(vcpu);
-               kvm_ioapic_scan_entry(vcpu, vcpu->arch.eoi_exit_bitmap);
+               if (vcpu->arch.apicv_active)
+                       kvm_x86_ops->sync_pir_to_irr(vcpu);
+               kvm_ioapic_scan_entry(vcpu, vcpu->arch.ioapic_handled_vectors);
        }
-       kvm_x86_ops->load_eoi_exitmap(vcpu);
+       bitmap_or((ulong *)eoi_exit_bitmap, vcpu->arch.ioapic_handled_vectors,
+                 vcpu_to_synic(vcpu)->vec_bitmap, 256);
+       kvm_x86_ops->load_eoi_exitmap(vcpu, eoi_exit_bitmap);
 }
 
 static void kvm_vcpu_flush_tlb(struct kvm_vcpu *vcpu)
@@ -6421,7 +6483,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
                if (kvm_check_request(KVM_REQ_IOAPIC_EOI_EXIT, vcpu)) {
                        BUG_ON(vcpu->arch.pending_ioapic_eoi > 255);
                        if (test_bit(vcpu->arch.pending_ioapic_eoi,
-                                    (void *) vcpu->arch.eoi_exit_bitmap)) {
+                                    vcpu->arch.ioapic_handled_vectors)) {
                                vcpu->run->exit_reason = KVM_EXIT_IOAPIC_EOI;
                                vcpu->run->eoi.vector =
                                                vcpu->arch.pending_ioapic_eoi;
@@ -6445,6 +6507,20 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
                        r = 0;
                        goto out;
                }
+               if (kvm_check_request(KVM_REQ_HV_EXIT, vcpu)) {
+                       vcpu->run->exit_reason = KVM_EXIT_HYPERV;
+                       vcpu->run->hyperv = vcpu->arch.hyperv.exit;
+                       r = 0;
+                       goto out;
+               }
+
+               /*
+                * KVM_REQ_HV_STIMER has to be processed after
+                * KVM_REQ_CLOCK_UPDATE, because Hyper-V SynIC timers
+                * depend on the guest clock being up-to-date
+                */
+               if (kvm_check_request(KVM_REQ_HV_STIMER, vcpu))
+                       kvm_hv_process_stimers(vcpu);
        }
 
        /*
@@ -6456,7 +6532,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
                 * Update architecture specific hints for APIC
                 * virtual interrupt delivery.
                 */
-               if (kvm_x86_ops->hwapic_irr_update)
+               if (vcpu->arch.apicv_active)
                        kvm_x86_ops->hwapic_irr_update(vcpu,
                                kvm_lapic_find_highest_irr(vcpu));
        }
@@ -7527,6 +7603,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
        BUG_ON(vcpu->kvm == NULL);
        kvm = vcpu->kvm;
 
+       vcpu->arch.apicv_active = kvm_x86_ops->get_enable_apicv();
        vcpu->arch.pv.pv_unhalted = false;
        vcpu->arch.emulate_ctxt.ops = &emulate_ops;
        if (!irqchip_in_kernel(kvm) || kvm_vcpu_is_reset_bsp(vcpu))
@@ -7584,6 +7661,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 
        vcpu->arch.pending_external_vector = -1;
 
+       kvm_hv_vcpu_init(vcpu);
+
        return 0;
 
 fail_free_mce_banks:
@@ -7602,6 +7681,7 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
 {
        int idx;
 
+       kvm_hv_vcpu_uninit(vcpu);
        kvm_pmu_destroy(vcpu);
        kfree(vcpu->arch.mce_banks);
        kvm_free_lapic(vcpu);
@@ -7996,6 +8076,9 @@ static inline bool kvm_vcpu_has_events(struct kvm_vcpu *vcpu)
            kvm_cpu_has_interrupt(vcpu))
                return true;
 
+       if (kvm_hv_has_stimer_pending(vcpu))
+               return true;
+
        return false;
 }
 
index a0d09f6c65337fc381353783639f45251bf28d78..4ba229ac3f4ff127dddf0c33fb91cc42f2e60b22 100644 (file)
@@ -1414,6 +1414,7 @@ __init void lguest_init(void)
        pv_info.kernel_rpl = 1;
        /* Everyone except Xen runs with this set. */
        pv_info.shared_kernel_pmd = 1;
+       pv_info.features = 0;
 
        /*
         * We set up all the lguest overrides for sensitive operations.  These
@@ -1472,7 +1473,6 @@ __init void lguest_init(void)
        pv_mmu_ops.lazy_mode.leave = lguest_leave_lazy_mmu_mode;
        pv_mmu_ops.lazy_mode.flush = paravirt_flush_lazy_mmu;
        pv_mmu_ops.pte_update = lguest_pte_update;
-       pv_mmu_ops.pte_update_defer = lguest_pte_update;
 
 #ifdef CONFIG_X86_LOCAL_APIC
        /* APIC read/write intercepts */
index f2587888d987f7ce4f370fd70b4b18461581b19e..a501fa25da41faac952fc05bba7c7ad45f8d0ca8 100644 (file)
@@ -16,7 +16,7 @@ clean-files := inat-tables.c
 
 obj-$(CONFIG_SMP) += msr-smp.o cache-smp.o
 
-lib-y := delay.o misc.o cmdline.o
+lib-y := delay.o misc.o cmdline.o cpu.o
 lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o
 lib-y += memcpy_$(BITS).o
 lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
diff --git a/arch/x86/lib/cpu.c b/arch/x86/lib/cpu.c
new file mode 100644 (file)
index 0000000..aa417a9
--- /dev/null
@@ -0,0 +1,35 @@
+#include <linux/module.h>
+
+unsigned int x86_family(unsigned int sig)
+{
+       unsigned int x86;
+
+       x86 = (sig >> 8) & 0xf;
+
+       if (x86 == 0xf)
+               x86 += (sig >> 20) & 0xff;
+
+       return x86;
+}
+EXPORT_SYMBOL_GPL(x86_family);
+
+unsigned int x86_model(unsigned int sig)
+{
+       unsigned int fam, model;
+
+        fam = x86_family(sig);
+
+       model = (sig >> 4) & 0xf;
+
+       if (fam >= 0x6)
+               model += ((sig >> 16) & 0xf) << 4;
+
+       return model;
+}
+EXPORT_SYMBOL_GPL(x86_model);
+
+unsigned int x86_stepping(unsigned int sig)
+{
+       return sig & 0xf;
+}
+EXPORT_SYMBOL_GPL(x86_stepping);
index 43623739c7cf315038f908d9623e601d8069c35b..004c861b1648e50ae8c386563b798bb6d50bece7 100644 (file)
@@ -1,6 +1,8 @@
 #include <linux/module.h>
 #include <linux/preempt.h>
 #include <asm/msr.h>
+#define CREATE_TRACE_POINTS
+#include <asm/msr-trace.h>
 
 struct msr *msrs_alloc(void)
 {
@@ -108,3 +110,27 @@ int msr_clear_bit(u32 msr, u8 bit)
 {
        return __flip_bit(msr, bit, false);
 }
+
+#ifdef CONFIG_TRACEPOINTS
+void do_trace_write_msr(unsigned msr, u64 val, int failed)
+{
+       trace_write_msr(msr, val, failed);
+}
+EXPORT_SYMBOL(do_trace_write_msr);
+EXPORT_TRACEPOINT_SYMBOL(write_msr);
+
+void do_trace_read_msr(unsigned msr, u64 val, int failed)
+{
+       trace_read_msr(msr, val, failed);
+}
+EXPORT_SYMBOL(do_trace_read_msr);
+EXPORT_TRACEPOINT_SYMBOL(read_msr);
+
+void do_trace_rdpmc(unsigned counter, u64 val, int failed)
+{
+       trace_rdpmc(counter, val, failed);
+}
+EXPORT_SYMBOL(do_trace_rdpmc);
+EXPORT_TRACEPOINT_SYMBOL(rdpmc);
+
+#endif
index 65c47fda26fc5643d67aed5013de8aa8257aac0a..f9d38a48e3c847f129ddd62c4f6d4e40180711ad 100644 (file)
@@ -15,6 +15,7 @@ obj-$(CONFIG_X86_32)          += pgtable_32.o iomap_32.o
 
 obj-$(CONFIG_HUGETLB_PAGE)     += hugetlbpage.o
 obj-$(CONFIG_X86_PTDUMP_CORE)  += dump_pagetables.o
+obj-$(CONFIG_X86_PTDUMP)       += debug_pagetables.o
 
 obj-$(CONFIG_HIGHMEM)          += highmem_32.o
 
diff --git a/arch/x86/mm/debug_pagetables.c b/arch/x86/mm/debug_pagetables.c
new file mode 100644 (file)
index 0000000..bfcffdf
--- /dev/null
@@ -0,0 +1,46 @@
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <asm/pgtable.h>
+
+static int ptdump_show(struct seq_file *m, void *v)
+{
+       ptdump_walk_pgd_level(m, NULL);
+       return 0;
+}
+
+static int ptdump_open(struct inode *inode, struct file *filp)
+{
+       return single_open(filp, ptdump_show, NULL);
+}
+
+static const struct file_operations ptdump_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ptdump_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static struct dentry *pe;
+
+static int __init pt_dump_debug_init(void)
+{
+       pe = debugfs_create_file("kernel_page_tables", S_IRUSR, NULL, NULL,
+                                &ptdump_fops);
+       if (!pe)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void __exit pt_dump_debug_exit(void)
+{
+       debugfs_remove_recursive(pe);
+}
+
+module_init(pt_dump_debug_init);
+module_exit(pt_dump_debug_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Arjan van de Ven <arjan@linux.intel.com>");
+MODULE_DESCRIPTION("Kernel debugging helper that dumps pagetables");
index 0f1c6fc3ddd88948646963772ac0fa12c492c212..4a6f1d9b51060cc9179598f5916efb69504fa50f 100644 (file)
@@ -426,38 +426,15 @@ void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd)
 {
        ptdump_walk_pgd_level_core(m, pgd, false);
 }
+EXPORT_SYMBOL_GPL(ptdump_walk_pgd_level);
 
 void ptdump_walk_pgd_level_checkwx(void)
 {
        ptdump_walk_pgd_level_core(NULL, NULL, true);
 }
 
-#ifdef CONFIG_X86_PTDUMP
-static int ptdump_show(struct seq_file *m, void *v)
+static int __init pt_dump_init(void)
 {
-       ptdump_walk_pgd_level(m, NULL);
-       return 0;
-}
-
-static int ptdump_open(struct inode *inode, struct file *filp)
-{
-       return single_open(filp, ptdump_show, NULL);
-}
-
-static const struct file_operations ptdump_fops = {
-       .open           = ptdump_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-#endif
-
-static int pt_dump_init(void)
-{
-#ifdef CONFIG_X86_PTDUMP
-       struct dentry *pe;
-#endif
-
 #ifdef CONFIG_X86_32
        /* Not a compile-time constant on x86-32 */
        address_markers[VMALLOC_START_NR].start_address = VMALLOC_START;
@@ -468,13 +445,6 @@ static int pt_dump_init(void)
        address_markers[FIXADDR_START_NR].start_address = FIXADDR_START;
 #endif
 
-#ifdef CONFIG_X86_PTDUMP
-       pe = debugfs_create_file("kernel_page_tables", 0600, NULL, NULL,
-                                &ptdump_fops);
-       if (!pe)
-               return -ENOMEM;
-#endif
-
        return 0;
 }
 
index b9c78f3bcd6739718def393f49d1f1cbb0e8bb5c..0d8d53d1f5cc29c2376e8d72204896b0be6b4878 100644 (file)
@@ -194,8 +194,8 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
         * Check if the request spans more than any BAR in the iomem resource
         * tree.
         */
-       WARN_ONCE(iomem_map_sanity_check(unaligned_phys_addr, unaligned_size),
-                 KERN_INFO "Info: mapping multiple BARs. Your kernel is fine.");
+       if (iomem_map_sanity_check(unaligned_phys_addr, unaligned_size))
+               pr_warn("caller %pS mapping multiple BARs\n", caller);
 
        return ret_addr;
 err_free_area:
index a3137a4feed15ed0d58189411e4e1ae2d9236e8a..6000ad7f560c399226f06612c406268ac6a68820 100644 (file)
@@ -129,14 +129,16 @@ within(unsigned long addr, unsigned long start, unsigned long end)
  */
 void clflush_cache_range(void *vaddr, unsigned int size)
 {
-       unsigned long clflush_mask = boot_cpu_data.x86_clflush_size - 1;
+       const unsigned long clflush_size = boot_cpu_data.x86_clflush_size;
+       void *p = (void *)((unsigned long)vaddr & ~(clflush_size - 1));
        void *vend = vaddr + size;
-       void *p;
+
+       if (p >= vend)
+               return;
 
        mb();
 
-       for (p = (void *)((unsigned long)vaddr & ~clflush_mask);
-            p < vend; p += boot_cpu_data.x86_clflush_size)
+       for (; p < vend; p += clflush_size)
                clflushopt(p);
 
        mb();
index 188e3e07eeeba7c0eb6555c138a16e97c3e5d787..031782e7423197ab4dbadb857eeed3349bcde396 100644 (file)
@@ -586,7 +586,7 @@ int free_memtype(u64 start, u64 end)
        entry = rbt_memtype_erase(start, end);
        spin_unlock(&memtype_lock);
 
-       if (!entry) {
+       if (IS_ERR(entry)) {
                pr_info("x86/PAT: %s:%d freeing invalid memtype [mem %#010Lx-%#010Lx]\n",
                        current->comm, current->pid, start, end - 1);
                return -EINVAL;
@@ -992,6 +992,16 @@ void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn,
        vma->vm_flags &= ~VM_PAT;
 }
 
+/*
+ * untrack_pfn_moved is called, while mremapping a pfnmap for a new region,
+ * with the old vma after its pfnmap page table has been removed.  The new
+ * vma has a new pfnmap to the same pfn & cache type with VM_PAT set.
+ */
+void untrack_pfn_moved(struct vm_area_struct *vma)
+{
+       vma->vm_flags &= ~VM_PAT;
+}
+
 pgprot_t pgprot_writecombine(pgprot_t prot)
 {
        return __pgprot(pgprot_val(prot) |
index 63931080366aaae1626c48b8ec780acd78d09569..2f7702253ccfaad30da5233ac9293cb5421d1742 100644 (file)
@@ -98,8 +98,13 @@ static struct memtype *memtype_rb_lowest_match(struct rb_root *root,
        return last_lower; /* Returns NULL if there is no overlap */
 }
 
-static struct memtype *memtype_rb_exact_match(struct rb_root *root,
-                               u64 start, u64 end)
+enum {
+       MEMTYPE_EXACT_MATCH     = 0,
+       MEMTYPE_END_MATCH       = 1
+};
+
+static struct memtype *memtype_rb_match(struct rb_root *root,
+                               u64 start, u64 end, int match_type)
 {
        struct memtype *match;
 
@@ -107,7 +112,12 @@ static struct memtype *memtype_rb_exact_match(struct rb_root *root,
        while (match != NULL && match->start < end) {
                struct rb_node *node;
 
-               if (match->start == start && match->end == end)
+               if ((match_type == MEMTYPE_EXACT_MATCH) &&
+                   (match->start == start) && (match->end == end))
+                       return match;
+
+               if ((match_type == MEMTYPE_END_MATCH) &&
+                   (match->start < start) && (match->end == end))
                        return match;
 
                node = rb_next(&match->rb);
@@ -117,7 +127,7 @@ static struct memtype *memtype_rb_exact_match(struct rb_root *root,
                        match = NULL;
        }
 
-       return NULL; /* Returns NULL if there is no exact match */
+       return NULL; /* Returns NULL if there is no match */
 }
 
 static int memtype_rb_check_conflict(struct rb_root *root,
@@ -210,12 +220,36 @@ struct memtype *rbt_memtype_erase(u64 start, u64 end)
 {
        struct memtype *data;
 
-       data = memtype_rb_exact_match(&memtype_rbroot, start, end);
-       if (!data)
-               goto out;
+       /*
+        * Since the memtype_rbroot tree allows overlapping ranges,
+        * rbt_memtype_erase() checks with EXACT_MATCH first, i.e. free
+        * a whole node for the munmap case.  If no such entry is found,
+        * it then checks with END_MATCH, i.e. shrink the size of a node
+        * from the end for the mremap case.
+        */
+       data = memtype_rb_match(&memtype_rbroot, start, end,
+                               MEMTYPE_EXACT_MATCH);
+       if (!data) {
+               data = memtype_rb_match(&memtype_rbroot, start, end,
+                                       MEMTYPE_END_MATCH);
+               if (!data)
+                       return ERR_PTR(-EINVAL);
+       }
+
+       if (data->start == start) {
+               /* munmap: erase this node */
+               rb_erase_augmented(&data->rb, &memtype_rbroot,
+                                       &memtype_rb_augment_cb);
+       } else {
+               /* mremap: update the end value of this node */
+               rb_erase_augmented(&data->rb, &memtype_rbroot,
+                                       &memtype_rb_augment_cb);
+               data->end = start;
+               data->subtree_max_end = data->end;
+               memtype_rb_insert(&memtype_rbroot, data);
+               return NULL;
+       }
 
-       rb_erase_augmented(&data->rb, &memtype_rbroot, &memtype_rb_augment_cb);
-out:
        return data;
 }
 
index fb0a9dd1d6e46fc6e6921bf29df9f71e830fdcb8..ee9c2e3a71999e547996e94a209954d8cc58c445 100644 (file)
@@ -414,7 +414,7 @@ int ptep_set_access_flags(struct vm_area_struct *vma,
 
        if (changed && dirty) {
                *ptep = entry;
-               pte_update_defer(vma->vm_mm, address, ptep);
+               pte_update(vma->vm_mm, address, ptep);
        }
 
        return changed;
@@ -431,7 +431,6 @@ int pmdp_set_access_flags(struct vm_area_struct *vma,
 
        if (changed && dirty) {
                *pmdp = entry;
-               pmd_update_defer(vma->vm_mm, address, pmdp);
                /*
                 * We had a write-protection fault here and changed the pmd
                 * to to more permissive. No need to flush the TLB for that,
@@ -469,9 +468,6 @@ int pmdp_test_and_clear_young(struct vm_area_struct *vma,
                ret = test_and_clear_bit(_PAGE_BIT_ACCESSED,
                                         (unsigned long *)pmdp);
 
-       if (ret)
-               pmd_update(vma->vm_mm, addr, pmdp);
-
        return ret;
 }
 #endif
@@ -518,7 +514,6 @@ void pmdp_splitting_flush(struct vm_area_struct *vma,
        set = !test_and_set_bit(_PAGE_BIT_SPLITTING,
                                (unsigned long *)pmdp);
        if (set) {
-               pmd_update(vma->vm_mm, address, pmdp);
                /* need tlb flush only to serialize against gup-fast */
                flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
        }
index 90555bf60aa45dce625c0171e4783e6014529490..92e2eacb33216821e8b18821834c7ce972571f29 100644 (file)
@@ -31,7 +31,7 @@ early_param("noexec", noexec_setup);
 
 void x86_configure_nx(void)
 {
-       if (cpu_has_nx && !disable_nx)
+       if (boot_cpu_has(X86_FEATURE_NX) && !disable_nx)
                __supported_pte_mask |= _PAGE_NX;
        else
                __supported_pte_mask &= ~_PAGE_NX;
@@ -39,7 +39,7 @@ void x86_configure_nx(void)
 
 void __init x86_report_nx(void)
 {
-       if (!cpu_has_nx) {
+       if (!boot_cpu_has(X86_FEATURE_NX)) {
                printk(KERN_NOTICE "Notice: NX (Execute Disable) protection "
                       "missing in CPU!\n");
        } else {
index c2aea63bee2085fdb08c9d4ea8f3accaf4ae2e5e..b5f821881465dccf29f51bafa142580061719c1c 100644 (file)
@@ -203,6 +203,8 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
                pr_warn("SRAT: Failed to mark hotplug range [mem %#010Lx-%#010Lx] in memblock\n",
                        (unsigned long long)start, (unsigned long long)end - 1);
 
+       max_possible_pfn = max(max_possible_pfn, PFN_UP(end - 1));
+
        return 0;
 out_err_bad_srat:
        bad_srat();
index 327f21c3bde1183ebe1dcc04eded4ba82e88d8af..8dd80050d705eea6099212724f953de8364355ff 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/nmi.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/clocksource.h>
 
 #include <asm/apic.h>
 #include <asm/current.h>
index 9ab52791fed59e3ab2e531611037c4ed9dc7bde3..d5f64996394a97a293aa90149aee54a9636bc6de 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/debugreg.h>
 #include <asm/cpu.h>
 #include <asm/mmu_context.h>
+#include <linux/dmi.h>
 
 #ifdef CONFIG_X86_32
 __visible unsigned long saved_context_ebx;
@@ -32,6 +33,29 @@ __visible unsigned long saved_context_eflags;
 #endif
 struct saved_context saved_context;
 
+static void msr_save_context(struct saved_context *ctxt)
+{
+       struct saved_msr *msr = ctxt->saved_msrs.array;
+       struct saved_msr *end = msr + ctxt->saved_msrs.num;
+
+       while (msr < end) {
+               msr->valid = !rdmsrl_safe(msr->info.msr_no, &msr->info.reg.q);
+               msr++;
+       }
+}
+
+static void msr_restore_context(struct saved_context *ctxt)
+{
+       struct saved_msr *msr = ctxt->saved_msrs.array;
+       struct saved_msr *end = msr + ctxt->saved_msrs.num;
+
+       while (msr < end) {
+               if (msr->valid)
+                       wrmsrl(msr->info.msr_no, msr->info.reg.q);
+               msr++;
+       }
+}
+
 /**
  *     __save_processor_state - save CPU registers before creating a
  *             hibernation image and before restoring the memory state from it
@@ -111,6 +135,7 @@ static void __save_processor_state(struct saved_context *ctxt)
 #endif
        ctxt->misc_enable_saved = !rdmsrl_safe(MSR_IA32_MISC_ENABLE,
                                               &ctxt->misc_enable);
+       msr_save_context(ctxt);
 }
 
 /* Needed by apm.c */
@@ -229,6 +254,7 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
        x86_platform.restore_sched_clock_state();
        mtrr_bp_restore();
        perf_restore_debug_store();
+       msr_restore_context(ctxt);
 }
 
 /* Needed by apm.c */
@@ -320,3 +346,69 @@ static int __init bsp_pm_check_init(void)
 }
 
 core_initcall(bsp_pm_check_init);
+
+static int msr_init_context(const u32 *msr_id, const int total_num)
+{
+       int i = 0;
+       struct saved_msr *msr_array;
+
+       if (saved_context.saved_msrs.array || saved_context.saved_msrs.num > 0) {
+               pr_err("x86/pm: MSR quirk already applied, please check your DMI match table.\n");
+               return -EINVAL;
+       }
+
+       msr_array = kmalloc_array(total_num, sizeof(struct saved_msr), GFP_KERNEL);
+       if (!msr_array) {
+               pr_err("x86/pm: Can not allocate memory to save/restore MSRs during suspend.\n");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < total_num; i++) {
+               msr_array[i].info.msr_no        = msr_id[i];
+               msr_array[i].valid              = false;
+               msr_array[i].info.reg.q         = 0;
+       }
+       saved_context.saved_msrs.num    = total_num;
+       saved_context.saved_msrs.array  = msr_array;
+
+       return 0;
+}
+
+/*
+ * The following section is a quirk framework for problematic BIOSen:
+ * Sometimes MSRs are modified by the BIOSen after suspended to
+ * RAM, this might cause unexpected behavior after wakeup.
+ * Thus we save/restore these specified MSRs across suspend/resume
+ * in order to work around it.
+ *
+ * For any further problematic BIOSen/platforms,
+ * please add your own function similar to msr_initialize_bdw.
+ */
+static int msr_initialize_bdw(const struct dmi_system_id *d)
+{
+       /* Add any extra MSR ids into this array. */
+       u32 bdw_msr_id[] = { MSR_IA32_THERM_CONTROL };
+
+       pr_info("x86/pm: %s detected, MSR saving is needed during suspending.\n", d->ident);
+       return msr_init_context(bdw_msr_id, ARRAY_SIZE(bdw_msr_id));
+}
+
+static struct dmi_system_id msr_save_dmi_table[] = {
+       {
+        .callback = msr_initialize_bdw,
+        .ident = "BROADWELL BDX_EP",
+        .matches = {
+               DMI_MATCH(DMI_PRODUCT_NAME, "GRANTLEY"),
+               DMI_MATCH(DMI_PRODUCT_VERSION, "E63448-400"),
+               },
+       },
+       {}
+};
+
+static int pm_check_save_msr(void)
+{
+       dmi_check_system(msr_save_dmi_table);
+       return 0;
+}
+
+device_initcall(pm_check_save_msr);
index acda713ab5beaba2c986191012a25c875c3a267c..abf4901c917bacd58e8172b4566ad8b3eb10a467 100644 (file)
@@ -64,7 +64,7 @@ static u32 xen_apic_read(u32 reg)
        if (reg != APIC_ID)
                return 0;
 
-       ret = HYPERVISOR_dom0_op(&op);
+       ret = HYPERVISOR_platform_op(&op);
        if (ret)
                return 0;
 
index 5774800ff583ca33916e365e408b057d982a8384..d09e4c9d7cc5b4044c4421bde8692aaa6f8b21be 100644 (file)
@@ -415,7 +415,7 @@ static bool __init xen_check_mwait(void)
 
        set_xen_guest_handle(op.u.set_pminfo.pdc, buf);
 
-       if ((HYPERVISOR_dom0_op(&op) == 0) &&
+       if ((HYPERVISOR_platform_op(&op) == 0) &&
            (buf[2] & (ACPI_PDC_C_C1_FFH | ACPI_PDC_C_C2C3_FFH))) {
                cpuid_leaf5_ecx_val = cx;
                cpuid_leaf5_edx_val = dx;
@@ -1192,7 +1192,7 @@ static const struct pv_info xen_info __initconst = {
 #ifdef CONFIG_X86_64
        .extra_user_64bit_cs = FLAT_USER_CS64,
 #endif
-
+       .features = 0,
        .name = "Xen",
 };
 
@@ -1229,10 +1229,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = {
 
        .iret = xen_iret,
 #ifdef CONFIG_X86_64
-       .usergs_sysret32 = xen_sysret32,
        .usergs_sysret64 = xen_sysret64,
-#else
-       .irq_enable_sysexit = xen_sysexit,
 #endif
 
        .load_tr_desc = paravirt_nop,
@@ -1265,12 +1262,6 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = {
        .end_context_switch = xen_end_context_switch,
 };
 
-static const struct pv_apic_ops xen_apic_ops __initconst = {
-#ifdef CONFIG_X86_LOCAL_APIC
-       .startup_ipi_hook = paravirt_nop,
-#endif
-};
-
 static void xen_reboot(int reason)
 {
        struct sched_shutdown r = { .reason = reason };
@@ -1374,7 +1365,7 @@ static void __init xen_boot_params_init_edd(void)
                info->params.length = sizeof(info->params);
                set_xen_guest_handle(op.u.firmware_info.u.disk_info.edd_params,
                                     &info->params);
-               ret = HYPERVISOR_dom0_op(&op);
+               ret = HYPERVISOR_platform_op(&op);
                if (ret)
                        break;
 
@@ -1392,7 +1383,7 @@ static void __init xen_boot_params_init_edd(void)
        op.u.firmware_info.type = XEN_FW_DISK_MBR_SIGNATURE;
        for (nr = 0; nr < EDD_MBR_SIG_MAX; nr++) {
                op.u.firmware_info.index = nr;
-               ret = HYPERVISOR_dom0_op(&op);
+               ret = HYPERVISOR_platform_op(&op);
                if (ret)
                        break;
                mbr_signature[nr] = op.u.firmware_info.u.disk_mbr_signature.mbr_signature;
@@ -1535,8 +1526,9 @@ asmlinkage __visible void __init xen_start_kernel(void)
 
        /* Install Xen paravirt ops */
        pv_info = xen_info;
+       if (xen_initial_domain())
+               pv_info.features |= PV_SUPPORTED_RTC;
        pv_init_ops = xen_init_ops;
-       pv_apic_ops = xen_apic_ops;
        if (!xen_pvh_domain()) {
                pv_cpu_ops = xen_cpu_ops;
 
@@ -1698,7 +1690,7 @@ asmlinkage __visible void __init xen_start_kernel(void)
                xen_start_info->console.domU.mfn = 0;
                xen_start_info->console.domU.evtchn = 0;
 
-               if (HYPERVISOR_dom0_op(&op) == 0)
+               if (HYPERVISOR_platform_op(&op) == 0)
                        boot_params.kbd_status = op.u.firmware_info.u.kbd_shift_flags;
 
                /* Make sure ACS will be enabled */
@@ -1886,8 +1878,10 @@ EXPORT_SYMBOL_GPL(xen_hvm_need_lapic);
 
 static void xen_set_cpu_features(struct cpuinfo_x86 *c)
 {
-       if (xen_pv_domain())
+       if (xen_pv_domain()) {
                clear_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS);
+               set_cpu_cap(c, X86_FEATURE_XENPV);
+       }
 }
 
 const struct hypervisor_x86 x86_hyper_xen = {
index cb5e266a8bf752297eaf6fc0d822c9398239fadf..c913ca4f6958693f6d7357c53bf149076a4b6d4f 100644 (file)
@@ -2436,7 +2436,6 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = {
        .flush_tlb_others = xen_flush_tlb_others,
 
        .pte_update = paravirt_nop,
-       .pte_update_defer = paravirt_nop,
 
        .pgd_alloc = xen_pgd_alloc,
        .pgd_free = xen_pgd_free,
index 3705eabd7e22ee68d22c1b66d4cb1661bb108f41..7f664c416faf55672f604c5b688f6b6ef32102a8 100644 (file)
@@ -1,6 +1,7 @@
 #include <linux/types.h>
 #include <linux/tick.h>
 
+#include <xen/xen.h>
 #include <xen/interface/xen.h>
 #include <xen/grant_table.h>
 #include <xen/events.h>
@@ -33,7 +34,8 @@ static void xen_hvm_post_suspend(int suspend_cancelled)
 {
 #ifdef CONFIG_XEN_PVHVM
        int cpu;
-       xen_hvm_init_shared_info();
+       if (!suspend_cancelled)
+           xen_hvm_init_shared_info();
        xen_callback_vector();
        xen_unplug_emulated_devices();
        if (xen_feature(XENFEAT_hvm_safe_pvclock)) {
index f1ba6a092854c68017a49f9a4d6fd7c1106bde7f..a0a4e554c6f195ffe2abd37d712e12e9ee8d9e85 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/gfp.h>
 #include <linux/slab.h>
 #include <linux/pvclock_gtod.h>
+#include <linux/timekeeper_internal.h>
 
 #include <asm/pvclock.h>
 #include <asm/xen/hypervisor.h>
 #define TIMER_SLOP     100000
 #define NS_PER_TICK    (1000000000LL / HZ)
 
-/* runstate info updated by Xen */
-static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate);
-
 /* snapshots of runstate info */
 static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate_snapshot);
 
 /* unused ns of stolen time */
 static DEFINE_PER_CPU(u64, xen_residual_stolen);
 
-/* return an consistent snapshot of 64-bit time/counter value */
-static u64 get64(const u64 *p)
-{
-       u64 ret;
-
-       if (BITS_PER_LONG < 64) {
-               u32 *p32 = (u32 *)p;
-               u32 h, l;
-
-               /*
-                * Read high then low, and then make sure high is
-                * still the same; this will only loop if low wraps
-                * and carries into high.
-                * XXX some clean way to make this endian-proof?
-                */
-               do {
-                       h = p32[1];
-                       barrier();
-                       l = p32[0];
-                       barrier();
-               } while (p32[1] != h);
-
-               ret = (((u64)h) << 32) | l;
-       } else
-               ret = *p;
-
-       return ret;
-}
-
-/*
- * Runstate accounting
- */
-static void get_runstate_snapshot(struct vcpu_runstate_info *res)
-{
-       u64 state_time;
-       struct vcpu_runstate_info *state;
-
-       BUG_ON(preemptible());
-
-       state = this_cpu_ptr(&xen_runstate);
-
-       /*
-        * The runstate info is always updated by the hypervisor on
-        * the current CPU, so there's no need to use anything
-        * stronger than a compiler barrier when fetching it.
-        */
-       do {
-               state_time = get64(&state->state_entry_time);
-               barrier();
-               *res = *state;
-               barrier();
-       } while (get64(&state->state_entry_time) != state_time);
-}
-
-/* return true when a vcpu could run but has no real cpu to run on */
-bool xen_vcpu_stolen(int vcpu)
-{
-       return per_cpu(xen_runstate, vcpu).state == RUNSTATE_runnable;
-}
-
-void xen_setup_runstate_info(int cpu)
-{
-       struct vcpu_register_runstate_memory_area area;
-
-       area.addr.v = &per_cpu(xen_runstate, cpu);
-
-       if (HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area,
-                              cpu, &area))
-               BUG();
-}
-
 static void do_stolen_accounting(void)
 {
        struct vcpu_runstate_info state;
@@ -119,7 +46,7 @@ static void do_stolen_accounting(void)
        s64 runnable, offline, stolen;
        cputime_t ticks;
 
-       get_runstate_snapshot(&state);
+       xen_get_runstate_snapshot(&state);
 
        WARN_ON(state.state != RUNSTATE_running);
 
@@ -194,26 +121,46 @@ static int xen_pvclock_gtod_notify(struct notifier_block *nb,
                                   unsigned long was_set, void *priv)
 {
        /* Protected by the calling core code serialization */
-       static struct timespec next_sync;
+       static struct timespec64 next_sync;
 
        struct xen_platform_op op;
-       struct timespec now;
+       struct timespec64 now;
+       struct timekeeper *tk = priv;
+       static bool settime64_supported = true;
+       int ret;
 
-       now = __current_kernel_time();
+       now.tv_sec = tk->xtime_sec;
+       now.tv_nsec = (long)(tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift);
 
        /*
         * We only take the expensive HV call when the clock was set
         * or when the 11 minutes RTC synchronization time elapsed.
         */
-       if (!was_set && timespec_compare(&now, &next_sync) < 0)
+       if (!was_set && timespec64_compare(&now, &next_sync) < 0)
                return NOTIFY_OK;
 
-       op.cmd = XENPF_settime;
-       op.u.settime.secs = now.tv_sec;
-       op.u.settime.nsecs = now.tv_nsec;
-       op.u.settime.system_time = xen_clocksource_read();
+again:
+       if (settime64_supported) {
+               op.cmd = XENPF_settime64;
+               op.u.settime64.mbz = 0;
+               op.u.settime64.secs = now.tv_sec;
+               op.u.settime64.nsecs = now.tv_nsec;
+               op.u.settime64.system_time = xen_clocksource_read();
+       } else {
+               op.cmd = XENPF_settime32;
+               op.u.settime32.secs = now.tv_sec;
+               op.u.settime32.nsecs = now.tv_nsec;
+               op.u.settime32.system_time = xen_clocksource_read();
+       }
+
+       ret = HYPERVISOR_platform_op(&op);
 
-       (void)HYPERVISOR_dom0_op(&op);
+       if (ret == -ENOSYS && settime64_supported) {
+               settime64_supported = false;
+               goto again;
+       }
+       if (ret < 0)
+               return NOTIFY_BAD;
 
        /*
         * Move the next drift compensation time 11 minutes
index fd92a64d748e1ca1a3838fe3c26f977f41a8b984..feb6d40a0860f450d5e2c29f2920a139c98794f8 100644 (file)
@@ -34,20 +34,6 @@ check_events:
        pop %eax
        ret
 
-/*
- * We can't use sysexit directly, because we're not running in ring0.
- * But we can easily fake it up using iret.  Assuming xen_sysexit is
- * jumped to with a standard stack frame, we can just strip it back to
- * a standard iret frame and use iret.
- */
-ENTRY(xen_sysexit)
-       movl PT_EAX(%esp), %eax                 /* Shouldn't be necessary? */
-       orl $X86_EFLAGS_IF, PT_EFLAGS(%esp)
-       lea PT_EIP(%esp), %esp
-
-       jmp xen_iret
-ENDPROC(xen_sysexit)
-
 /*
  * This is run where a normal iret would be run, with the same stack setup:
  *     8: eflags
index f22667abf7b9d54d475edd08ffcdac8ba79b4cf3..cc8acc410ddb81d9c3a86b87c0b11f96b29c4bb4 100644 (file)
@@ -68,25 +68,6 @@ ENTRY(xen_sysret64)
 ENDPATCH(xen_sysret64)
 RELOC(xen_sysret64, 1b+1)
 
-ENTRY(xen_sysret32)
-       /*
-        * We're already on the usermode stack at this point, but
-        * still with the kernel gs, so we can easily switch back
-        */
-       movq %rsp, PER_CPU_VAR(rsp_scratch)
-       movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
-
-       pushq $__USER32_DS
-       pushq PER_CPU_VAR(rsp_scratch)
-       pushq %r11
-       pushq $__USER32_CS
-       pushq %rcx
-
-       pushq $0
-1:     jmp hypercall_iret
-ENDPATCH(xen_sysret32)
-RELOC(xen_sysret32, 1b+1)
-
 /*
  * Xen handles syscall callbacks much like ordinary exceptions, which
  * means we have:
index 1399423f34183dc3bb899180e264a1198dc93192..4140b070f2e991e1b56152056ae78be9f2899244 100644 (file)
@@ -139,9 +139,6 @@ DECL_ASM(void, xen_restore_fl_direct, unsigned long);
 
 /* These are not functions, and cannot be called normally */
 __visible void xen_iret(void);
-#ifdef CONFIG_X86_32
-__visible void xen_sysexit(void);
-#endif
 __visible void xen_sysret32(void);
 __visible void xen_sysret64(void);
 __visible void xen_adjust_exception_frame(void);
index c487b94c59e3052074f5e40c99680d0cb709b517..33e2f62d50622ea8b40153175d0f44d96df399a6 100644 (file)
@@ -206,6 +206,22 @@ void blk_delay_queue(struct request_queue *q, unsigned long msecs)
 }
 EXPORT_SYMBOL(blk_delay_queue);
 
+/**
+ * blk_start_queue_async - asynchronously restart a previously stopped queue
+ * @q:    The &struct request_queue in question
+ *
+ * Description:
+ *   blk_start_queue_async() will clear the stop flag on the queue, and
+ *   ensure that the request_fn for the queue is run from an async
+ *   context.
+ **/
+void blk_start_queue_async(struct request_queue *q)
+{
+       queue_flag_clear(QUEUE_FLAG_STOPPED, q);
+       blk_run_queue_async(q);
+}
+EXPORT_SYMBOL(blk_start_queue_async);
+
 /**
  * blk_start_queue - restart a previously stopped queue
  * @q:    The &struct request_queue in question
index ca9efe17db1ac4e9e2806528ea28d2d87a954b8f..634b4d1ab6817d56343d5b8b24b29cd34de422d1 100644 (file)
@@ -47,7 +47,7 @@ struct skcipher_ctx {
        bool merge;
        bool enc;
 
-       struct ablkcipher_request req;
+       struct skcipher_request req;
 };
 
 struct skcipher_async_rsgl {
@@ -64,13 +64,13 @@ struct skcipher_async_req {
 };
 
 #define GET_SREQ(areq, ctx) (struct skcipher_async_req *)((char *)areq + \
-       crypto_ablkcipher_reqsize(crypto_ablkcipher_reqtfm(&ctx->req)))
+       crypto_skcipher_reqsize(crypto_skcipher_reqtfm(&ctx->req)))
 
 #define GET_REQ_SIZE(ctx) \
-       crypto_ablkcipher_reqsize(crypto_ablkcipher_reqtfm(&ctx->req))
+       crypto_skcipher_reqsize(crypto_skcipher_reqtfm(&ctx->req))
 
 #define GET_IV_SIZE(ctx) \
-       crypto_ablkcipher_ivsize(crypto_ablkcipher_reqtfm(&ctx->req))
+       crypto_skcipher_ivsize(crypto_skcipher_reqtfm(&ctx->req))
 
 #define MAX_SGL_ENTS ((4096 - sizeof(struct skcipher_sg_list)) / \
                      sizeof(struct scatterlist) - 1)
@@ -302,8 +302,8 @@ static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg,
        struct sock *sk = sock->sk;
        struct alg_sock *ask = alg_sk(sk);
        struct skcipher_ctx *ctx = ask->private;
-       struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(&ctx->req);
-       unsigned ivsize = crypto_ablkcipher_ivsize(tfm);
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(&ctx->req);
+       unsigned ivsize = crypto_skcipher_ivsize(tfm);
        struct skcipher_sg_list *sgl;
        struct af_alg_control con = {};
        long copied = 0;
@@ -507,7 +507,7 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg,
        struct skcipher_sg_list *sgl;
        struct scatterlist *sg;
        struct skcipher_async_req *sreq;
-       struct ablkcipher_request *req;
+       struct skcipher_request *req;
        struct skcipher_async_rsgl *last_rsgl = NULL;
        unsigned int txbufs = 0, len = 0, tx_nents = skcipher_all_sg_nents(ctx);
        unsigned int reqlen = sizeof(struct skcipher_async_req) +
@@ -531,9 +531,9 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg,
        }
        sg_init_table(sreq->tsg, tx_nents);
        memcpy(sreq->iv, ctx->iv, GET_IV_SIZE(ctx));
-       ablkcipher_request_set_tfm(req, crypto_ablkcipher_reqtfm(&ctx->req));
-       ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
-                                       skcipher_async_cb, sk);
+       skcipher_request_set_tfm(req, crypto_skcipher_reqtfm(&ctx->req));
+       skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+                                     skcipher_async_cb, sk);
 
        while (iov_iter_count(&msg->msg_iter)) {
                struct skcipher_async_rsgl *rsgl;
@@ -608,10 +608,10 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg,
        if (mark)
                sg_mark_end(sreq->tsg + txbufs - 1);
 
-       ablkcipher_request_set_crypt(req, sreq->tsg, sreq->first_sgl.sgl.sg,
-                                    len, sreq->iv);
-       err = ctx->enc ? crypto_ablkcipher_encrypt(req) :
-                        crypto_ablkcipher_decrypt(req);
+       skcipher_request_set_crypt(req, sreq->tsg, sreq->first_sgl.sgl.sg,
+                                  len, sreq->iv);
+       err = ctx->enc ? crypto_skcipher_encrypt(req) :
+                        crypto_skcipher_decrypt(req);
        if (err == -EINPROGRESS) {
                atomic_inc(&ctx->inflight);
                err = -EIOCBQUEUED;
@@ -632,7 +632,7 @@ static int skcipher_recvmsg_sync(struct socket *sock, struct msghdr *msg,
        struct sock *sk = sock->sk;
        struct alg_sock *ask = alg_sk(sk);
        struct skcipher_ctx *ctx = ask->private;
-       unsigned bs = crypto_ablkcipher_blocksize(crypto_ablkcipher_reqtfm(
+       unsigned bs = crypto_skcipher_blocksize(crypto_skcipher_reqtfm(
                &ctx->req));
        struct skcipher_sg_list *sgl;
        struct scatterlist *sg;
@@ -669,14 +669,13 @@ static int skcipher_recvmsg_sync(struct socket *sock, struct msghdr *msg,
                if (!used)
                        goto free;
 
-               ablkcipher_request_set_crypt(&ctx->req, sg,
-                                            ctx->rsgl.sg, used,
-                                            ctx->iv);
+               skcipher_request_set_crypt(&ctx->req, sg, ctx->rsgl.sg, used,
+                                          ctx->iv);
 
                err = af_alg_wait_for_completion(
                                ctx->enc ?
-                                       crypto_ablkcipher_encrypt(&ctx->req) :
-                                       crypto_ablkcipher_decrypt(&ctx->req),
+                                       crypto_skcipher_encrypt(&ctx->req) :
+                                       crypto_skcipher_decrypt(&ctx->req),
                                &ctx->completion);
 
 free:
@@ -751,17 +750,17 @@ static struct proto_ops algif_skcipher_ops = {
 
 static void *skcipher_bind(const char *name, u32 type, u32 mask)
 {
-       return crypto_alloc_ablkcipher(name, type, mask);
+       return crypto_alloc_skcipher(name, type, mask);
 }
 
 static void skcipher_release(void *private)
 {
-       crypto_free_ablkcipher(private);
+       crypto_free_skcipher(private);
 }
 
 static int skcipher_setkey(void *private, const u8 *key, unsigned int keylen)
 {
-       return crypto_ablkcipher_setkey(private, key, keylen);
+       return crypto_skcipher_setkey(private, key, keylen);
 }
 
 static void skcipher_wait(struct sock *sk)
@@ -778,13 +777,13 @@ static void skcipher_sock_destruct(struct sock *sk)
 {
        struct alg_sock *ask = alg_sk(sk);
        struct skcipher_ctx *ctx = ask->private;
-       struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(&ctx->req);
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(&ctx->req);
 
        if (atomic_read(&ctx->inflight))
                skcipher_wait(sk);
 
        skcipher_free_sgl(sk);
-       sock_kzfree_s(sk, ctx->iv, crypto_ablkcipher_ivsize(tfm));
+       sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm));
        sock_kfree_s(sk, ctx, ctx->len);
        af_alg_release_parent(sk);
 }
@@ -793,20 +792,20 @@ static int skcipher_accept_parent(void *private, struct sock *sk)
 {
        struct skcipher_ctx *ctx;
        struct alg_sock *ask = alg_sk(sk);
-       unsigned int len = sizeof(*ctx) + crypto_ablkcipher_reqsize(private);
+       unsigned int len = sizeof(*ctx) + crypto_skcipher_reqsize(private);
 
        ctx = sock_kmalloc(sk, len, GFP_KERNEL);
        if (!ctx)
                return -ENOMEM;
 
-       ctx->iv = sock_kmalloc(sk, crypto_ablkcipher_ivsize(private),
+       ctx->iv = sock_kmalloc(sk, crypto_skcipher_ivsize(private),
                               GFP_KERNEL);
        if (!ctx->iv) {
                sock_kfree_s(sk, ctx, len);
                return -ENOMEM;
        }
 
-       memset(ctx->iv, 0, crypto_ablkcipher_ivsize(private));
+       memset(ctx->iv, 0, crypto_skcipher_ivsize(private));
 
        INIT_LIST_HEAD(&ctx->tsgl);
        ctx->len = len;
@@ -819,9 +818,9 @@ static int skcipher_accept_parent(void *private, struct sock *sk)
 
        ask->private = ctx;
 
-       ablkcipher_request_set_tfm(&ctx->req, private);
-       ablkcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
-                                       af_alg_complete, &ctx->completion);
+       skcipher_request_set_tfm(&ctx->req, private);
+       skcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+                                     af_alg_complete, &ctx->completion);
 
        sk->sk_destruct = skcipher_sock_destruct;
 
index f8c0b8dbeb7582beca1ee7fd5c7aaac58aba23cd..88bc8e6b2a545b9667f3d5fb390854a19f0be778 100644 (file)
@@ -53,7 +53,7 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
        struct dmaengine_unmap_data *unmap = NULL;
 
        if (device)
-               unmap = dmaengine_get_unmap_data(device->dev, 2, GFP_NOIO);
+               unmap = dmaengine_get_unmap_data(device->dev, 2, GFP_NOWAIT);
 
        if (unmap && is_dma_copy_aligned(device, src_offset, dest_offset, len)) {
                unsigned long dma_prep_flags = 0;
index 5d355e0c263339b5bd179ad61aad63c9b7efb3a3..c0748bbd4c083b47f78c662cdd7cb490590a2587 100644 (file)
@@ -188,7 +188,7 @@ async_gen_syndrome(struct page **blocks, unsigned int offset, int disks,
        BUG_ON(disks > 255 || !(P(blocks, disks) || Q(blocks, disks)));
 
        if (device)
-               unmap = dmaengine_get_unmap_data(device->dev, disks, GFP_NOIO);
+               unmap = dmaengine_get_unmap_data(device->dev, disks, GFP_NOWAIT);
 
        /* XORing P/Q is only implemented in software */
        if (unmap && !(submit->flags & ASYNC_TX_PQ_XOR_DST) &&
@@ -307,7 +307,7 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks,
        BUG_ON(disks < 4);
 
        if (device)
-               unmap = dmaengine_get_unmap_data(device->dev, disks, GFP_NOIO);
+               unmap = dmaengine_get_unmap_data(device->dev, disks, GFP_NOWAIT);
 
        if (unmap && disks <= dma_maxpq(device, 0) &&
            is_dma_pq_aligned(device, offset, 0, len)) {
index 934a849814958e6ea37b9dbdb96abc820c4fe9e1..8fab6275ea1facaae8730a8f676f2578c792e7c3 100644 (file)
@@ -41,7 +41,7 @@ async_sum_product(struct page *dest, struct page **srcs, unsigned char *coef,
        u8 *a, *b, *c;
 
        if (dma)
-               unmap = dmaengine_get_unmap_data(dma->dev, 3, GFP_NOIO);
+               unmap = dmaengine_get_unmap_data(dma->dev, 3, GFP_NOWAIT);
 
        if (unmap) {
                struct device *dev = dma->dev;
@@ -105,7 +105,7 @@ async_mult(struct page *dest, struct page *src, u8 coef, size_t len,
        u8 *d, *s;
 
        if (dma)
-               unmap = dmaengine_get_unmap_data(dma->dev, 3, GFP_NOIO);
+               unmap = dmaengine_get_unmap_data(dma->dev, 3, GFP_NOWAIT);
 
        if (unmap) {
                dma_addr_t dma_dest[2];
index e1bce26cd4f9098f2765ffbf0f8e2f00017a9219..da75777f2b3f04f09a3fc025da9e38102b2211e8 100644 (file)
@@ -182,7 +182,7 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset,
        BUG_ON(src_cnt <= 1);
 
        if (device)
-               unmap = dmaengine_get_unmap_data(device->dev, src_cnt+1, GFP_NOIO);
+               unmap = dmaengine_get_unmap_data(device->dev, src_cnt+1, GFP_NOWAIT);
 
        if (unmap && is_dma_xor_aligned(device, offset, 0, len)) {
                struct dma_async_tx_descriptor *tx;
@@ -278,7 +278,7 @@ async_xor_val(struct page *dest, struct page **src_list, unsigned int offset,
        BUG_ON(src_cnt <= 1);
 
        if (device)
-               unmap = dmaengine_get_unmap_data(device->dev, src_cnt, GFP_NOIO);
+               unmap = dmaengine_get_unmap_data(device->dev, src_cnt, GFP_NOWAIT);
 
        if (unmap && src_cnt <= device->max_xor &&
            is_dma_xor_aligned(device, offset, 0, len)) {
index 707cf6213bc2888b4cc1e09a0f851d232b9521c0..b9afb47db7ed98f23f140cd24433682b82d2274f 100644 (file)
@@ -104,7 +104,7 @@ static void acpi_expose_nondev_subnodes(struct kobject *kobj,
 
                init_completion(&dn->kobj_done);
                ret = kobject_init_and_add(&dn->kobj, &acpi_data_node_ktype,
-                                          kobj, dn->name);
+                                          kobj, "%s", dn->name);
                if (ret)
                        acpi_handle_err(dn->handle, "Failed to expose (%d)\n", ret);
                else
index 6aaa3f81755be2e4917decb14c8f52348efeb0d0..861643ea91b5b5c1d13d4b01a5311e2dcd6171ec 100644 (file)
@@ -100,7 +100,7 @@ config SATA_AHCI_PLATFORM
 
 config AHCI_BRCMSTB
        tristate "Broadcom STB AHCI SATA support"
-       depends on ARCH_BRCMSTB
+       depends on ARCH_BRCMSTB || BMIPS_GENERIC
        help
          This option enables support for the AHCI SATA3 controller found on
          STB SoC's.
index cdfbcc54821fd6ea3a5dd6a11c969f12055c7e24..594fcabd22cd16bfcc09626338a3da33481497cc 100644 (file)
@@ -1306,15 +1306,13 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
 #endif
 
 /*
- * ahci_init_msix() only implements single MSI-X support, not multiple
- * MSI-X per-port interrupts. This is needed for host controllers that only
- * have MSI-X support implemented, but no MSI or intx.
+ * ahci_init_msix() - optionally enable per-port MSI-X otherwise defer
+ * to single msi.
  */
 static int ahci_init_msix(struct pci_dev *pdev, unsigned int n_ports,
-                         struct ahci_host_priv *hpriv)
+                         struct ahci_host_priv *hpriv, unsigned long flags)
 {
-       int rc, nvec;
-       struct msix_entry entry = {};
+       int nvec, i, rc;
 
        /* Do not init MSI-X if MSI is disabled for the device */
        if (hpriv->flags & AHCI_HFLAG_NO_MSI)
@@ -1324,22 +1322,39 @@ static int ahci_init_msix(struct pci_dev *pdev, unsigned int n_ports,
        if (nvec < 0)
                return nvec;
 
-       if (!nvec) {
+       /*
+        * Proper MSI-X implementations will have a vector per-port.
+        * Barring that, we prefer single-MSI over single-MSIX.  If this
+        * check fails (not enough MSI-X vectors for all ports) we will
+        * be called again with the flag clear iff ahci_init_msi()
+        * fails.
+        */
+       if (flags & AHCI_HFLAG_MULTI_MSIX) {
+               if (nvec < n_ports)
+                       return -ENODEV;
+               nvec = n_ports;
+       } else if (nvec) {
+               nvec = 1;
+       } else {
+               /*
+                * Emit dev_err() since this was the non-legacy irq
+                * method of last resort.
+                */
                rc = -ENODEV;
                goto fail;
        }
 
-       /*
-        * There can be more than one vector (e.g. for error detection or
-        * hdd hotplug). Only the first vector (entry.entry = 0) is used.
-        */
-       rc = pci_enable_msix_exact(pdev, &entry, 1);
+       for (i = 0; i < nvec; i++)
+               hpriv->msix[i].entry = i;
+       rc = pci_enable_msix_exact(pdev, hpriv->msix, nvec);
        if (rc < 0)
                goto fail;
 
-       hpriv->irq = entry.vector;
+       if (nvec > 1)
+               hpriv->flags |= AHCI_HFLAG_MULTI_MSIX;
+       hpriv->irq = hpriv->msix[0].vector; /* for single msi-x */
 
-       return 1;
+       return nvec;
 fail:
        dev_err(&pdev->dev,
                "failed to enable MSI-X with error %d, # of vectors: %d\n",
@@ -1403,20 +1418,25 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
 {
        int nvec;
 
+       /*
+        * Try to enable per-port MSI-X.  If the host is not capable
+        * fall back to single MSI before finally attempting single
+        * MSI-X.
+        */
+       nvec = ahci_init_msix(pdev, n_ports, hpriv, AHCI_HFLAG_MULTI_MSIX);
+       if (nvec >= 0)
+               return nvec;
+
        nvec = ahci_init_msi(pdev, n_ports, hpriv);
        if (nvec >= 0)
                return nvec;
 
-       /*
-        * Currently, MSI-X support only implements single IRQ mode and
-        * exists for controllers which can't do other types of IRQ. Only
-        * set it up if MSI fails.
-        */
-       nvec = ahci_init_msix(pdev, n_ports, hpriv);
+       /* try single-msix */
+       nvec = ahci_init_msix(pdev, n_ports, hpriv, 0);
        if (nvec >= 0)
                return nvec;
 
-       /* lagacy intx interrupts */
+       /* legacy intx interrupts */
        pci_intx(pdev, 1);
        hpriv->irq = pdev->irq;
 
@@ -1578,7 +1598,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!host)
                return -ENOMEM;
        host->private_data = hpriv;
-
+       hpriv->msix = devm_kzalloc(&pdev->dev,
+                       sizeof(struct msix_entry) * n_ports, GFP_KERNEL);
+       if (!hpriv->msix)
+               return -ENOMEM;
        ahci_init_interrupts(pdev, n_ports, hpriv);
 
        if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
index 45586c1dbbdc1e225947c09e200bf5b2c2296a15..a4faa438889c075070084fb1f1cd943d61082a88 100644 (file)
@@ -35,6 +35,7 @@
 #ifndef _AHCI_H
 #define _AHCI_H
 
+#include <linux/pci.h>
 #include <linux/clk.h>
 #include <linux/libata.h>
 #include <linux/phy/phy.h>
@@ -237,11 +238,18 @@ enum {
        AHCI_HFLAG_DELAY_ENGINE         = (1 << 15), /* do not start engine on
                                                        port start (wait until
                                                        error-handling stage) */
-       AHCI_HFLAG_MULTI_MSI            = (1 << 16), /* multiple PCI MSIs */
        AHCI_HFLAG_NO_DEVSLP            = (1 << 17), /* no device sleep */
        AHCI_HFLAG_NO_FBS               = (1 << 18), /* no FBS */
        AHCI_HFLAG_EDGE_IRQ             = (1 << 19), /* HOST_IRQ_STAT behaves as
                                                        Edge Triggered */
+#ifdef CONFIG_PCI_MSI
+       AHCI_HFLAG_MULTI_MSI            = (1 << 20), /* multiple PCI MSIs */
+       AHCI_HFLAG_MULTI_MSIX           = (1 << 21), /* per-port MSI-X */
+#else
+       /* compile out MSI infrastructure */
+       AHCI_HFLAG_MULTI_MSI            = 0,
+       AHCI_HFLAG_MULTI_MSIX           = 0,
+#endif
 
        /* ap->flags bits */
 
@@ -308,7 +316,6 @@ struct ahci_port_priv {
        unsigned int            ncq_saw_d2h:1;
        unsigned int            ncq_saw_dmas:1;
        unsigned int            ncq_saw_sdb:1;
-       atomic_t                intr_status;    /* interrupts to handle */
        spinlock_t              lock;           /* protects parent ata_port */
        u32                     intr_mask;      /* interrupts to enable */
        bool                    fbs_supported;  /* set iff FBS is supported */
@@ -343,6 +350,7 @@ struct ahci_host_priv {
         * the PHY position in this array.
         */
        struct phy              **phys;
+       struct msix_entry       *msix;          /* Optional MSI-X support */
        unsigned                nports;         /* Number of ports */
        void                    *plat_data;     /* Other platform data */
        unsigned int            irq;            /* interrupt line */
@@ -354,6 +362,21 @@ struct ahci_host_priv {
        void                    (*start_engine)(struct ata_port *ap);
 };
 
+#ifdef CONFIG_PCI_MSI
+static inline int ahci_irq_vector(struct ahci_host_priv *hpriv, int port)
+{
+       if (hpriv->flags & AHCI_HFLAG_MULTI_MSIX)
+               return hpriv->msix[port].vector;
+       else
+               return hpriv->irq + port;
+}
+#else
+static inline int ahci_irq_vector(struct ahci_host_priv *hpriv, int port)
+{
+       return hpriv->irq;
+}
+#endif
+
 extern int ahci_ignore_sss;
 
 extern struct device_attribute *ahci_shost_attrs[];
index 14b7305d2ba0b3cc24aa101e76c87e242f01f537..b36cae2fd04b2b2969cfefcfe54f63beadef48e2 100644 (file)
   #define SATA_TOP_CTRL_2_PHY_GLOBAL_RESET             BIT(14)
  #define SATA_TOP_CTRL_PHY_OFFS                                0x8
  #define SATA_TOP_MAX_PHYS                             2
-#define SATA_TOP_CTRL_SATA_TP_OUT                      0x1c
-#define SATA_TOP_CTRL_CLIENT_INIT_CTRL                 0x20
+
+#define SATA_FIRST_PORT_CTRL                           0x700
+#define SATA_NEXT_PORT_CTRL_OFFSET                     0x80
+#define SATA_PORT_PCTRL6(reg_base)                     (reg_base + 0x18)
 
 /* On big-endian MIPS, buses are reversed to big endian, so switch them back */
 #if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN)
        (DATA_ENDIAN << DMADESC_ENDIAN_SHIFT) |         \
        (MMIO_ENDIAN << MMIO_ENDIAN_SHIFT))
 
+enum brcm_ahci_quirks {
+       BRCM_AHCI_QUIRK_NO_NCQ          = BIT(0),
+       BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE = BIT(1),
+};
+
 struct brcm_ahci_priv {
        struct device *dev;
        void __iomem *top_ctrl;
        u32 port_mask;
+       u32 quirks;
 };
 
 static const struct ata_port_info ahci_brcm_port_info = {
-       .flags          = AHCI_FLAG_COMMON,
+       .flags          = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM,
+       .link_flags     = ATA_LFLAG_NO_DB_DELAY,
        .pio_mask       = ATA_PIO4,
        .udma_mask      = ATA_UDMA6,
        .port_ops       = &ahci_platform_ops,
@@ -107,6 +116,34 @@ static inline void brcm_sata_writereg(u32 val, void __iomem *addr)
                writel_relaxed(val, addr);
 }
 
+static void brcm_sata_alpm_init(struct ahci_host_priv *hpriv)
+{
+       struct brcm_ahci_priv *priv = hpriv->plat_data;
+       u32 bus_ctrl, port_ctrl, host_caps;
+       int i;
+
+       /* Enable support for ALPM */
+       bus_ctrl = brcm_sata_readreg(priv->top_ctrl +
+                                    SATA_TOP_CTRL_BUS_CTRL);
+       brcm_sata_writereg(bus_ctrl | OVERRIDE_HWINIT,
+                          priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL);
+       host_caps = readl(hpriv->mmio + HOST_CAP);
+       writel(host_caps | HOST_CAP_ALPM, hpriv->mmio);
+       brcm_sata_writereg(bus_ctrl, priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL);
+
+       /*
+        * Adjust timeout to allow PLL sufficient time to lock while waking
+        * up from slumber mode.
+        */
+       for (i = 0, port_ctrl = SATA_FIRST_PORT_CTRL;
+            i < SATA_TOP_MAX_PHYS;
+            i++, port_ctrl += SATA_NEXT_PORT_CTRL_OFFSET) {
+               if (priv->port_mask & BIT(i))
+                       writel(0xff1003fc,
+                              hpriv->mmio + SATA_PORT_PCTRL6(port_ctrl));
+       }
+}
+
 static void brcm_sata_phy_enable(struct brcm_ahci_priv *priv, int port)
 {
        void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL +
@@ -114,6 +151,9 @@ static void brcm_sata_phy_enable(struct brcm_ahci_priv *priv, int port)
        void __iomem *p;
        u32 reg;
 
+       if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE)
+               return;
+
        /* clear PHY_DEFAULT_POWER_STATE */
        p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1;
        reg = brcm_sata_readreg(p);
@@ -143,6 +183,9 @@ static void brcm_sata_phy_disable(struct brcm_ahci_priv *priv, int port)
        void __iomem *p;
        u32 reg;
 
+       if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE)
+               return;
+
        /* power-off the PHY digital logic */
        p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2;
        reg = brcm_sata_readreg(p);
@@ -230,6 +273,7 @@ static int brcm_ahci_resume(struct device *dev)
 
        brcm_sata_init(priv);
        brcm_sata_phys_enable(priv);
+       brcm_sata_alpm_init(hpriv);
        return ahci_platform_resume(dev);
 }
 #endif
@@ -256,6 +300,11 @@ static int brcm_ahci_probe(struct platform_device *pdev)
        if (IS_ERR(priv->top_ctrl))
                return PTR_ERR(priv->top_ctrl);
 
+       if (of_device_is_compatible(dev->of_node, "brcm,bcm7425-ahci")) {
+               priv->quirks |= BRCM_AHCI_QUIRK_NO_NCQ;
+               priv->quirks |= BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE;
+       }
+
        brcm_sata_init(priv);
 
        priv->port_mask = brcm_ahci_get_portmask(pdev, priv);
@@ -269,10 +318,15 @@ static int brcm_ahci_probe(struct platform_device *pdev)
                return PTR_ERR(hpriv);
        hpriv->plat_data = priv;
 
+       brcm_sata_alpm_init(hpriv);
+
        ret = ahci_platform_enable_resources(hpriv);
        if (ret)
                return ret;
 
+       if (priv->quirks & BRCM_AHCI_QUIRK_NO_NCQ)
+               hpriv->flags |= AHCI_HFLAG_NO_NCQ;
+
        ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info,
                                      &ahci_platform_sht);
        if (ret)
@@ -300,6 +354,7 @@ static int brcm_ahci_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id ahci_of_match[] = {
+       {.compatible = "brcm,bcm7425-ahci"},
        {.compatible = "brcm,bcm7445-ahci"},
        {},
 };
index d0f9de96e4ea626a44b30506b239105869fb2eb5..7bdee9bd8786638049c51d952520f2fe298df694 100644 (file)
 
 /* port register default value */
 #define AHCI_PORT_PHY_1_CFG    0xa003fffe
-#define AHCI_PORT_PHY_2_CFG    0x28183411
-#define AHCI_PORT_PHY_3_CFG    0x0e081004
-#define AHCI_PORT_PHY_4_CFG    0x00480811
-#define AHCI_PORT_PHY_5_CFG    0x192c96a4
-#define AHCI_PORT_TRANS_CFG    0x08000025
+#define AHCI_PORT_TRANS_CFG    0x08000029
+
+/* for ls1021a */
+#define LS1021A_PORT_PHY2      0x28183414
+#define LS1021A_PORT_PHY3      0x0e080e06
+#define LS1021A_PORT_PHY4      0x064a080b
+#define LS1021A_PORT_PHY5      0x2aa86470
 
 #define SATA_ECC_DISABLE       0x00020000
 
+/* for ls1043a */
+#define LS1043A_PORT_PHY2      0x28184d1f
+#define LS1043A_PORT_PHY3      0x0e081509
+
 enum ahci_qoriq_type {
        AHCI_LS1021A,
        AHCI_LS1043A,
@@ -151,16 +157,23 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
        case AHCI_LS1021A:
                writel(SATA_ECC_DISABLE, qpriv->ecc_addr);
                writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
-               writel(AHCI_PORT_PHY_2_CFG, reg_base + PORT_PHY2);
-               writel(AHCI_PORT_PHY_3_CFG, reg_base + PORT_PHY3);
-               writel(AHCI_PORT_PHY_4_CFG, reg_base + PORT_PHY4);
-               writel(AHCI_PORT_PHY_5_CFG, reg_base + PORT_PHY5);
+               writel(LS1021A_PORT_PHY2, reg_base + PORT_PHY2);
+               writel(LS1021A_PORT_PHY3, reg_base + PORT_PHY3);
+               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);
                break;
 
        case AHCI_LS1043A:
+               writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
+               writel(LS1043A_PORT_PHY2, reg_base + PORT_PHY2);
+               writel(LS1043A_PORT_PHY3, reg_base + PORT_PHY3);
+               writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
+               break;
+
        case AHCI_LS2080A:
                writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
+               writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
                break;
        }
 
index 4665512dae44d99e9a5af194812094498d5888cf..d61740e78d6dc93a1b17d9e3c9d9425067190a21 100644 (file)
@@ -43,6 +43,7 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_cmnd.h>
 #include <linux/libata.h>
+#include <linux/pci.h>
 #include "ahci.h"
 #include "libata.h"
 
@@ -1804,41 +1805,24 @@ static void ahci_port_intr(struct ata_port *ap)
        ahci_handle_port_interrupt(ap, port_mmio, status);
 }
 
-static irqreturn_t ahci_port_thread_fn(int irq, void *dev_instance)
+static irqreturn_t ahci_multi_irqs_intr_hard(int irq, void *dev_instance)
 {
        struct ata_port *ap = dev_instance;
-       struct ahci_port_priv *pp = ap->private_data;
        void __iomem *port_mmio = ahci_port_base(ap);
        u32 status;
 
-       status = atomic_xchg(&pp->intr_status, 0);
-       if (!status)
-               return IRQ_NONE;
-
-       spin_lock_bh(ap->lock);
-       ahci_handle_port_interrupt(ap, port_mmio, status);
-       spin_unlock_bh(ap->lock);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance)
-{
-       struct ata_port *ap = dev_instance;
-       void __iomem *port_mmio = ahci_port_base(ap);
-       struct ahci_port_priv *pp = ap->private_data;
-       u32 status;
-
        VPRINTK("ENTER\n");
 
        status = readl(port_mmio + PORT_IRQ_STAT);
        writel(status, port_mmio + PORT_IRQ_STAT);
 
-       atomic_or(status, &pp->intr_status);
+       spin_lock(ap->lock);
+       ahci_handle_port_interrupt(ap, port_mmio, status);
+       spin_unlock(ap->lock);
 
        VPRINTK("EXIT\n");
 
-       return IRQ_WAKE_THREAD;
+       return IRQ_HANDLED;
 }
 
 static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
@@ -2479,9 +2463,10 @@ void ahci_set_em_messages(struct ahci_host_priv *hpriv,
 }
 EXPORT_SYMBOL_GPL(ahci_set_em_messages);
 
-static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq,
+static int ahci_host_activate_multi_irqs(struct ata_host *host,
                                         struct scsi_host_template *sht)
 {
+       struct ahci_host_priv *hpriv = host->private_data;
        int i, rc;
 
        rc = ata_host_start(host);
@@ -2493,6 +2478,7 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq,
         */
        for (i = 0; i < host->n_ports; i++) {
                struct ahci_port_priv *pp = host->ports[i]->private_data;
+               int irq = ahci_irq_vector(hpriv, i);
 
                /* Do not receive interrupts sent by dummy ports */
                if (!pp) {
@@ -2500,14 +2486,14 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq,
                        continue;
                }
 
-               rc = devm_request_threaded_irq(host->dev, irq + i,
-                                              ahci_multi_irqs_intr,
-                                              ahci_port_thread_fn, 0,
-                                              pp->irq_desc, host->ports[i]);
+               rc = devm_request_irq(host->dev, irq, ahci_multi_irqs_intr_hard,
+                               0, pp->irq_desc, host->ports[i]);
+
                if (rc)
                        return rc;
-               ata_port_desc(host->ports[i], "irq %d", irq + i);
+               ata_port_desc(host->ports[i], "irq %d", irq);
        }
+
        return ata_host_register(host, sht);
 }
 
@@ -2528,8 +2514,8 @@ int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht)
        int irq = hpriv->irq;
        int rc;
 
-       if (hpriv->flags & AHCI_HFLAG_MULTI_MSI)
-               rc = ahci_host_activate_multi_irqs(host, irq, sht);
+       if (hpriv->flags & (AHCI_HFLAG_MULTI_MSI | AHCI_HFLAG_MULTI_MSIX))
+               rc = ahci_host_activate_multi_irqs(host, sht);
        else if (hpriv->flags & AHCI_HFLAG_EDGE_IRQ)
                rc = ata_host_activate(host, irq, ahci_single_edge_irq_intr,
                                       IRQF_SHARED, sht);
index b79cb10e289e8a1eb52c2887b3e7c135952beb0f..cbb74719d2c1b80d61590ddf3fb2f9c71a31ce06 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/timer.h>
+#include <linux/time.h>
 #include <linux/interrupt.h>
 #include <linux/completion.h>
 #include <linux/suspend.h>
@@ -3597,7 +3598,8 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params,
                 * immediately after resuming.  Delay 200ms before
                 * debouncing.
                 */
-               ata_msleep(link->ap, 200);
+               if (!(link->flags & ATA_LFLAG_NO_DB_DELAY))
+                       ata_msleep(link->ap, 200);
 
                /* is SControl restored correctly? */
                if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
@@ -6223,6 +6225,7 @@ int ata_host_activate(struct ata_host *host, int irq,
                      struct scsi_host_template *sht)
 {
        int i, rc;
+       char *irq_desc;
 
        rc = ata_host_start(host);
        if (rc)
@@ -6234,8 +6237,14 @@ int ata_host_activate(struct ata_host *host, int irq,
                return ata_host_register(host, sht);
        }
 
+       irq_desc = devm_kasprintf(host->dev, GFP_KERNEL, "%s[%s]",
+                                 dev_driver_string(host->dev),
+                                 dev_name(host->dev));
+       if (!irq_desc)
+               return -ENOMEM;
+
        rc = devm_request_irq(host->dev, irq, irq_handler, irq_flags,
-                             dev_name(host->dev), host);
+                             irq_desc, host);
        if (rc)
                return rc;
 
@@ -6697,7 +6706,12 @@ void ata_msleep(struct ata_port *ap, unsigned int msecs)
        if (owns_eh)
                ata_eh_release(ap);
 
-       msleep(msecs);
+       if (msecs < 20) {
+               unsigned long usecs = msecs * USEC_PER_MSEC;
+               usleep_range(usecs, usecs + 50);
+       } else {
+               msleep(msecs);
+       }
 
        if (owns_eh)
                ata_eh_acquire(ap);
index 8804127b108c0f8e613f2583968f6b661a46be84..f72d601e300aa9f85aab64ba4a6d31d001ff075b 100644 (file)
@@ -854,17 +854,14 @@ static struct of_device_id sata_rcar_match[] = {
                .compatible = "renesas,sata-r8a7793",
                .data = (void *)RCAR_GEN2_SATA
        },
+       {
+               .compatible = "renesas,sata-r8a7795",
+               .data = (void *)RCAR_GEN2_SATA
+       },
        { },
 };
 MODULE_DEVICE_TABLE(of, sata_rcar_match);
 
-static const struct platform_device_id sata_rcar_id_table[] = {
-       { "sata_rcar", RCAR_GEN1_SATA }, /* Deprecated by "sata-r8a7779" */
-       { "sata-r8a7779", RCAR_GEN1_SATA },
-       { },
-};
-MODULE_DEVICE_TABLE(platform, sata_rcar_id_table);
-
 static int sata_rcar_probe(struct platform_device *pdev)
 {
        const struct of_device_id *of_id;
@@ -884,11 +881,10 @@ static int sata_rcar_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        of_id = of_match_device(sata_rcar_match, &pdev->dev);
-       if (of_id)
-               priv->type = (enum sata_rcar_type)of_id->data;
-       else
-               priv->type = platform_get_device_id(pdev)->driver_data;
+       if (!of_id)
+               return -ENODEV;
 
+       priv->type = (enum sata_rcar_type)of_id->data;
        priv->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(priv->clk)) {
                dev_err(&pdev->dev, "failed to get access to sata clock\n");
@@ -1018,7 +1014,6 @@ static const struct dev_pm_ops sata_rcar_pm_ops = {
 static struct platform_driver sata_rcar_driver = {
        .probe          = sata_rcar_probe,
        .remove         = sata_rcar_remove,
-       .id_table       = sata_rcar_id_table,
        .driver = {
                .name           = DRV_NAME,
                .of_match_table = sata_rcar_match,
index fab504fd9cfd7ace54d772927a01650373d02206..48301cb3a3165a189981764b6fea81a87cbdb858 100644 (file)
@@ -1396,6 +1396,8 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host)
                addr = 0;
                length = size * 1024 * 1024;
                buf = kzalloc(ECC_ERASE_BUF_SZ, GFP_KERNEL);
+               if (!buf)
+                       return 1;
                while (addr < length) {
                        pdc20621_put_to_dimm(host, buf, addr,
                                             ECC_ERASE_BUF_SZ);
index f748430bb654154918ae67984405021835f44ec8..89f5cf68d80a143198c2c253d6d21c0d9fb38388 100644 (file)
 #include <linux/mutex.h>
 #include <linux/slab.h>
 
+struct component;
+
+struct component_match_array {
+       void *data;
+       int (*compare)(struct device *, void *);
+       void (*release)(struct device *, void *);
+       struct component *component;
+       bool duplicate;
+};
+
 struct component_match {
        size_t alloc;
        size_t num;
-       struct {
-               void *data;
-               int (*fn)(struct device *, void *);
-       } compare[0];
+       struct component_match_array *compare;
 };
 
 struct master {
        struct list_head node;
-       struct list_head components;
        bool bound;
 
        const struct component_master_ops *ops;
@@ -39,7 +45,6 @@ struct master {
 
 struct component {
        struct list_head node;
-       struct list_head master_node;
        struct master *master;
        bool bound;
 
@@ -63,48 +68,21 @@ static struct master *__master_find(struct device *dev,
        return NULL;
 }
 
-/* Attach an unattached component to a master. */
-static void component_attach_master(struct master *master, struct component *c)
-{
-       c->master = master;
-
-       list_add_tail(&c->master_node, &master->components);
-}
-
-/* Detach a component from a master. */
-static void component_detach_master(struct master *master, struct component *c)
-{
-       list_del(&c->master_node);
-
-       c->master = NULL;
-}
-
-/*
- * Add a component to a master, finding the component via the compare
- * function and compare data.  This is safe to call for duplicate matches
- * and will not result in the same component being added multiple times.
- */
-int component_master_add_child(struct master *master,
+static struct component *find_component(struct master *master,
        int (*compare)(struct device *, void *), void *compare_data)
 {
        struct component *c;
-       int ret = -ENXIO;
 
        list_for_each_entry(c, &component_list, node) {
                if (c->master && c->master != master)
                        continue;
 
-               if (compare(c->dev, compare_data)) {
-                       if (!c->master)
-                               component_attach_master(master, c);
-                       ret = 0;
-                       break;
-               }
+               if (compare(c->dev, compare_data))
+                       return c;
        }
 
-       return ret;
+       return NULL;
 }
-EXPORT_SYMBOL_GPL(component_master_add_child);
 
 static int find_components(struct master *master)
 {
@@ -112,39 +90,44 @@ static int find_components(struct master *master)
        size_t i;
        int ret = 0;
 
-       if (!match) {
-               /*
-                * Search the list of components, looking for components that
-                * belong to this master, and attach them to the master.
-                */
-               return master->ops->add_components(master->dev, master);
-       }
-
        /*
         * Scan the array of match functions and attach
         * any components which are found to this master.
         */
        for (i = 0; i < match->num; i++) {
-               ret = component_master_add_child(master,
-                                                match->compare[i].fn,
-                                                match->compare[i].data);
-               if (ret)
+               struct component_match_array *mc = &match->compare[i];
+               struct component *c;
+
+               dev_dbg(master->dev, "Looking for component %zu\n", i);
+
+               if (match->compare[i].component)
+                       continue;
+
+               c = find_component(master, mc->compare, mc->data);
+               if (!c) {
+                       ret = -ENXIO;
                        break;
+               }
+
+               dev_dbg(master->dev, "found component %s, duplicate %u\n", dev_name(c->dev), !!c->master);
+
+               /* Attach this component to the master */
+               match->compare[i].duplicate = !!c->master;
+               match->compare[i].component = c;
+               c->master = master;
        }
        return ret;
 }
 
-/* Detach all attached components from this master */
-static void master_remove_components(struct master *master)
+/* Detach component from associated master */
+static void remove_component(struct master *master, struct component *c)
 {
-       while (!list_empty(&master->components)) {
-               struct component *c = list_first_entry(&master->components,
-                                       struct component, master_node);
-
-               WARN_ON(c->master != master);
+       size_t i;
 
-               component_detach_master(master, c);
-       }
+       /* Detach the component from this master. */
+       for (i = 0; i < master->match->num; i++)
+               if (master->match->compare[i].component == c)
+                       master->match->compare[i].component = NULL;
 }
 
 /*
@@ -159,44 +142,32 @@ static int try_to_bring_up_master(struct master *master,
 {
        int ret;
 
-       if (master->bound)
-               return 0;
+       dev_dbg(master->dev, "trying to bring up master\n");
 
-       /*
-        * Search the list of components, looking for components that
-        * belong to this master, and attach them to the master.
-        */
        if (find_components(master)) {
-               /* Failed to find all components */
-               ret = 0;
-               goto out;
+               dev_dbg(master->dev, "master has incomplete components\n");
+               return 0;
        }
 
        if (component && component->master != master) {
-               ret = 0;
-               goto out;
+               dev_dbg(master->dev, "master is not for this component (%s)\n",
+                       dev_name(component->dev));
+               return 0;
        }
 
-       if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
+               return -ENOMEM;
 
        /* Found all components */
        ret = master->ops->bind(master->dev);
        if (ret < 0) {
                devres_release_group(master->dev, NULL);
                dev_info(master->dev, "master bind failed: %d\n", ret);
-               goto out;
+               return ret;
        }
 
        master->bound = true;
        return 1;
-
-out:
-       master_remove_components(master);
-
-       return ret;
 }
 
 static int try_to_bring_up_masters(struct component *component)
@@ -205,9 +176,11 @@ static int try_to_bring_up_masters(struct component *component)
        int ret = 0;
 
        list_for_each_entry(m, &masters, node) {
-               ret = try_to_bring_up_master(m, component);
-               if (ret != 0)
-                       break;
+               if (!m->bound) {
+                       ret = try_to_bring_up_master(m, component);
+                       if (ret != 0)
+                               break;
+               }
        }
 
        return ret;
@@ -220,45 +193,57 @@ static void take_down_master(struct master *master)
                devres_release_group(master->dev, NULL);
                master->bound = false;
        }
+}
 
-       master_remove_components(master);
+static void component_match_release(struct device *master,
+       struct component_match *match)
+{
+       unsigned int i;
+
+       for (i = 0; i < match->num; i++) {
+               struct component_match_array *mc = &match->compare[i];
+
+               if (mc->release)
+                       mc->release(master, mc->data);
+       }
 }
 
-static size_t component_match_size(size_t num)
+static void devm_component_match_release(struct device *dev, void *res)
 {
-       return offsetof(struct component_match, compare[num]);
+       component_match_release(dev, res);
 }
 
-static struct component_match *component_match_realloc(struct device *dev,
+static int component_match_realloc(struct device *dev,
        struct component_match *match, size_t num)
 {
-       struct component_match *new;
+       struct component_match_array *new;
 
-       if (match && match->alloc == num)
-               return match;
+       if (match->alloc == num)
+               return 0;
 
-       new = devm_kmalloc(dev, component_match_size(num), GFP_KERNEL);
+       new = devm_kmalloc_array(dev, num, sizeof(*new), GFP_KERNEL);
        if (!new)
-               return ERR_PTR(-ENOMEM);
+               return -ENOMEM;
 
-       if (match) {
-               memcpy(new, match, component_match_size(min(match->num, num)));
-               devm_kfree(dev, match);
-       } else {
-               new->num = 0;
+       if (match->compare) {
+               memcpy(new, match->compare, sizeof(*new) *
+                                           min(match->num, num));
+               devm_kfree(dev, match->compare);
        }
+       match->compare = new;
+       match->alloc = num;
 
-       new->alloc = num;
-
-       return new;
+       return 0;
 }
 
 /*
- * Add a component to be matched.
+ * Add a component to be matched, with a release function.
  *
  * The match array is first created or extended if necessary.
  */
-void component_match_add(struct device *dev, struct component_match **matchptr,
+void component_match_add_release(struct device *master,
+       struct component_match **matchptr,
+       void (*release)(struct device *, void *),
        int (*compare)(struct device *, void *), void *compare_data)
 {
        struct component_match *match = *matchptr;
@@ -266,22 +251,37 @@ void component_match_add(struct device *dev, struct component_match **matchptr,
        if (IS_ERR(match))
                return;
 
-       if (!match || match->num == match->alloc) {
-               size_t new_size = match ? match->alloc + 16 : 15;
+       if (!match) {
+               match = devres_alloc(devm_component_match_release,
+                                    sizeof(*match), GFP_KERNEL);
+               if (!match) {
+                       *matchptr = ERR_PTR(-ENOMEM);
+                       return;
+               }
 
-               match = component_match_realloc(dev, match, new_size);
+               devres_add(master, match);
 
                *matchptr = match;
+       }
+
+       if (match->num == match->alloc) {
+               size_t new_size = match ? match->alloc + 16 : 15;
+               int ret;
 
-               if (IS_ERR(match))
+               ret = component_match_realloc(master, match, new_size);
+               if (ret) {
+                       *matchptr = ERR_PTR(ret);
                        return;
+               }
        }
 
-       match->compare[match->num].fn = compare;
+       match->compare[match->num].compare = compare;
+       match->compare[match->num].release = release;
        match->compare[match->num].data = compare_data;
+       match->compare[match->num].component = NULL;
        match->num++;
 }
-EXPORT_SYMBOL(component_match_add);
+EXPORT_SYMBOL(component_match_add_release);
 
 int component_master_add_with_match(struct device *dev,
        const struct component_master_ops *ops,
@@ -290,15 +290,10 @@ int component_master_add_with_match(struct device *dev,
        struct master *master;
        int ret;
 
-       if (ops->add_components && match)
-               return -EINVAL;
-
-       if (match) {
-               /* Reallocate the match array for its true size */
-               match = component_match_realloc(dev, match, match->num);
-               if (IS_ERR(match))
-                       return PTR_ERR(match);
-       }
+       /* Reallocate the match array for its true size */
+       ret = component_match_realloc(dev, match, match->num);
+       if (ret)
+               return ret;
 
        master = kzalloc(sizeof(*master), GFP_KERNEL);
        if (!master)
@@ -307,7 +302,6 @@ int component_master_add_with_match(struct device *dev,
        master->dev = dev;
        master->ops = ops;
        master->match = match;
-       INIT_LIST_HEAD(&master->components);
 
        /* Add to the list of available masters. */
        mutex_lock(&component_mutex);
@@ -326,24 +320,28 @@ int component_master_add_with_match(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(component_master_add_with_match);
 
-int component_master_add(struct device *dev,
-       const struct component_master_ops *ops)
-{
-       return component_master_add_with_match(dev, ops, NULL);
-}
-EXPORT_SYMBOL_GPL(component_master_add);
-
 void component_master_del(struct device *dev,
        const struct component_master_ops *ops)
 {
        struct master *master;
+       int i;
 
        mutex_lock(&component_mutex);
        master = __master_find(dev, ops);
        if (master) {
+               struct component_match *match = master->match;
+
                take_down_master(master);
 
                list_del(&master->node);
+
+               if (match) {
+                       for (i = 0; i < match->num; i++) {
+                               struct component *c = match->compare[i].component;
+                               if (c)
+                                       c->master = NULL;
+                       }
+               }
                kfree(master);
        }
        mutex_unlock(&component_mutex);
@@ -366,6 +364,7 @@ void component_unbind_all(struct device *master_dev, void *data)
 {
        struct master *master;
        struct component *c;
+       size_t i;
 
        WARN_ON(!mutex_is_locked(&component_mutex));
 
@@ -373,8 +372,12 @@ void component_unbind_all(struct device *master_dev, void *data)
        if (!master)
                return;
 
-       list_for_each_entry_reverse(c, &master->components, master_node)
-               component_unbind(c, master, data);
+       /* Unbind components in reverse order */
+       for (i = master->match->num; i--; )
+               if (!master->match->compare[i].duplicate) {
+                       c = master->match->compare[i].component;
+                       component_unbind(c, master, data);
+               }
 }
 EXPORT_SYMBOL_GPL(component_unbind_all);
 
@@ -434,6 +437,7 @@ int component_bind_all(struct device *master_dev, void *data)
 {
        struct master *master;
        struct component *c;
+       size_t i;
        int ret = 0;
 
        WARN_ON(!mutex_is_locked(&component_mutex));
@@ -442,16 +446,21 @@ int component_bind_all(struct device *master_dev, void *data)
        if (!master)
                return -EINVAL;
 
-       list_for_each_entry(c, &master->components, master_node) {
-               ret = component_bind(c, master, data);
-               if (ret)
-                       break;
-       }
+       /* Bind components in match order */
+       for (i = 0; i < master->match->num; i++)
+               if (!master->match->compare[i].duplicate) {
+                       c = master->match->compare[i].component;
+                       ret = component_bind(c, master, data);
+                       if (ret)
+                               break;
+               }
 
        if (ret != 0) {
-               list_for_each_entry_continue_reverse(c, &master->components,
-                                                    master_node)
-                       component_unbind(c, master, data);
+               for (; i--; )
+                       if (!master->match->compare[i].duplicate) {
+                               c = master->match->compare[i].component;
+                               component_unbind(c, master, data);
+                       }
        }
 
        return ret;
@@ -499,8 +508,10 @@ void component_del(struct device *dev, const struct component_ops *ops)
                        break;
                }
 
-       if (component && component->master)
+       if (component && component->master) {
                take_down_master(component->master);
+               remove_component(component->master, component);
+       }
 
        mutex_unlock(&component_mutex);
 
index 5df4575b5ba765de181a02701c706a6802d38b13..47c43386786b13229f4fbeb5cbdbfe03a2009804 100644 (file)
 #include <linux/msi.h>
 #include <linux/slab.h>
 
-#define DEV_ID_SHIFT   24
+#define DEV_ID_SHIFT   21
+#define MAX_DEV_MSIS   (1 << (32 - DEV_ID_SHIFT))
 
 /*
  * Internal data structure containing a (made up, but unique) devid
  * and the callback to write the MSI message.
  */
 struct platform_msi_priv_data {
+       struct device           *dev;
+       void                    *host_data;
+       msi_alloc_info_t        arg;
        irq_write_msi_msg_t     write_msg;
        int                     devid;
 };
@@ -110,39 +114,49 @@ static void platform_msi_update_chip_ops(struct msi_domain_info *info)
                chip->irq_write_msi_msg = platform_msi_write_msg;
 }
 
-static void platform_msi_free_descs(struct device *dev)
+static void platform_msi_free_descs(struct device *dev, int base, int nvec)
 {
        struct msi_desc *desc, *tmp;
 
        list_for_each_entry_safe(desc, tmp, dev_to_msi_list(dev), list) {
-               list_del(&desc->list);
-               free_msi_entry(desc);
+               if (desc->platform.msi_index >= base &&
+                   desc->platform.msi_index < (base + nvec)) {
+                       list_del(&desc->list);
+                       free_msi_entry(desc);
+               }
        }
 }
 
-static int platform_msi_alloc_descs(struct device *dev, int nvec,
-                                   struct platform_msi_priv_data *data)
+static int platform_msi_alloc_descs_with_irq(struct device *dev, int virq,
+                                            int nvec,
+                                            struct platform_msi_priv_data *data)
 
 {
-       int i;
+       struct msi_desc *desc;
+       int i, base = 0;
 
-       for (i = 0; i < nvec; i++) {
-               struct msi_desc *desc;
+       if (!list_empty(dev_to_msi_list(dev))) {
+               desc = list_last_entry(dev_to_msi_list(dev),
+                                      struct msi_desc, list);
+               base = desc->platform.msi_index + 1;
+       }
 
+       for (i = 0; i < nvec; i++) {
                desc = alloc_msi_entry(dev);
                if (!desc)
                        break;
 
                desc->platform.msi_priv_data = data;
-               desc->platform.msi_index = i;
+               desc->platform.msi_index = base + i;
                desc->nvec_used = 1;
+               desc->irq = virq ? virq + i : 0;
 
                list_add_tail(&desc->list, dev_to_msi_list(dev));
        }
 
        if (i != nvec) {
                /* Clean up the mess */
-               platform_msi_free_descs(dev);
+               platform_msi_free_descs(dev, base, nvec);
 
                return -ENOMEM;
        }
@@ -150,6 +164,13 @@ static int platform_msi_alloc_descs(struct device *dev, int nvec,
        return 0;
 }
 
+static int platform_msi_alloc_descs(struct device *dev, int nvec,
+                                   struct platform_msi_priv_data *data)
+
+{
+       return platform_msi_alloc_descs_with_irq(dev, 0, nvec, data);
+}
+
 /**
  * platform_msi_create_irq_domain - Create a platform MSI interrupt domain
  * @fwnode:            Optional fwnode of the interrupt controller
@@ -180,56 +201,75 @@ struct irq_domain *platform_msi_create_irq_domain(struct fwnode_handle *fwnode,
        return domain;
 }
 
-/**
- * platform_msi_domain_alloc_irqs - Allocate MSI interrupts for @dev
- * @dev:               The device for which to allocate interrupts
- * @nvec:              The number of interrupts to allocate
- * @write_msi_msg:     Callback to write an interrupt message for @dev
- *
- * Returns:
- * Zero for success, or an error code in case of failure
- */
-int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
-                                  irq_write_msi_msg_t write_msi_msg)
+static struct platform_msi_priv_data *
+platform_msi_alloc_priv_data(struct device *dev, unsigned int nvec,
+                            irq_write_msi_msg_t write_msi_msg)
 {
-       struct platform_msi_priv_data *priv_data;
-       int err;
-
+       struct platform_msi_priv_data *datap;
        /*
         * Limit the number of interrupts to 256 per device. Should we
         * need to bump this up, DEV_ID_SHIFT should be adjusted
         * accordingly (which would impact the max number of MSI
         * capable devices).
         */
-       if (!dev->msi_domain || !write_msi_msg || !nvec ||
-           nvec > (1 << (32 - DEV_ID_SHIFT)))
-               return -EINVAL;
+       if (!dev->msi_domain || !write_msi_msg || !nvec || nvec > MAX_DEV_MSIS)
+               return ERR_PTR(-EINVAL);
 
        if (dev->msi_domain->bus_token != DOMAIN_BUS_PLATFORM_MSI) {
                dev_err(dev, "Incompatible msi_domain, giving up\n");
-               return -EINVAL;
+               return ERR_PTR(-EINVAL);
        }
 
        /* Already had a helping of MSI? Greed... */
        if (!list_empty(dev_to_msi_list(dev)))
-               return -EBUSY;
+               return ERR_PTR(-EBUSY);
+
+       datap = kzalloc(sizeof(*datap), GFP_KERNEL);
+       if (!datap)
+               return ERR_PTR(-ENOMEM);
+
+       datap->devid = ida_simple_get(&platform_msi_devid_ida,
+                                     0, 1 << DEV_ID_SHIFT, GFP_KERNEL);
+       if (datap->devid < 0) {
+               int err = datap->devid;
+               kfree(datap);
+               return ERR_PTR(err);
+       }
 
-       priv_data = kzalloc(sizeof(*priv_data), GFP_KERNEL);
-       if (!priv_data)
-               return -ENOMEM;
+       datap->write_msg = write_msi_msg;
+       datap->dev = dev;
 
-       priv_data->devid = ida_simple_get(&platform_msi_devid_ida,
-                                         0, 1 << DEV_ID_SHIFT, GFP_KERNEL);
-       if (priv_data->devid < 0) {
-               err = priv_data->devid;
-               goto out_free_data;
-       }
+       return datap;
+}
+
+static void platform_msi_free_priv_data(struct platform_msi_priv_data *data)
+{
+       ida_simple_remove(&platform_msi_devid_ida, data->devid);
+       kfree(data);
+}
+
+/**
+ * platform_msi_domain_alloc_irqs - Allocate MSI interrupts for @dev
+ * @dev:               The device for which to allocate interrupts
+ * @nvec:              The number of interrupts to allocate
+ * @write_msi_msg:     Callback to write an interrupt message for @dev
+ *
+ * Returns:
+ * Zero for success, or an error code in case of failure
+ */
+int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
+                                  irq_write_msi_msg_t write_msi_msg)
+{
+       struct platform_msi_priv_data *priv_data;
+       int err;
 
-       priv_data->write_msg = write_msi_msg;
+       priv_data = platform_msi_alloc_priv_data(dev, nvec, write_msi_msg);
+       if (IS_ERR(priv_data))
+               return PTR_ERR(priv_data);
 
        err = platform_msi_alloc_descs(dev, nvec, priv_data);
        if (err)
-               goto out_free_id;
+               goto out_free_priv_data;
 
        err = msi_domain_alloc_irqs(dev->msi_domain, dev, nvec);
        if (err)
@@ -238,11 +278,9 @@ int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
        return 0;
 
 out_free_desc:
-       platform_msi_free_descs(dev);
-out_free_id:
-       ida_simple_remove(&platform_msi_devid_ida, priv_data->devid);
-out_free_data:
-       kfree(priv_data);
+       platform_msi_free_descs(dev, 0, nvec);
+out_free_priv_data:
+       platform_msi_free_priv_data(priv_data);
 
        return err;
 }
@@ -253,18 +291,126 @@ out_free_data:
  */
 void platform_msi_domain_free_irqs(struct device *dev)
 {
-       struct msi_desc *desc;
+       if (!list_empty(dev_to_msi_list(dev))) {
+               struct msi_desc *desc;
+
+               desc = first_msi_entry(dev);
+               platform_msi_free_priv_data(desc->platform.msi_priv_data);
+       }
+
+       msi_domain_free_irqs(dev->msi_domain, dev);
+       platform_msi_free_descs(dev, 0, MAX_DEV_MSIS);
+}
+
+/**
+ * platform_msi_get_host_data - Query the private data associated with
+ *                              a platform-msi domain
+ * @domain:    The platform-msi domain
+ *
+ * Returns the private data provided when calling
+ * platform_msi_create_device_domain.
+ */
+void *platform_msi_get_host_data(struct irq_domain *domain)
+{
+       struct platform_msi_priv_data *data = domain->host_data;
+       return data->host_data;
+}
+
+/**
+ * platform_msi_create_device_domain - Create a platform-msi domain
+ *
+ * @dev:               The device generating the MSIs
+ * @nvec:              The number of MSIs that need to be allocated
+ * @write_msi_msg:     Callback to write an interrupt message for @dev
+ * @ops:               The hierarchy domain operations to use
+ * @host_data:         Private data associated to this domain
+ *
+ * Returns an irqdomain for @nvec interrupts
+ */
+struct irq_domain *
+platform_msi_create_device_domain(struct device *dev,
+                                 unsigned int nvec,
+                                 irq_write_msi_msg_t write_msi_msg,
+                                 const struct irq_domain_ops *ops,
+                                 void *host_data)
+{
+       struct platform_msi_priv_data *data;
+       struct irq_domain *domain;
+       int err;
+
+       data = platform_msi_alloc_priv_data(dev, nvec, write_msi_msg);
+       if (IS_ERR(data))
+               return NULL;
+
+       data->host_data = host_data;
+       domain = irq_domain_create_hierarchy(dev->msi_domain, 0, nvec,
+                                            of_node_to_fwnode(dev->of_node),
+                                            ops, data);
+       if (!domain)
+               goto free_priv;
 
-       desc = first_msi_entry(dev);
-       if (desc) {
-               struct platform_msi_priv_data *data;
+       err = msi_domain_prepare_irqs(domain->parent, dev, nvec, &data->arg);
+       if (err)
+               goto free_domain;
+
+       return domain;
 
-               data = desc->platform.msi_priv_data;
+free_domain:
+       irq_domain_remove(domain);
+free_priv:
+       platform_msi_free_priv_data(data);
+       return NULL;
+}
+
+/**
+ * platform_msi_domain_free - Free interrupts associated with a platform-msi
+ *                            domain
+ *
+ * @domain:    The platform-msi domain
+ * @virq:      The base irq from which to perform the free operation
+ * @nvec:      How many interrupts to free from @virq
+ */
+void platform_msi_domain_free(struct irq_domain *domain, unsigned int virq,
+                             unsigned int nvec)
+{
+       struct platform_msi_priv_data *data = domain->host_data;
+       struct msi_desc *desc;
+       for_each_msi_entry(desc, data->dev) {
+               if (WARN_ON(!desc->irq || desc->nvec_used != 1))
+                       return;
+               if (!(desc->irq >= virq && desc->irq < (virq + nvec)))
+                       continue;
 
-               ida_simple_remove(&platform_msi_devid_ida, data->devid);
-               kfree(data);
+               irq_domain_free_irqs_common(domain, desc->irq, 1);
        }
+}
 
-       msi_domain_free_irqs(dev->msi_domain, dev);
-       platform_msi_free_descs(dev);
+/**
+ * platform_msi_domain_alloc - Allocate interrupts associated with
+ *                            a platform-msi domain
+ *
+ * @domain:    The platform-msi domain
+ * @virq:      The base irq from which to perform the allocate operation
+ * @nvec:      How many interrupts to free from @virq
+ *
+ * Return 0 on success, or an error code on failure. Must be called
+ * with irq_domain_mutex held (which can only be done as part of a
+ * top-level interrupt allocation).
+ */
+int platform_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
+                             unsigned int nr_irqs)
+{
+       struct platform_msi_priv_data *data = domain->host_data;
+       int err;
+
+       err = platform_msi_alloc_descs_with_irq(data->dev, virq, nr_irqs, data);
+       if (err)
+               return err;
+
+       err = msi_domain_populate_irqs(domain->parent, data->dev,
+                                      virq, nr_irqs, &data->arg);
+       if (err)
+               platform_msi_domain_free(domain, virq, nr_irqs);
+
+       return err;
 }
index 1dd6d3bf109834b453002a251b584c2880bb1c06..73e399466c6edfe0dbd4b704e925dab5bff19904 100644 (file)
@@ -116,6 +116,26 @@ int platform_get_irq(struct platform_device *dev, unsigned int num)
 }
 EXPORT_SYMBOL_GPL(platform_get_irq);
 
+/**
+ * platform_irq_count - Count the number of IRQs a platform device uses
+ * @dev: platform device
+ *
+ * Return: Number of IRQs a platform device uses or EPROBE_DEFER
+ */
+int platform_irq_count(struct platform_device *dev)
+{
+       int ret, nr = 0;
+
+       while ((ret = platform_get_irq(dev, nr)) >= 0)
+               nr++;
+
+       if (ret == -EPROBE_DEFER)
+               return ret;
+
+       return nr;
+}
+EXPORT_SYMBOL_GPL(platform_irq_count);
+
 /**
  * platform_get_resource_byname - get a resource for a device by name
  * @dev: platform device
index 0246f44ded747478f3dab0ba0441d4fdff2ae318..686c9e0b930eff7db5fb5ea01d8760cdf4d5901f 100644 (file)
@@ -21,7 +21,7 @@ static int regcache_flat_init(struct regmap *map)
        int i;
        unsigned int *cache;
 
-       map->cache = kzalloc(sizeof(unsigned int) * (map->max_register + 1),
+       map->cache = kcalloc(map->max_register + 1, sizeof(unsigned int),
                             GFP_KERNEL);
        if (!map->cache)
                return -ENOMEM;
index 736e0d378567c80900f2be8dd4d117b829e0242d..6f77d7319fc6dd35182fecefcaa56a4650fed65f 100644 (file)
@@ -139,7 +139,7 @@ static int regcache_lzo_init(struct regmap *map)
        ret = 0;
 
        blkcount = regcache_lzo_block_count(map);
-       map->cache = kzalloc(blkcount * sizeof *lzo_blocks,
+       map->cache = kcalloc(blkcount, sizeof(*lzo_blocks),
                             GFP_KERNEL);
        if (!map->cache)
                return -ENOMEM;
@@ -152,8 +152,8 @@ static int regcache_lzo_init(struct regmap *map)
         * that register.
         */
        bmp_size = map->num_reg_defaults_raw;
-       sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long),
-                          GFP_KERNEL);
+       sync_bmp = kmalloc_array(BITS_TO_LONGS(bmp_size), sizeof(long),
+                                GFP_KERNEL);
        if (!sync_bmp) {
                ret = -ENOMEM;
                goto err;
index 56486d92c4e72bd583630baea0fba541f36c926f..aa56af87d94118338befbbf62aa7f7b64cfd6570 100644 (file)
@@ -361,13 +361,14 @@ regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg)
                rbnode->base_reg = reg;
        }
 
-       rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
-                               GFP_KERNEL);
+       rbnode->block = kmalloc_array(rbnode->blklen, map->cache_word_size,
+                                     GFP_KERNEL);
        if (!rbnode->block)
                goto err_free;
 
-       rbnode->cache_present = kzalloc(BITS_TO_LONGS(rbnode->blklen) *
-               sizeof(*rbnode->cache_present), GFP_KERNEL);
+       rbnode->cache_present = kcalloc(BITS_TO_LONGS(rbnode->blklen),
+                                       sizeof(*rbnode->cache_present),
+                                       GFP_KERNEL);
        if (!rbnode->cache_present)
                goto err_free_block;
 
@@ -413,8 +414,8 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
                max = reg + max_dist;
 
                /* look for an adjacent register to the one we are about to add */
-               for (node = rb_first(&rbtree_ctx->root); node;
-                    node = rb_next(node)) {
+               node = rbtree_ctx->root.rb_node;
+               while (node) {
                        rbnode_tmp = rb_entry(node, struct regcache_rbtree_node,
                                              node);
 
@@ -425,6 +426,11 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
                                new_base_reg = min(reg, base_reg);
                                new_top_reg = max(reg, top_reg);
                        } else {
+                               if (max < base_reg)
+                                       node = node->rb_left;
+                               else
+                                       node = node->rb_right;
+
                                continue;
                        }
 
index 4c07802986b2c92862e1f0242eebddcb42e2b45d..348be3a354108eb2533587dabed9495e9c324b5a 100644 (file)
@@ -100,15 +100,25 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
        int i;
        void *tmp_buf;
 
-       for (i = 0; i < config->num_reg_defaults; i++)
-               if (config->reg_defaults[i].reg % map->reg_stride)
-                       return -EINVAL;
-
        if (map->cache_type == REGCACHE_NONE) {
+               if (config->reg_defaults || config->num_reg_defaults_raw)
+                       dev_warn(map->dev,
+                                "No cache used with register defaults set!\n");
+
                map->cache_bypass = true;
                return 0;
        }
 
+       if (config->reg_defaults && !config->num_reg_defaults) {
+               dev_err(map->dev,
+                        "Register defaults are set without the number!\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < config->num_reg_defaults; i++)
+               if (config->reg_defaults[i].reg % map->reg_stride)
+                       return -EINVAL;
+
        for (i = 0; i < ARRAY_SIZE(cache_types); i++)
                if (cache_types[i]->type == map->cache_type)
                        break;
@@ -138,8 +148,6 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
         * a copy of it.
         */
        if (config->reg_defaults) {
-               if (!map->num_reg_defaults)
-                       return -EINVAL;
                tmp_buf = kmemdup(config->reg_defaults, map->num_reg_defaults *
                                  sizeof(struct reg_default), GFP_KERNEL);
                if (!tmp_buf)
@@ -535,19 +543,30 @@ bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
        switch (map->cache_word_size) {
        case 1: {
                u8 *cache = base;
+
                cache[idx] = val;
                break;
        }
        case 2: {
                u16 *cache = base;
+
                cache[idx] = val;
                break;
        }
        case 4: {
                u32 *cache = base;
+
+               cache[idx] = val;
+               break;
+       }
+#ifdef CONFIG_64BIT
+       case 8: {
+               u64 *cache = base;
+
                cache[idx] = val;
                break;
        }
+#endif
        default:
                BUG();
        }
@@ -568,16 +587,26 @@ unsigned int regcache_get_val(struct regmap *map, const void *base,
        switch (map->cache_word_size) {
        case 1: {
                const u8 *cache = base;
+
                return cache[idx];
        }
        case 2: {
                const u16 *cache = base;
+
                return cache[idx];
        }
        case 4: {
                const u32 *cache = base;
+
+               return cache[idx];
+       }
+#ifdef CONFIG_64BIT
+       case 8: {
+               const u64 *cache = base;
+
                return cache[idx];
        }
+#endif
        default:
                BUG();
        }
index 3f0a7e262d6982c63dcaf3e81f058b0c471d2880..1ee3d40861c7ee77b819e9ae0118fb5f774bb215 100644 (file)
@@ -397,72 +397,39 @@ static const struct file_operations regmap_reg_ranges_fops = {
        .llseek = default_llseek,
 };
 
-static ssize_t regmap_access_read_file(struct file *file,
-                                      char __user *user_buf, size_t count,
-                                      loff_t *ppos)
+static int regmap_access_show(struct seq_file *s, void *ignored)
 {
-       int reg_len, tot_len;
-       size_t buf_pos = 0;
-       loff_t p = 0;
-       ssize_t ret;
-       int i;
-       struct regmap *map = file->private_data;
-       char *buf;
-
-       if (*ppos < 0 || !count)
-               return -EINVAL;
+       struct regmap *map = s->private;
+       int i, reg_len;
 
-       buf = kmalloc(count, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       /* Calculate the length of a fixed format  */
        reg_len = regmap_calc_reg_len(map->max_register);
-       tot_len = reg_len + 10; /* ': R W V P\n' */
 
        for (i = 0; i <= map->max_register; i += map->reg_stride) {
                /* Ignore registers which are neither readable nor writable */
                if (!regmap_readable(map, i) && !regmap_writeable(map, i))
                        continue;
 
-               /* If we're in the region the user is trying to read */
-               if (p >= *ppos) {
-                       /* ...but not beyond it */
-                       if (buf_pos + tot_len + 1 >= count)
-                               break;
-
-                       /* Format the register */
-                       snprintf(buf + buf_pos, count - buf_pos,
-                                "%.*x: %c %c %c %c\n",
-                                reg_len, i,
-                                regmap_readable(map, i) ? 'y' : 'n',
-                                regmap_writeable(map, i) ? 'y' : 'n',
-                                regmap_volatile(map, i) ? 'y' : 'n',
-                                regmap_precious(map, i) ? 'y' : 'n');
-
-                       buf_pos += tot_len;
-               }
-               p += tot_len;
-       }
-
-       ret = buf_pos;
-
-       if (copy_to_user(user_buf, buf, buf_pos)) {
-               ret = -EFAULT;
-               goto out;
+               /* Format the register */
+               seq_printf(s, "%.*x: %c %c %c %c\n", reg_len, i,
+                          regmap_readable(map, i) ? 'y' : 'n',
+                          regmap_writeable(map, i) ? 'y' : 'n',
+                          regmap_volatile(map, i) ? 'y' : 'n',
+                          regmap_precious(map, i) ? 'y' : 'n');
        }
 
-       *ppos += buf_pos;
+       return 0;
+}
 
-out:
-       kfree(buf);
-       return ret;
+static int access_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, regmap_access_show, inode->i_private);
 }
 
 static const struct file_operations regmap_access_fops = {
-       .open = simple_open,
-       .read = regmap_access_read_file,
-       .llseek = default_llseek,
+       .open           = access_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
 };
 
 static ssize_t regmap_cache_only_write_file(struct file *file,
index 8d16db533527362efa638f67b69673607d069327..9b0d202414d065bf6e03a6f39bb33c9925dee4db 100644 (file)
@@ -39,8 +39,11 @@ struct regmap_irq_chip_data {
        unsigned int *mask_buf;
        unsigned int *mask_buf_def;
        unsigned int *wake_buf;
+       unsigned int *type_buf;
+       unsigned int *type_buf_def;
 
        unsigned int irq_reg_stride;
+       unsigned int type_reg_stride;
 };
 
 static inline const
@@ -144,6 +147,22 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
                }
        }
 
+       for (i = 0; i < d->chip->num_type_reg; i++) {
+               if (!d->type_buf_def[i])
+                       continue;
+               reg = d->chip->type_base +
+                       (i * map->reg_stride * d->type_reg_stride);
+               if (d->chip->type_invert)
+                       ret = regmap_update_bits(d->map, reg,
+                               d->type_buf_def[i], ~d->type_buf[i]);
+               else
+                       ret = regmap_update_bits(d->map, reg,
+                               d->type_buf_def[i], d->type_buf[i]);
+               if (ret != 0)
+                       dev_err(d->map->dev, "Failed to sync type in %x\n",
+                               reg);
+       }
+
        if (d->chip->runtime_pm)
                pm_runtime_put(map->dev);
 
@@ -178,6 +197,38 @@ static void regmap_irq_disable(struct irq_data *data)
        d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask;
 }
 
+static int regmap_irq_set_type(struct irq_data *data, unsigned int type)
+{
+       struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
+       struct regmap *map = d->map;
+       const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
+       int reg = irq_data->type_reg_offset / map->reg_stride;
+
+       if (!(irq_data->type_rising_mask | irq_data->type_falling_mask))
+               return 0;
+
+       d->type_buf[reg] &= ~(irq_data->type_falling_mask |
+                                       irq_data->type_rising_mask);
+       switch (type) {
+       case IRQ_TYPE_EDGE_FALLING:
+               d->type_buf[reg] |= irq_data->type_falling_mask;
+               break;
+
+       case IRQ_TYPE_EDGE_RISING:
+               d->type_buf[reg] |= irq_data->type_rising_mask;
+               break;
+
+       case IRQ_TYPE_EDGE_BOTH:
+               d->type_buf[reg] |= (irq_data->type_falling_mask |
+                                       irq_data->type_rising_mask);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
 static int regmap_irq_set_wake(struct irq_data *data, unsigned int on)
 {
        struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
@@ -204,6 +255,7 @@ static const struct irq_chip regmap_irq_chip = {
        .irq_bus_sync_unlock    = regmap_irq_sync_unlock,
        .irq_disable            = regmap_irq_disable,
        .irq_enable             = regmap_irq_enable,
+       .irq_set_type           = regmap_irq_set_type,
        .irq_set_wake           = regmap_irq_set_wake,
 };
 
@@ -386,28 +438,40 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
        if (!d)
                return -ENOMEM;
 
-       d->status_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
+       d->status_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
                                GFP_KERNEL);
        if (!d->status_buf)
                goto err_alloc;
 
-       d->mask_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
+       d->mask_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
                              GFP_KERNEL);
        if (!d->mask_buf)
                goto err_alloc;
 
-       d->mask_buf_def = kzalloc(sizeof(unsigned int) * chip->num_regs,
+       d->mask_buf_def = kcalloc(chip->num_regs, sizeof(unsigned int),
                                  GFP_KERNEL);
        if (!d->mask_buf_def)
                goto err_alloc;
 
        if (chip->wake_base) {
-               d->wake_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
+               d->wake_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
                                      GFP_KERNEL);
                if (!d->wake_buf)
                        goto err_alloc;
        }
 
+       if (chip->num_type_reg) {
+               d->type_buf_def = kcalloc(chip->num_type_reg,
+                                       sizeof(unsigned int), GFP_KERNEL);
+               if (!d->type_buf_def)
+                       goto err_alloc;
+
+               d->type_buf = kcalloc(chip->num_type_reg, sizeof(unsigned int),
+                                     GFP_KERNEL);
+               if (!d->type_buf)
+                       goto err_alloc;
+       }
+
        d->irq_chip = regmap_irq_chip;
        d->irq_chip.name = chip->name;
        d->irq = irq;
@@ -420,10 +484,16 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
        else
                d->irq_reg_stride = 1;
 
+       if (chip->type_reg_stride)
+               d->type_reg_stride = chip->type_reg_stride;
+       else
+               d->type_reg_stride = 1;
+
        if (!map->use_single_read && map->reg_stride == 1 &&
            d->irq_reg_stride == 1) {
-               d->status_reg_buf = kmalloc(map->format.val_bytes *
-                                           chip->num_regs, GFP_KERNEL);
+               d->status_reg_buf = kmalloc_array(chip->num_regs,
+                                                 map->format.val_bytes,
+                                                 GFP_KERNEL);
                if (!d->status_reg_buf)
                        goto err_alloc;
        }
@@ -511,6 +581,33 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
                }
        }
 
+       if (chip->num_type_reg) {
+               for (i = 0; i < chip->num_irqs; i++) {
+                       reg = chip->irqs[i].type_reg_offset / map->reg_stride;
+                       d->type_buf_def[reg] |= chip->irqs[i].type_rising_mask |
+                                       chip->irqs[i].type_falling_mask;
+               }
+               for (i = 0; i < chip->num_type_reg; ++i) {
+                       if (!d->type_buf_def[i])
+                               continue;
+
+                       reg = chip->type_base +
+                               (i * map->reg_stride * d->type_reg_stride);
+                       if (chip->type_invert)
+                               ret = regmap_update_bits(map, reg,
+                                       d->type_buf_def[i], 0xFF);
+                       else
+                               ret = regmap_update_bits(map, reg,
+                                       d->type_buf_def[i], 0x0);
+                       if (ret != 0) {
+                               dev_err(map->dev,
+                                       "Failed to set type in 0x%x: %x\n",
+                                       reg, ret);
+                               goto err_alloc;
+                       }
+               }
+       }
+
        if (irq_base)
                d->domain = irq_domain_add_legacy(map->dev->of_node,
                                                  chip->num_irqs, irq_base, 0,
@@ -541,6 +638,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
 err_domain:
        /* Should really dispose of the domain but... */
 err_alloc:
+       kfree(d->type_buf);
+       kfree(d->type_buf_def);
        kfree(d->wake_buf);
        kfree(d->mask_buf_def);
        kfree(d->mask_buf);
@@ -564,6 +663,8 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
 
        free_irq(irq, d);
        irq_domain_remove(d->domain);
+       kfree(d->type_buf);
+       kfree(d->type_buf_def);
        kfree(d->wake_buf);
        kfree(d->mask_buf_def);
        kfree(d->mask_buf);
index 426a57e41ac76071e213ebd69d9d454c51f92172..8812bfb9e3b89256f4a5d1468cf45484b18e4cd1 100644 (file)
@@ -61,6 +61,33 @@ static int regmap_mmio_regbits_check(size_t reg_bits)
        }
 }
 
+static int regmap_mmio_get_min_stride(size_t val_bits)
+{
+       int min_stride;
+
+       switch (val_bits) {
+       case 8:
+               /* The core treats 0 as 1 */
+               min_stride = 0;
+               return 0;
+       case 16:
+               min_stride = 2;
+               break;
+       case 32:
+               min_stride = 4;
+               break;
+#ifdef CONFIG_64BIT
+       case 64:
+               min_stride = 8;
+               break;
+#endif
+       default:
+               return -EINVAL;
+       }
+
+       return min_stride;
+}
+
 static inline void regmap_mmio_count_check(size_t count, u32 offset)
 {
        BUG_ON(count <= offset);
@@ -106,17 +133,17 @@ static int regmap_mmio_gather_write(void *context,
        while (val_size) {
                switch (ctx->val_bytes) {
                case 1:
-                       writeb(*(u8 *)val, ctx->regs + offset);
+                       __raw_writeb(*(u8 *)val, ctx->regs + offset);
                        break;
                case 2:
-                       writew(*(u16 *)val, ctx->regs + offset);
+                       __raw_writew(*(u16 *)val, ctx->regs + offset);
                        break;
                case 4:
-                       writel(*(u32 *)val, ctx->regs + offset);
+                       __raw_writel(*(u32 *)val, ctx->regs + offset);
                        break;
 #ifdef CONFIG_64BIT
                case 8:
-                       writeq(*(u64 *)val, ctx->regs + offset);
+                       __raw_writeq(*(u64 *)val, ctx->regs + offset);
                        break;
 #endif
                default:
@@ -166,17 +193,17 @@ static int regmap_mmio_read(void *context,
        while (val_size) {
                switch (ctx->val_bytes) {
                case 1:
-                       *(u8 *)val = readb(ctx->regs + offset);
+                       *(u8 *)val = __raw_readb(ctx->regs + offset);
                        break;
                case 2:
-                       *(u16 *)val = readw(ctx->regs + offset);
+                       *(u16 *)val = __raw_readw(ctx->regs + offset);
                        break;
                case 4:
-                       *(u32 *)val = readl(ctx->regs + offset);
+                       *(u32 *)val = __raw_readl(ctx->regs + offset);
                        break;
 #ifdef CONFIG_64BIT
                case 8:
-                       *(u64 *)val = readq(ctx->regs + offset);
+                       *(u64 *)val = __raw_readq(ctx->regs + offset);
                        break;
 #endif
                default:
@@ -231,26 +258,9 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
        if (config->pad_bits)
                return ERR_PTR(-EINVAL);
 
-       switch (config->val_bits) {
-       case 8:
-               /* The core treats 0 as 1 */
-               min_stride = 0;
-               break;
-       case 16:
-               min_stride = 2;
-               break;
-       case 32:
-               min_stride = 4;
-               break;
-#ifdef CONFIG_64BIT
-       case 64:
-               min_stride = 8;
-               break;
-#endif
-               break;
-       default:
-               return ERR_PTR(-EINVAL);
-       }
+       min_stride = regmap_mmio_get_min_stride(config->val_bits);
+       if (min_stride < 0)
+               return ERR_PTR(min_stride);
 
        if (config->reg_stride < min_stride)
                return ERR_PTR(-EINVAL);
index 4ac63c0e50c7e6a446847b7a29567834d4a5b073..ee54e841de4ad69c96ecb7897ddc04e889e8c702 100644 (file)
@@ -245,6 +245,28 @@ static void regmap_format_32_native(void *buf, unsigned int val,
        *(u32 *)buf = val << shift;
 }
 
+#ifdef CONFIG_64BIT
+static void regmap_format_64_be(void *buf, unsigned int val, unsigned int shift)
+{
+       __be64 *b = buf;
+
+       b[0] = cpu_to_be64((u64)val << shift);
+}
+
+static void regmap_format_64_le(void *buf, unsigned int val, unsigned int shift)
+{
+       __le64 *b = buf;
+
+       b[0] = cpu_to_le64((u64)val << shift);
+}
+
+static void regmap_format_64_native(void *buf, unsigned int val,
+                                   unsigned int shift)
+{
+       *(u64 *)buf = (u64)val << shift;
+}
+#endif
+
 static void regmap_parse_inplace_noop(void *buf)
 {
 }
@@ -332,6 +354,41 @@ static unsigned int regmap_parse_32_native(const void *buf)
        return *(u32 *)buf;
 }
 
+#ifdef CONFIG_64BIT
+static unsigned int regmap_parse_64_be(const void *buf)
+{
+       const __be64 *b = buf;
+
+       return be64_to_cpu(b[0]);
+}
+
+static unsigned int regmap_parse_64_le(const void *buf)
+{
+       const __le64 *b = buf;
+
+       return le64_to_cpu(b[0]);
+}
+
+static void regmap_parse_64_be_inplace(void *buf)
+{
+       __be64 *b = buf;
+
+       b[0] = be64_to_cpu(b[0]);
+}
+
+static void regmap_parse_64_le_inplace(void *buf)
+{
+       __le64 *b = buf;
+
+       b[0] = le64_to_cpu(b[0]);
+}
+
+static unsigned int regmap_parse_64_native(const void *buf)
+{
+       return *(u64 *)buf;
+}
+#endif
+
 static void regmap_lock_mutex(void *__map)
 {
        struct regmap *map = __map;
@@ -712,6 +769,21 @@ struct regmap *__regmap_init(struct device *dev,
                }
                break;
 
+#ifdef CONFIG_64BIT
+       case 64:
+               switch (reg_endian) {
+               case REGMAP_ENDIAN_BIG:
+                       map->format.format_reg = regmap_format_64_be;
+                       break;
+               case REGMAP_ENDIAN_NATIVE:
+                       map->format.format_reg = regmap_format_64_native;
+                       break;
+               default:
+                       goto err_map;
+               }
+               break;
+#endif
+
        default:
                goto err_map;
        }
@@ -771,6 +843,28 @@ struct regmap *__regmap_init(struct device *dev,
                        goto err_map;
                }
                break;
+#ifdef CONFIG_64BIT
+       case 64:
+               switch (val_endian) {
+               case REGMAP_ENDIAN_BIG:
+                       map->format.format_val = regmap_format_64_be;
+                       map->format.parse_val = regmap_parse_64_be;
+                       map->format.parse_inplace = regmap_parse_64_be_inplace;
+                       break;
+               case REGMAP_ENDIAN_LITTLE:
+                       map->format.format_val = regmap_format_64_le;
+                       map->format.parse_val = regmap_parse_64_le;
+                       map->format.parse_inplace = regmap_parse_64_le_inplace;
+                       break;
+               case REGMAP_ENDIAN_NATIVE:
+                       map->format.format_val = regmap_format_64_native;
+                       map->format.parse_val = regmap_parse_64_native;
+                       break;
+               default:
+                       goto err_map;
+               }
+               break;
+#endif
        }
 
        if (map->format.format_write) {
@@ -1513,7 +1607,7 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val)
 {
        int ret;
 
-       if (reg % map->reg_stride)
+       if (!IS_ALIGNED(reg, map->reg_stride))
                return -EINVAL;
 
        map->lock(map->lock_arg);
@@ -1540,7 +1634,7 @@ int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val)
 {
        int ret;
 
-       if (reg % map->reg_stride)
+       if (!IS_ALIGNED(reg, map->reg_stride))
                return -EINVAL;
 
        map->lock(map->lock_arg);
@@ -1714,7 +1808,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
 
        if (map->bus && !map->format.parse_inplace)
                return -EINVAL;
-       if (reg % map->reg_stride)
+       if (!IS_ALIGNED(reg, map->reg_stride))
                return -EINVAL;
 
        /*
@@ -1983,7 +2077,7 @@ static int _regmap_multi_reg_write(struct regmap *map,
                        int reg = regs[i].reg;
                        if (!map->writeable_reg(map->dev, reg))
                                return -EINVAL;
-                       if (reg % map->reg_stride)
+                       if (!IS_ALIGNED(reg, map->reg_stride))
                                return -EINVAL;
                }
 
@@ -2133,7 +2227,7 @@ int regmap_raw_write_async(struct regmap *map, unsigned int reg,
 
        if (val_len % map->format.val_bytes)
                return -EINVAL;
-       if (reg % map->reg_stride)
+       if (!IS_ALIGNED(reg, map->reg_stride))
                return -EINVAL;
 
        map->lock(map->lock_arg);
@@ -2260,7 +2354,7 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)
 {
        int ret;
 
-       if (reg % map->reg_stride)
+       if (!IS_ALIGNED(reg, map->reg_stride))
                return -EINVAL;
 
        map->lock(map->lock_arg);
@@ -2296,7 +2390,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
                return -EINVAL;
        if (val_len % map->format.val_bytes)
                return -EINVAL;
-       if (reg % map->reg_stride)
+       if (!IS_ALIGNED(reg, map->reg_stride))
                return -EINVAL;
        if (val_count == 0)
                return -EINVAL;
@@ -2414,7 +2508,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
        size_t val_bytes = map->format.val_bytes;
        bool vol = regmap_volatile_range(map, reg, val_count);
 
-       if (reg % map->reg_stride)
+       if (!IS_ALIGNED(reg, map->reg_stride))
                return -EINVAL;
 
        if (map->bus && map->format.parse_inplace && (vol || map->cache_type == REGCACHE_NONE)) {
@@ -2488,11 +2582,19 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
                                 * we assume that the values are native
                                 * endian.
                                 */
+#ifdef CONFIG_64BIT
+                               u64 *u64 = val;
+#endif
                                u32 *u32 = val;
                                u16 *u16 = val;
                                u8 *u8 = val;
 
                                switch (map->format.val_bytes) {
+#ifdef CONFIG_64BIT
+                               case 8:
+                                       u64[i] = ival;
+                                       break;
+#endif
                                case 4:
                                        u32[i] = ival;
                                        break;
index a428e4ef71fd74ce2d569b9cfd407a7f6b0e3eb0..09e3c0d87eccff2d526666b99d3036f3921662a8 100644 (file)
@@ -232,20 +232,19 @@ static void end_cmd(struct nullb_cmd *cmd)
                break;
        case NULL_Q_BIO:
                bio_endio(cmd->bio);
-               goto free_cmd;
+               break;
        }
 
+       free_cmd(cmd);
+
        /* Restart queue if needed, as we are freeing a tag */
-       if (q && !q->mq_ops && blk_queue_stopped(q)) {
+       if (queue_mode == NULL_Q_RQ && blk_queue_stopped(q)) {
                unsigned long flags;
 
                spin_lock_irqsave(q->queue_lock, flags);
-               if (blk_queue_stopped(q))
-                       blk_start_queue(q);
+               blk_start_queue_async(q);
                spin_unlock_irqrestore(q->queue_lock, flags);
        }
-free_cmd:
-       free_cmd(cmd);
 }
 
 static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer)
index 0c98a9d51a2494e6a49ef49e6bfb557cefca1974..44ce806069444712ce9d6f883c2c3e3d3b8354a3 100644 (file)
@@ -140,7 +140,7 @@ static int via_rng_init(struct hwrng *rng)
         * RNG configuration like it used to be the case in this
         * register */
        if ((c->x86 == 6) && (c->x86_model >= 0x0f)) {
-               if (!cpu_has_xstore_enabled) {
+               if (!boot_cpu_has(X86_FEATURE_XSTORE_EN)) {
                        pr_err(PFX "can't enable hardware RNG "
                                "if XSTORE is not enabled\n");
                        return -ENODEV;
@@ -200,8 +200,9 @@ static int __init mod_init(void)
 {
        int err;
 
-       if (!cpu_has_xstore)
+       if (!boot_cpu_has(X86_FEATURE_XSTORE))
                return -ENODEV;
+
        pr_info("VIA RNG detected\n");
        err = hwrng_register(&via_rng);
        if (err) {
index 2eb5f0efae903cd5235bdd2132ec455dfafe7c26..b251013eef0a952f28e3c3464e0876773bd9ddab 100644 (file)
@@ -28,10 +28,16 @@ config CLKSRC_MMIO
        bool
 
 config DIGICOLOR_TIMER
-       bool
+       bool "Digicolor timer driver" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
+       help
+         Enables the support for the digicolor timer driver.
 
 config DW_APB_TIMER
-       bool
+       bool "DW APB timer driver" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
+       help
+         Enables the support for the dw_apb timer.
 
 config DW_APB_TIMER_OF
        bool
@@ -39,47 +45,77 @@ config DW_APB_TIMER_OF
        select CLKSRC_OF
 
 config ROCKCHIP_TIMER
-       bool
+       bool "Rockchip timer driver" if COMPILE_TEST
+       depends on ARM || ARM64
        select CLKSRC_OF
+       help
+         Enables the support for the rockchip timer driver.
 
 config ARMADA_370_XP_TIMER
-       bool
+       bool "Armada 370 and XP timer driver" if COMPILE_TEST
+       depends on ARM
        select CLKSRC_OF
+       help
+         Enables the support for the Armada 370 and XP timer driver.
 
 config MESON6_TIMER
-       bool
+       bool "Meson6 timer driver" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
+       help
+         Enables the support for the Meson6 timer driver.
 
 config ORION_TIMER
+       bool "Orion timer driver" if COMPILE_TEST
+       depends on ARM
        select CLKSRC_OF
        select CLKSRC_MMIO
-       bool
+       help
+         Enables the support for the Orion timer driver
 
 config SUN4I_TIMER
+       bool "Sun4i timer driver" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
-       bool
+       help
+         Enables support for the Sun4i timer.
 
 config SUN5I_HSTIMER
+       bool "Sun5i timer driver" if COMPILE_TEST
        select CLKSRC_MMIO
-       bool
+       depends on COMMON_CLK
+       help
+         Enables support the Sun5i timer.
 
 config TEGRA_TIMER
-       bool
+       bool "Tegra timer driver" if COMPILE_TEST
+       depends on ARM
+       help
+         Enables support for the Tegra driver.
 
 config VT8500_TIMER
-       bool
+       bool "VT8500 timer driver" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
+       help
+         Enables support for the VT8500 driver.
 
 config CADENCE_TTC_TIMER
-       bool
+       bool "Cadence TTC timer driver" if COMPILE_TEST
+       depends on COMMON_CLK
+       help
+         Enables support for the cadence ttc driver.
 
 config ASM9260_TIMER
-       bool
+       bool "ASM9260 timer driver" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
        select CLKSRC_OF
+       help
+         Enables support for the ASM9260 timer.
 
 config CLKSRC_NOMADIK_MTU
-       bool
-       depends on (ARCH_NOMADIK || ARCH_U8500)
+       bool "Nomakdik clocksource driver" if COMPILE_TEST
+       depends on ARM
        select CLKSRC_MMIO
        help
          Support for Multi Timer Unit. MTU provides access
@@ -93,9 +129,8 @@ config CLKSRC_NOMADIK_MTU_SCHED_CLOCK
          Use the Multi Timer Unit as the sched_clock.
 
 config CLKSRC_DBX500_PRCMU
-       bool "Clocksource PRCMU Timer"
-       depends on UX500_SOC_DB8500
-       default y
+       bool "Clocksource PRCMU Timer" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
        help
          Use the always on PRCMU Timer as clocksource
 
@@ -116,13 +151,18 @@ config CLKSRC_EFM32
          event device.
 
 config CLKSRC_LPC32XX
-       bool
+       bool "Clocksource for LPC32XX" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
        select CLKSRC_OF
+       help
+         Support for the LPC32XX clocksource.
 
 config CLKSRC_PISTACHIO
-       bool
+       bool "Clocksource for Pistachio SoC" if COMPILE_TEST
        select CLKSRC_OF
+       help
+         Enables the clocksource for the Pistachio SoC.
 
 config CLKSRC_TI_32K
        bool "Texas Instruments 32.768 Hz Clocksource" if COMPILE_TEST
@@ -199,13 +239,14 @@ config CLKSRC_METAG_GENERIC
          This option enables support for the Meta per-thread timers.
 
 config CLKSRC_EXYNOS_MCT
-       def_bool y if ARCH_EXYNOS
-       depends on !ARM64
+       bool "Exynos multi core timer driver" if COMPILE_TEST
+       depends on ARM
        help
          Support for Multi Core Timer controller on Exynos SoCs.
 
 config CLKSRC_SAMSUNG_PWM
-       bool
+       bool "PWM timer drvier for Samsung S3C, S5P" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
        help
          This is a new clocksource driver for the PWM timer found in
          Samsung S3C, S5P and Exynos SoCs, replacing an earlier driver
@@ -213,7 +254,8 @@ config CLKSRC_SAMSUNG_PWM
          needed only on systems that do not have the Exynos MCT available.
 
 config FSL_FTM_TIMER
-       bool
+       bool "Freescale FlexTimer Module driver" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
        help
          Support for Freescale FlexTimer Module (FTM) timer.
 
@@ -226,9 +268,12 @@ config SYS_SUPPORTS_SH_CMT
         bool
 
 config MTK_TIMER
+       bool "Mediatek timer driver" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_OF
        select CLKSRC_MMIO
-       bool
+       help
+         Support for Mediatek timer driver.
 
 config SYS_SUPPORTS_SH_MTU2
         bool
@@ -279,7 +324,12 @@ config EM_TIMER_STI
          such as EMEV2 from former NEC Electronics.
 
 config CLKSRC_QCOM
-       bool
+       bool "Qualcomm MSM timer" if COMPILE_TEST
+       depends on ARM
+       select CLKSRC_OF
+       help
+         This enables the clocksource and the per CPU clockevent driver for the
+         Qualcomm SoCs.
 
 config CLKSRC_VERSATILE
        bool "ARM Versatile (Express) reference platforms clock source"
@@ -298,21 +348,40 @@ config CLKSRC_MIPS_GIC
        select CLKSRC_OF
 
 config CLKSRC_TANGO_XTAL
-       bool
+       bool "Clocksource for Tango SoC" if COMPILE_TEST
+       depends on ARM
        select CLKSRC_OF
+       select CLKSRC_MMIO
+       help
+         This enables the clocksource for Tango SoC
 
 config CLKSRC_PXA
-       def_bool y if ARCH_PXA || ARCH_SA1100
-       select CLKSRC_OF if OF
+       bool "Clocksource for PXA or SA-11x0 platform" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
+       select CLKSRC_MMIO
        help
          This enables OST0 support available on PXA and SA-11x0
          platforms.
 
+config H8300_TMR8
+        bool "Clockevent timer for the H8300 platform" if COMPILE_TEST
+        depends on GENERIC_CLOCKEVENTS
+       help
+         This enables the 8 bits timer for the H8300 platform.
+
 config H8300_TMR16
-        bool
+        bool "Clockevent timer for the H83069 platform" if COMPILE_TEST
+        depends on GENERIC_CLOCKEVENTS
+       help
+         This enables the 16 bits timer for the H8300 platform with the
+         H83069 cpu.
 
 config H8300_TPU
-        bool
+        bool "Clocksource for the H8300 platform" if COMPILE_TEST
+        depends on GENERIC_CLOCKEVENTS
+       help
+         This enables the clocksource for the H8300 platform with the
+         H8S2678 cpu.
 
 config CLKSRC_IMX_GPT
        bool "Clocksource using i.MX GPT" if COMPILE_TEST
@@ -320,8 +389,7 @@ config CLKSRC_IMX_GPT
        select CLKSRC_MMIO
 
 config CLKSRC_ST_LPC
-       bool
-       depends on ARCH_STI
+       bool "Low power clocksource found in the LPC" if COMPILE_TEST
        select CLKSRC_OF if OF
        help
          Enable this option to use the Low Power controller timer
index 56bd16e77ae37147da0fa4e977adffcb9bc1a4c6..dc2b8997f6e637c0ae83f09b4b6bd4b92bffbf8d 100644 (file)
@@ -60,7 +60,7 @@ obj-$(CONFIG_CLKSRC_MIPS_GIC)         += mips-gic-timer.o
 obj-$(CONFIG_CLKSRC_TANGO_XTAL)                += tango_xtal.o
 obj-$(CONFIG_CLKSRC_IMX_GPT)           += timer-imx-gpt.o
 obj-$(CONFIG_ASM9260_TIMER)            += asm9260_timer.o
-obj-$(CONFIG_H8300)                    += h8300_timer8.o
+obj-$(CONFIG_H8300_TMR8)               += h8300_timer8.o
 obj-$(CONFIG_H8300_TMR16)              += h8300_timer16.o
 obj-$(CONFIG_H8300_TPU)                        += h8300_tpu.o
 obj-$(CONFIG_CLKSRC_ST_LPC)            += clksrc_st_lpc.o
index 6eab8898567031cf0e6519ec6d0d970340fc1705..28037d0b8dcd133c4be8814bf609342c1520d0c4 100644 (file)
@@ -109,10 +109,8 @@ static void acpi_pm_check_blacklist(struct pci_dev *dev)
 
        /* the bug has been fixed in PIIX4M */
        if (dev->revision < 3) {
-               printk(KERN_WARNING "* Found PM-Timer Bug on the chipset."
-                      " Due to workarounds for a bug,\n"
-                      "* this clock source is slow. Consider trying"
-                      " other clock sources\n");
+               pr_warn("* Found PM-Timer Bug on the chipset. Due to workarounds for a bug,\n"
+                       "* this clock source is slow. Consider trying other clock sources\n");
 
                acpi_pm_need_workaround();
        }
@@ -125,12 +123,9 @@ static void acpi_pm_check_graylist(struct pci_dev *dev)
        if (acpi_pm_good)
                return;
 
-       printk(KERN_WARNING "* The chipset may have PM-Timer Bug. Due to"
-              " workarounds for a bug,\n"
-              "* this clock source is slow. If you are sure your timer"
-              " does not have\n"
-              "* this bug, please use \"acpi_pm_good\" to disable the"
-              " workaround\n");
+       pr_warn("* The chipset may have PM-Timer Bug. Due to workarounds for a bug,\n"
+               "* this clock source is slow. If you are sure your timer does not have\n"
+               "* this bug, please use \"acpi_pm_good\" to disable the workaround\n");
 
        acpi_pm_need_workaround();
 }
@@ -162,8 +157,7 @@ static int verify_pmtmr_rate(void)
        /* Check that the PMTMR delta is within 5% of what we expect */
        if (delta < (PMTMR_EXPECTED_RATE * 19) / 20 ||
            delta > (PMTMR_EXPECTED_RATE * 21) / 20) {
-               printk(KERN_INFO "PM-Timer running at invalid rate: %lu%% "
-                       "of normal - aborting.\n",
+               pr_info("PM-Timer running at invalid rate: %lu%% of normal - aborting.\n",
                        100UL * delta / PMTMR_EXPECTED_RATE);
                return -1;
        }
@@ -199,15 +193,14 @@ static int __init init_acpi_pm_clocksource(void)
                                break;
                        if ((value2 < value1) && ((value2) < 0xFFF))
                                break;
-                       printk(KERN_INFO "PM-Timer had inconsistent results:"
-                              " %#llx, %#llx - aborting.\n",
-                              value1, value2);
+                       pr_info("PM-Timer had inconsistent results: %#llx, %#llx - aborting.\n",
+                               value1, value2);
                        pmtmr_ioport = 0;
                        return -EINVAL;
                }
                if (i == ACPI_PM_READ_CHECKS) {
-                       printk(KERN_INFO "PM-Timer failed consistency check "
-                              " (%#llx) - aborting.\n", value1);
+                       pr_info("PM-Timer failed consistency check  (%#llx) - aborting.\n",
+                               value1);
                        pmtmr_ioport = 0;
                        return -ENODEV;
                }
index a2cb6fae92958b7319c55ee20ef21e26268ffbea..d189d8cb69f70244cacca5a331b32e5beca4b5f1 100644 (file)
@@ -99,17 +99,17 @@ static void gt_compare_set(unsigned long delta, int periodic)
 
        counter += delta;
        ctrl = GT_CONTROL_TIMER_ENABLE;
-       writel(ctrl, gt_base + GT_CONTROL);
-       writel(lower_32_bits(counter), gt_base + GT_COMP0);
-       writel(upper_32_bits(counter), gt_base + GT_COMP1);
+       writel_relaxed(ctrl, gt_base + GT_CONTROL);
+       writel_relaxed(lower_32_bits(counter), gt_base + GT_COMP0);
+       writel_relaxed(upper_32_bits(counter), gt_base + GT_COMP1);
 
        if (periodic) {
-               writel(delta, gt_base + GT_AUTO_INC);
+               writel_relaxed(delta, gt_base + GT_AUTO_INC);
                ctrl |= GT_CONTROL_AUTO_INC;
        }
 
        ctrl |= GT_CONTROL_COMP_ENABLE | GT_CONTROL_IRQ_ENABLE;
-       writel(ctrl, gt_base + GT_CONTROL);
+       writel_relaxed(ctrl, gt_base + GT_CONTROL);
 }
 
 static int gt_clockevent_shutdown(struct clock_event_device *evt)
@@ -195,12 +195,23 @@ static cycle_t gt_clocksource_read(struct clocksource *cs)
        return gt_counter_read();
 }
 
+static void gt_resume(struct clocksource *cs)
+{
+       unsigned long ctrl;
+
+       ctrl = readl(gt_base + GT_CONTROL);
+       if (!(ctrl & GT_CONTROL_TIMER_ENABLE))
+               /* re-enable timer on resume */
+               writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
+}
+
 static struct clocksource gt_clocksource = {
        .name   = "arm_global_timer",
        .rating = 300,
        .read   = gt_clocksource_read,
        .mask   = CLOCKSOURCE_MASK(64),
        .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+       .resume = gt_resume,
 };
 
 #ifdef CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
index c76c75006ea6c412eedeaa790ef1f602123bc54b..63345260244d7d97df303b3fd12445612e6b4395 100644 (file)
@@ -49,20 +49,31 @@ clocksource_to_dw_apb_clocksource(struct clocksource *cs)
        return container_of(cs, struct dw_apb_clocksource, cs);
 }
 
-static unsigned long apbt_readl(struct dw_apb_timer *timer, unsigned long offs)
+static inline u32 apbt_readl(struct dw_apb_timer *timer, unsigned long offs)
 {
        return readl(timer->base + offs);
 }
 
-static void apbt_writel(struct dw_apb_timer *timer, unsigned long val,
-                unsigned long offs)
+static inline void apbt_writel(struct dw_apb_timer *timer, u32 val,
+                       unsigned long offs)
 {
        writel(val, timer->base + offs);
 }
 
+static inline u32 apbt_readl_relaxed(struct dw_apb_timer *timer, unsigned long offs)
+{
+       return readl_relaxed(timer->base + offs);
+}
+
+static inline void apbt_writel_relaxed(struct dw_apb_timer *timer, u32 val,
+                       unsigned long offs)
+{
+       writel_relaxed(val, timer->base + offs);
+}
+
 static void apbt_disable_int(struct dw_apb_timer *timer)
 {
-       unsigned long ctrl = apbt_readl(timer, APBTMR_N_CONTROL);
+       u32 ctrl = apbt_readl(timer, APBTMR_N_CONTROL);
 
        ctrl |= APBTMR_CONTROL_INT;
        apbt_writel(timer, ctrl, APBTMR_N_CONTROL);
@@ -81,7 +92,7 @@ void dw_apb_clockevent_pause(struct dw_apb_clock_event_device *dw_ced)
 
 static void apbt_eoi(struct dw_apb_timer *timer)
 {
-       apbt_readl(timer, APBTMR_N_EOI);
+       apbt_readl_relaxed(timer, APBTMR_N_EOI);
 }
 
 static irqreturn_t dw_apb_clockevent_irq(int irq, void *data)
@@ -103,7 +114,7 @@ static irqreturn_t dw_apb_clockevent_irq(int irq, void *data)
 
 static void apbt_enable_int(struct dw_apb_timer *timer)
 {
-       unsigned long ctrl = apbt_readl(timer, APBTMR_N_CONTROL);
+       u32 ctrl = apbt_readl(timer, APBTMR_N_CONTROL);
        /* clear pending intr */
        apbt_readl(timer, APBTMR_N_EOI);
        ctrl &= ~APBTMR_CONTROL_INT;
@@ -113,7 +124,7 @@ static void apbt_enable_int(struct dw_apb_timer *timer)
 static int apbt_shutdown(struct clock_event_device *evt)
 {
        struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
-       unsigned long ctrl;
+       u32 ctrl;
 
        pr_debug("%s CPU %d state=shutdown\n", __func__,
                 cpumask_first(evt->cpumask));
@@ -127,7 +138,7 @@ static int apbt_shutdown(struct clock_event_device *evt)
 static int apbt_set_oneshot(struct clock_event_device *evt)
 {
        struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
-       unsigned long ctrl;
+       u32 ctrl;
 
        pr_debug("%s CPU %d state=oneshot\n", __func__,
                 cpumask_first(evt->cpumask));
@@ -160,7 +171,7 @@ static int apbt_set_periodic(struct clock_event_device *evt)
 {
        struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
        unsigned long period = DIV_ROUND_UP(dw_ced->timer.freq, HZ);
-       unsigned long ctrl;
+       u32 ctrl;
 
        pr_debug("%s CPU %d state=periodic\n", __func__,
                 cpumask_first(evt->cpumask));
@@ -196,17 +207,17 @@ static int apbt_resume(struct clock_event_device *evt)
 static int apbt_next_event(unsigned long delta,
                           struct clock_event_device *evt)
 {
-       unsigned long ctrl;
+       u32 ctrl;
        struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
 
        /* Disable timer */
-       ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL);
+       ctrl = apbt_readl_relaxed(&dw_ced->timer, APBTMR_N_CONTROL);
        ctrl &= ~APBTMR_CONTROL_ENABLE;
-       apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
+       apbt_writel_relaxed(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
        /* write new count */
-       apbt_writel(&dw_ced->timer, delta, APBTMR_N_LOAD_COUNT);
+       apbt_writel_relaxed(&dw_ced->timer, delta, APBTMR_N_LOAD_COUNT);
        ctrl |= APBTMR_CONTROL_ENABLE;
-       apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
+       apbt_writel_relaxed(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
 
        return 0;
 }
@@ -323,7 +334,7 @@ void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs)
         * start count down from 0xffff_ffff. this is done by toggling the
         * enable bit then load initial load count to ~0.
         */
-       unsigned long ctrl = apbt_readl(&dw_cs->timer, APBTMR_N_CONTROL);
+       u32 ctrl = apbt_readl(&dw_cs->timer, APBTMR_N_CONTROL);
 
        ctrl &= ~APBTMR_CONTROL_ENABLE;
        apbt_writel(&dw_cs->timer, ctrl, APBTMR_N_CONTROL);
@@ -338,11 +349,12 @@ void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs)
 
 static cycle_t __apbt_read_clocksource(struct clocksource *cs)
 {
-       unsigned long current_count;
+       u32 current_count;
        struct dw_apb_clocksource *dw_cs =
                clocksource_to_dw_apb_clocksource(cs);
 
-       current_count = apbt_readl(&dw_cs->timer, APBTMR_N_CURRENT_VALUE);
+       current_count = apbt_readl_relaxed(&dw_cs->timer,
+                                       APBTMR_N_CURRENT_VALUE);
 
        return (cycle_t)~current_count;
 }
index a19a3f619cc755d3a9a04dbdcde24b230cb30d6d..860843cef5725f6a4d64fc515d9ccac7b88b2457 100644 (file)
@@ -16,6 +16,7 @@
  * 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/delay.h>
 #include <linux/dw_apb_timer.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
@@ -130,6 +131,17 @@ static void __init init_sched_clock(void)
        sched_clock_register(read_sched_clock, 32, sched_rate);
 }
 
+#ifdef CONFIG_ARM
+static unsigned long dw_apb_delay_timer_read(void)
+{
+       return ~readl_relaxed(sched_io_base);
+}
+
+static struct delay_timer dw_apb_delay_timer = {
+       .read_current_timer     = dw_apb_delay_timer_read,
+};
+#endif
+
 static int num_called;
 static void __init dw_apb_timer_init(struct device_node *timer)
 {
@@ -142,6 +154,10 @@ static void __init dw_apb_timer_init(struct device_node *timer)
                pr_debug("%s: found clocksource timer\n", __func__);
                add_clocksource(timer);
                init_sched_clock();
+#ifdef CONFIG_ARM
+               dw_apb_delay_timer.freq = sched_rate;
+               register_current_timer_delay(&dw_apb_delay_timer);
+#endif
                break;
        default:
                break;
index 0e076c6fc006b26b52729c9389db7d87a9604ce3..75c44079b3454513b2f6a788872b4c579c7f27b8 100644 (file)
@@ -4,85 +4,56 @@
  *  Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp>
  */
 
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
-#include <linux/platform_device.h>
 #include <linux/clocksource.h>
-#include <linux/module.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/of.h>
-
-#include <asm/segment.h>
-#include <asm/irq.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 
 #define TSTR   0
-#define TSNC   1
-#define TMDR   2
-#define TOLR   3
-#define TISRA  4
-#define TISRB  5
 #define TISRC  6
 
 #define TCR    0
-#define TIOR   1
 #define TCNT   2
-#define GRA    4
-#define GRB    6
-
-#define FLAG_REPROGRAM (1 << 0)
-#define FLAG_SKIPEVENT (1 << 1)
-#define FLAG_IRQCONTEXT (1 << 2)
-#define FLAG_STARTED (1 << 3)
 
-#define ONESHOT  0
-#define PERIODIC 1
-
-#define RELATIVE 0
-#define ABSOLUTE 1
+#define bset(b, a) iowrite8(ioread8(a) | (1 << (b)), (a))
+#define bclr(b, a) iowrite8(ioread8(a) & ~(1 << (b)), (a))
 
 struct timer16_priv {
-       struct platform_device *pdev;
        struct clocksource cs;
-       struct irqaction irqaction;
        unsigned long total_cycles;
-       unsigned long mapbase;
-       unsigned long mapcommon;
-       unsigned long flags;
-       unsigned short gra;
+       void __iomem *mapbase;
+       void __iomem *mapcommon;
        unsigned short cs_enabled;
        unsigned char enb;
-       unsigned char imfa;
-       unsigned char imiea;
        unsigned char ovf;
-       raw_spinlock_t lock;
-       struct clk *clk;
+       unsigned char ovie;
 };
 
 static unsigned long timer16_get_counter(struct timer16_priv *p)
 {
-       unsigned long v1, v2, v3;
-       int o1, o2;
+       unsigned short v1, v2, v3;
+       unsigned char  o1, o2;
 
-       o1 = ctrl_inb(p->mapcommon + TISRC) & p->ovf;
+       o1 = ioread8(p->mapcommon + TISRC) & p->ovf;
 
        /* Make sure the timer value is stable. Stolen from acpi_pm.c */
        do {
                o2 = o1;
-               v1 = ctrl_inw(p->mapbase + TCNT);
-               v2 = ctrl_inw(p->mapbase + TCNT);
-               v3 = ctrl_inw(p->mapbase + TCNT);
-               o1 = ctrl_inb(p->mapcommon + TISRC) & p->ovf;
+               v1 = ioread16be(p->mapbase + TCNT);
+               v2 = ioread16be(p->mapbase + TCNT);
+               v3 = ioread16be(p->mapbase + TCNT);
+               o1 = ioread8(p->mapcommon + TISRC) & p->ovf;
        } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
                          || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
 
-       v2 |= 0x10000;
-       return v2;
+       if (likely(!o1))
+               return v2;
+       else
+               return v2 + 0x10000;
 }
 
 
@@ -90,8 +61,7 @@ static irqreturn_t timer16_interrupt(int irq, void *dev_id)
 {
        struct timer16_priv *p = (struct timer16_priv *)dev_id;
 
-       ctrl_outb(ctrl_inb(p->mapcommon + TISRA) & ~p->imfa,
-                 p->mapcommon + TISRA);
+       bclr(p->ovf, p->mapcommon + TISRC);
        p->total_cycles += 0x10000;
 
        return IRQ_HANDLED;
@@ -105,13 +75,10 @@ static inline struct timer16_priv *cs_to_priv(struct clocksource *cs)
 static cycle_t timer16_clocksource_read(struct clocksource *cs)
 {
        struct timer16_priv *p = cs_to_priv(cs);
-       unsigned long flags, raw;
-       unsigned long value;
+       unsigned long raw, value;
 
-       raw_spin_lock_irqsave(&p->lock, flags);
        value = p->total_cycles;
        raw = timer16_get_counter(p);
-       raw_spin_unlock_irqrestore(&p->lock, flags);
 
        return value + raw;
 }
@@ -123,10 +90,10 @@ static int timer16_enable(struct clocksource *cs)
        WARN_ON(p->cs_enabled);
 
        p->total_cycles = 0;
-       ctrl_outw(0x0000, p->mapbase + TCNT);
-       ctrl_outb(0x83, p->mapbase + TCR);
-       ctrl_outb(ctrl_inb(p->mapcommon + TSTR) | p->enb,
-                 p->mapcommon + TSTR);
+       iowrite16be(0x0000, p->mapbase + TCNT);
+       iowrite8(0x83, p->mapbase + TCR);
+       bset(p->ovie, p->mapcommon + TISRC);
+       bset(p->enb, p->mapcommon + TSTR);
 
        p->cs_enabled = true;
        return 0;
@@ -138,116 +105,83 @@ static void timer16_disable(struct clocksource *cs)
 
        WARN_ON(!p->cs_enabled);
 
-       ctrl_outb(ctrl_inb(p->mapcommon + TSTR) & ~p->enb,
-                 p->mapcommon + TSTR);
+       bclr(p->ovie, p->mapcommon + TISRC);
+       bclr(p->enb, p->mapcommon + TSTR);
 
        p->cs_enabled = false;
 }
 
+static struct timer16_priv timer16_priv = {
+       .cs = {
+               .name = "h8300_16timer",
+               .rating = 200,
+               .read = timer16_clocksource_read,
+               .enable = timer16_enable,
+               .disable = timer16_disable,
+               .mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8),
+               .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+       },
+};
+
 #define REG_CH   0
 #define REG_COMM 1
 
-static int timer16_setup(struct timer16_priv *p, struct platform_device *pdev)
+static void __init h8300_16timer_init(struct device_node *node)
 {
-       struct resource *res[2];
+       void __iomem *base[2];
        int ret, irq;
        unsigned int ch;
+       struct clk *clk;
 
-       p->pdev = pdev;
-
-       res[REG_CH] = platform_get_resource(p->pdev,
-                                           IORESOURCE_MEM, REG_CH);
-       res[REG_COMM] = platform_get_resource(p->pdev,
-                                             IORESOURCE_MEM, REG_COMM);
-       if (!res[REG_CH] || !res[REG_COMM]) {
-               dev_err(&p->pdev->dev, "failed to get I/O memory\n");
-               return -ENXIO;
-       }
-       irq = platform_get_irq(p->pdev, 0);
-       if (irq < 0) {
-               dev_err(&p->pdev->dev, "failed to get irq\n");
-               return irq;
+       clk = of_clk_get(node, 0);
+       if (IS_ERR(clk)) {
+               pr_err("failed to get clock for clocksource\n");
+               return;
        }
 
-       p->clk = clk_get(&p->pdev->dev, "fck");
-       if (IS_ERR(p->clk)) {
-               dev_err(&p->pdev->dev, "can't get clk\n");
-               return PTR_ERR(p->clk);
+       base[REG_CH] = of_iomap(node, 0);
+       if (!base[REG_CH]) {
+               pr_err("failed to map registers for clocksource\n");
+               goto free_clk;
        }
-       of_property_read_u32(p->pdev->dev.of_node, "renesas,channel", &ch);
-
-       p->pdev = pdev;
-       p->mapbase = res[REG_CH]->start;
-       p->mapcommon = res[REG_COMM]->start;
-       p->enb = 1 << ch;
-       p->imfa = 1 << ch;
-       p->imiea = 1 << (4 + ch);
-       p->cs.name = pdev->name;
-       p->cs.rating = 200;
-       p->cs.read = timer16_clocksource_read;
-       p->cs.enable = timer16_enable;
-       p->cs.disable = timer16_disable;
-       p->cs.mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
-       p->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
 
-       ret = request_irq(irq, timer16_interrupt,
-                         IRQF_TIMER, pdev->name, p);
-       if (ret < 0) {
-               dev_err(&p->pdev->dev, "failed to request irq %d\n", irq);
-               return ret;
+       base[REG_COMM] = of_iomap(node, 1);
+       if (!base[REG_COMM]) {
+               pr_err("failed to map registers for clocksource\n");
+               goto unmap_ch;
        }
 
-       clocksource_register_hz(&p->cs, clk_get_rate(p->clk) / 8);
-
-       return 0;
-}
-
-static int timer16_probe(struct platform_device *pdev)
-{
-       struct timer16_priv *p = platform_get_drvdata(pdev);
-
-       if (p) {
-               dev_info(&pdev->dev, "kept as earlytimer\n");
-               return 0;
+       irq = irq_of_parse_and_map(node, 0);
+       if (!irq) {
+               pr_err("failed to get irq for clockevent\n");
+               goto unmap_comm;
        }
 
-       p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
-       if (!p)
-               return -ENOMEM;
+       of_property_read_u32(node, "renesas,channel", &ch);
 
-       return timer16_setup(p, pdev);
-}
-
-static int timer16_remove(struct platform_device *pdev)
-{
-       return -EBUSY;
-}
+       timer16_priv.mapbase = base[REG_CH];
+       timer16_priv.mapcommon = base[REG_COMM];
+       timer16_priv.enb = ch;
+       timer16_priv.ovf = ch;
+       timer16_priv.ovie = 4 + ch;
 
-static const struct of_device_id timer16_of_table[] = {
-       { .compatible = "renesas,16bit-timer" },
-       { }
-};
-static struct platform_driver timer16_driver = {
-       .probe          = timer16_probe,
-       .remove         = timer16_remove,
-       .driver         = {
-               .name   = "h8300h-16timer",
-               .of_match_table = of_match_ptr(timer16_of_table),
+       ret = request_irq(irq, timer16_interrupt,
+                         IRQF_TIMER, timer16_priv.cs.name, &timer16_priv);
+       if (ret < 0) {
+               pr_err("failed to request irq %d of clocksource\n", irq);
+               goto unmap_comm;
        }
-};
 
-static int __init timer16_init(void)
-{
-       return platform_driver_register(&timer16_driver);
-}
+       clocksource_register_hz(&timer16_priv.cs,
+                               clk_get_rate(clk) / 8);
+       return;
 
-static void __exit timer16_exit(void)
-{
-       platform_driver_unregister(&timer16_driver);
+unmap_comm:
+       iounmap(base[REG_COMM]);
+unmap_ch:
+       iounmap(base[REG_CH]);
+free_clk:
+       clk_put(clk);
 }
 
-subsys_initcall(timer16_init);
-module_exit(timer16_exit);
-MODULE_AUTHOR("Yoshinori Sato");
-MODULE_DESCRIPTION("H8/300H 16bit Timer Driver");
-MODULE_LICENSE("GPL v2");
+CLOCKSOURCE_OF_DECLARE(h8300_16bit, "renesas,16bit-timer", h8300_16timer_init);
index 44375d8b9bc438878be58699fb95ce8fb624ebc6..c151941e1956d3a8338edeeeefd4c09e0d78066c 100644 (file)
@@ -8,19 +8,15 @@
  */
 
 #include <linux/errno.h>
-#include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
 #include <linux/clockchips.h>
-#include <linux/module.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/of.h>
-
-#include <asm/irq.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 
 #define _8TCR  0
 #define _8TCSR 2
 #define TCORB  6
 #define _8TCNT 8
 
-#define FLAG_REPROGRAM (1 << 0)
-#define FLAG_SKIPEVENT (1 << 1)
-#define FLAG_IRQCONTEXT (1 << 2)
+#define CMIEA  6
+#define CMFA   6
+
 #define FLAG_STARTED (1 << 3)
 
-#define ONESHOT  0
-#define PERIODIC 1
+#define SCALE 64
 
-#define RELATIVE 0
-#define ABSOLUTE 1
+#define bset(b, a) iowrite8(ioread8(a) | (1 << (b)), (a))
+#define bclr(b, a) iowrite8(ioread8(a) & ~(1 << (b)), (a))
 
 struct timer8_priv {
-       struct platform_device *pdev;
        struct clock_event_device ced;
-       struct irqaction irqaction;
-       unsigned long mapbase;
-       raw_spinlock_t lock;
+       void __iomem *mapbase;
        unsigned long flags;
        unsigned int rate;
-       unsigned int tcora;
-       struct clk *pclk;
 };
 
-static unsigned long timer8_get_counter(struct timer8_priv *p)
-{
-       unsigned long v1, v2, v3;
-       int o1, o2;
-
-       o1 = ctrl_inb(p->mapbase + _8TCSR) & 0x20;
-
-       /* Make sure the timer value is stable. Stolen from acpi_pm.c */
-       do {
-               o2 = o1;
-               v1 = ctrl_inw(p->mapbase + _8TCNT);
-               v2 = ctrl_inw(p->mapbase + _8TCNT);
-               v3 = ctrl_inw(p->mapbase + _8TCNT);
-               o1 = ctrl_inb(p->mapbase + _8TCSR) & 0x20;
-       } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
-                         || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
-
-       v2 |= o1 << 10;
-       return v2;
-}
-
 static irqreturn_t timer8_interrupt(int irq, void *dev_id)
 {
        struct timer8_priv *p = dev_id;
 
-       ctrl_outb(ctrl_inb(p->mapbase + _8TCSR) & ~0x40,
-                 p->mapbase + _8TCSR);
-       p->flags |= FLAG_IRQCONTEXT;
-       ctrl_outw(p->tcora, p->mapbase + TCORA);
-       if (!(p->flags & FLAG_SKIPEVENT)) {
-               if (clockevent_state_oneshot(&p->ced))
-                       ctrl_outw(0x0000, p->mapbase + _8TCR);
-               p->ced.event_handler(&p->ced);
-       }
-       p->flags &= ~(FLAG_SKIPEVENT | FLAG_IRQCONTEXT);
+       if (clockevent_state_oneshot(&p->ced))
+               iowrite16be(0x0000, p->mapbase + _8TCR);
+
+       p->ced.event_handler(&p->ced);
+
+       bclr(CMFA, p->mapbase + _8TCSR);
 
        return IRQ_HANDLED;
 }
 
 static void timer8_set_next(struct timer8_priv *p, unsigned long delta)
 {
-       unsigned long flags;
-       unsigned long now;
-
-       raw_spin_lock_irqsave(&p->lock, flags);
        if (delta >= 0x10000)
-               dev_warn(&p->pdev->dev, "delta out of range\n");
-       now = timer8_get_counter(p);
-       p->tcora = delta;
-       ctrl_outb(ctrl_inb(p->mapbase + _8TCR) | 0x40, p->mapbase + _8TCR);
-       if (delta > now)
-               ctrl_outw(delta, p->mapbase + TCORA);
-       else
-               ctrl_outw(now + 1, p->mapbase + TCORA);
-
-       raw_spin_unlock_irqrestore(&p->lock, flags);
+               pr_warn("delta out of range\n");
+       bclr(CMIEA, p->mapbase + _8TCR);
+       iowrite16be(delta, p->mapbase + TCORA);
+       iowrite16be(0x0000, p->mapbase + _8TCNT);
+       bclr(CMFA, p->mapbase + _8TCSR);
+       bset(CMIEA, p->mapbase + _8TCR);
 }
 
 static int timer8_enable(struct timer8_priv *p)
 {
-       p->rate = clk_get_rate(p->pclk) / 64;
-       ctrl_outw(0xffff, p->mapbase + TCORA);
-       ctrl_outw(0x0000, p->mapbase + _8TCNT);
-       ctrl_outw(0x0c02, p->mapbase + _8TCR);
+       iowrite16be(0xffff, p->mapbase + TCORA);
+       iowrite16be(0x0000, p->mapbase + _8TCNT);
+       iowrite16be(0x0c02, p->mapbase + _8TCR);
 
        return 0;
 }
 
 static int timer8_start(struct timer8_priv *p)
 {
-       int ret = 0;
-       unsigned long flags;
-
-       raw_spin_lock_irqsave(&p->lock, flags);
-
-       if (!(p->flags & FLAG_STARTED))
-               ret = timer8_enable(p);
+       int ret;
 
-       if (ret)
-               goto out;
-       p->flags |= FLAG_STARTED;
+       if ((p->flags & FLAG_STARTED))
+               return 0;
 
- out:
-       raw_spin_unlock_irqrestore(&p->lock, flags);
+       ret = timer8_enable(p);
+       if (!ret)
+               p->flags |= FLAG_STARTED;
 
        return ret;
 }
 
 static void timer8_stop(struct timer8_priv *p)
 {
-       unsigned long flags;
-
-       raw_spin_lock_irqsave(&p->lock, flags);
-
-       ctrl_outw(0x0000, p->mapbase + _8TCR);
-
-       raw_spin_unlock_irqrestore(&p->lock, flags);
+       iowrite16be(0x0000, p->mapbase + _8TCR);
 }
 
 static inline struct timer8_priv *ced_to_priv(struct clock_event_device *ced)
@@ -155,7 +99,7 @@ static inline struct timer8_priv *ced_to_priv(struct clock_event_device *ced)
        return container_of(ced, struct timer8_priv, ced);
 }
 
-static void timer8_clock_event_start(struct timer8_priv *p, int periodic)
+static void timer8_clock_event_start(struct timer8_priv *p, unsigned long delta)
 {
        struct clock_event_device *ced = &p->ced;
 
@@ -166,7 +110,7 @@ static void timer8_clock_event_start(struct timer8_priv *p, int periodic)
        ced->max_delta_ns = clockevent_delta2ns(0xffff, ced);
        ced->min_delta_ns = clockevent_delta2ns(0x0001, ced);
 
-       timer8_set_next(p, periodic?(p->rate + HZ/2) / HZ:0x10000);
+       timer8_set_next(p, delta);
 }
 
 static int timer8_clock_event_shutdown(struct clock_event_device *ced)
@@ -179,9 +123,9 @@ static int timer8_clock_event_periodic(struct clock_event_device *ced)
 {
        struct timer8_priv *p = ced_to_priv(ced);
 
-       dev_info(&p->pdev->dev, "used for periodic clock events\n");
+       pr_info("%s: used for periodic clock events\n", ced->name);
        timer8_stop(p);
-       timer8_clock_event_start(p, PERIODIC);
+       timer8_clock_event_start(p, (p->rate + HZ/2) / HZ);
 
        return 0;
 }
@@ -190,9 +134,9 @@ static int timer8_clock_event_oneshot(struct clock_event_device *ced)
 {
        struct timer8_priv *p = ced_to_priv(ced);
 
-       dev_info(&p->pdev->dev, "used for oneshot clock events\n");
+       pr_info("%s: used for oneshot clock events\n", ced->name);
        timer8_stop(p);
-       timer8_clock_event_start(p, ONESHOT);
+       timer8_clock_event_start(p, 0x10000);
 
        return 0;
 }
@@ -208,110 +152,64 @@ static int timer8_clock_event_next(unsigned long delta,
        return 0;
 }
 
-static int timer8_setup(struct timer8_priv *p,
-                       struct platform_device *pdev)
+static struct timer8_priv timer8_priv = {
+       .ced = {
+               .name = "h8300_8timer",
+               .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+               .rating = 200,
+               .set_next_event = timer8_clock_event_next,
+               .set_state_shutdown = timer8_clock_event_shutdown,
+               .set_state_periodic = timer8_clock_event_periodic,
+               .set_state_oneshot = timer8_clock_event_oneshot,
+       },
+};
+
+static void __init h8300_8timer_init(struct device_node *node)
 {
-       struct resource *res;
+       void __iomem *base;
        int irq;
-       int ret;
+       struct clk *clk;
 
-       p->pdev = pdev;
-
-       res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&p->pdev->dev, "failed to get I/O memory\n");
-               return -ENXIO;
+       clk = of_clk_get(node, 0);
+       if (IS_ERR(clk)) {
+               pr_err("failed to get clock for clockevent\n");
+               return;
        }
 
-       irq = platform_get_irq(p->pdev, 0);
-       if (irq < 0) {
-               dev_err(&p->pdev->dev, "failed to get irq\n");
-               return -ENXIO;
+       base = of_iomap(node, 0);
+       if (!base) {
+               pr_err("failed to map registers for clockevent\n");
+               goto free_clk;
        }
 
-       p->mapbase = res->start;
-
-       p->irqaction.name = dev_name(&p->pdev->dev);
-       p->irqaction.handler = timer8_interrupt;
-       p->irqaction.dev_id = p;
-       p->irqaction.flags = IRQF_TIMER;
-
-       p->pclk = clk_get(&p->pdev->dev, "fck");
-       if (IS_ERR(p->pclk)) {
-               dev_err(&p->pdev->dev, "can't get clk\n");
-               return PTR_ERR(p->pclk);
+       irq = irq_of_parse_and_map(node, 0);
+       if (!irq) {
+               pr_err("failed to get irq for clockevent\n");
+               goto unmap_reg;
        }
 
-       p->ced.name = pdev->name;
-       p->ced.features = CLOCK_EVT_FEAT_PERIODIC |
-               CLOCK_EVT_FEAT_ONESHOT;
-       p->ced.rating = 200;
-       p->ced.cpumask = cpumask_of(0);
-       p->ced.set_next_event = timer8_clock_event_next;
-       p->ced.set_state_shutdown = timer8_clock_event_shutdown;
-       p->ced.set_state_periodic = timer8_clock_event_periodic;
-       p->ced.set_state_oneshot = timer8_clock_event_oneshot;
-
-       ret = setup_irq(irq, &p->irqaction);
-       if (ret < 0) {
-               dev_err(&p->pdev->dev,
-                       "failed to request irq %d\n", irq);
-               return ret;
-       }
-       clockevents_register_device(&p->ced);
-       platform_set_drvdata(pdev, p);
+       timer8_priv.mapbase = base;
 
-       return 0;
-}
-
-static int timer8_probe(struct platform_device *pdev)
-{
-       struct timer8_priv *p = platform_get_drvdata(pdev);
-
-       if (p) {
-               dev_info(&pdev->dev, "kept as earlytimer\n");
-               return 0;
+       timer8_priv.rate = clk_get_rate(clk) / SCALE;
+       if (!timer8_priv.rate) {
+               pr_err("Failed to get rate for the clocksource\n");
+               goto unmap_reg;
        }
 
-       p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
-       if (!p)
-               return -ENOMEM;
-
-       return timer8_setup(p, pdev);
-}
-
-static int timer8_remove(struct platform_device *pdev)
-{
-       return -EBUSY;
-}
-
-static const struct of_device_id timer8_of_table[] __maybe_unused = {
-       { .compatible = "renesas,8bit-timer" },
-       { }
-};
-
-MODULE_DEVICE_TABLE(of, timer8_of_table);
-static struct platform_driver timer8_driver = {
-       .probe          = timer8_probe,
-       .remove         = timer8_remove,
-       .driver         = {
-               .name   = "h8300-8timer",
-               .of_match_table = of_match_ptr(timer8_of_table),
+       if (request_irq(irq, timer8_interrupt, IRQF_TIMER,
+                       timer8_priv.ced.name, &timer8_priv) < 0) {
+               pr_err("failed to request irq %d for clockevent\n", irq);
+               goto unmap_reg;
        }
-};
 
-static int __init timer8_init(void)
-{
-       return platform_driver_register(&timer8_driver);
-}
+       clockevents_config_and_register(&timer8_priv.ced,
+                                       timer8_priv.rate, 1, 0x0000ffff);
 
-static void __exit timer8_exit(void)
-{
-       platform_driver_unregister(&timer8_driver);
+       return;
+unmap_reg:
+       iounmap(base);
+free_clk:
+       clk_put(clk);
 }
 
-subsys_initcall(timer8_init);
-module_exit(timer8_exit);
-MODULE_AUTHOR("Yoshinori Sato");
-MODULE_DESCRIPTION("H8/300 8bit Timer Driver");
-MODULE_LICENSE("GPL v2");
+CLOCKSOURCE_OF_DECLARE(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init);
index 5487410bfabb93b0c4768a91870485f6ba77d31f..d4c1a287c2622e459bbe544399e872cddcc44439 100644 (file)
@@ -1,42 +1,30 @@
 /*
- *  H8/300 TPU Driver
+ *  H8S TPU Driver
  *
  *  Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp>
  *
  */
 
 #include <linux/errno.h>
-#include <linux/sched.h>
 #include <linux/kernel.h>
-#include <linux/interrupt.h>
 #include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
 #include <linux/clocksource.h>
-#include <linux/module.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 
-#include <asm/irq.h>
+#define TCR    0x0
+#define TSR    0x5
+#define TCNT   0x6
 
-#define TCR    0
-#define TMDR   1
-#define TIOR   2
-#define TER    4
-#define TSR    5
-#define TCNT   6
-#define TGRA   8
-#define TGRB   10
-#define TGRC   12
-#define TGRD   14
+#define TCFV   0x10
 
 struct tpu_priv {
-       struct platform_device *pdev;
        struct clocksource cs;
-       struct clk *clk;
-       unsigned long mapbase1;
-       unsigned long mapbase2;
+       void __iomem *mapbase1;
+       void __iomem *mapbase2;
        raw_spinlock_t lock;
        unsigned int cs_enabled;
 };
@@ -45,8 +33,8 @@ static inline unsigned long read_tcnt32(struct tpu_priv *p)
 {
        unsigned long tcnt;
 
-       tcnt = ctrl_inw(p->mapbase1 + TCNT) << 16;
-       tcnt |= ctrl_inw(p->mapbase2 + TCNT);
+       tcnt = ioread16be(p->mapbase1 + TCNT) << 16;
+       tcnt |= ioread16be(p->mapbase2 + TCNT);
        return tcnt;
 }
 
@@ -55,7 +43,7 @@ static int tpu_get_counter(struct tpu_priv *p, unsigned long long *val)
        unsigned long v1, v2, v3;
        int o1, o2;
 
-       o1 = ctrl_inb(p->mapbase1 + TSR) & 0x10;
+       o1 = ioread8(p->mapbase1 + TSR) & TCFV;
 
        /* Make sure the timer value is stable. Stolen from acpi_pm.c */
        do {
@@ -63,7 +51,7 @@ static int tpu_get_counter(struct tpu_priv *p, unsigned long long *val)
                v1 = read_tcnt32(p);
                v2 = read_tcnt32(p);
                v3 = read_tcnt32(p);
-               o1 = ctrl_inb(p->mapbase1 + TSR) & 0x10;
+               o1 = ioread8(p->mapbase1 + TSR) & TCFV;
        } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
                          || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
 
@@ -96,10 +84,10 @@ static int tpu_clocksource_enable(struct clocksource *cs)
 
        WARN_ON(p->cs_enabled);
 
-       ctrl_outw(0, p->mapbase1 + TCNT);
-       ctrl_outw(0, p->mapbase2 + TCNT);
-       ctrl_outb(0x0f, p->mapbase1 + TCR);
-       ctrl_outb(0x03, p->mapbase2 + TCR);
+       iowrite16be(0, p->mapbase1 + TCNT);
+       iowrite16be(0, p->mapbase2 + TCNT);
+       iowrite8(0x0f, p->mapbase1 + TCR);
+       iowrite8(0x03, p->mapbase2 + TCR);
 
        p->cs_enabled = true;
        return 0;
@@ -111,96 +99,59 @@ static void tpu_clocksource_disable(struct clocksource *cs)
 
        WARN_ON(!p->cs_enabled);
 
-       ctrl_outb(0, p->mapbase1 + TCR);
-       ctrl_outb(0, p->mapbase2 + TCR);
+       iowrite8(0, p->mapbase1 + TCR);
+       iowrite8(0, p->mapbase2 + TCR);
        p->cs_enabled = false;
 }
 
+static struct tpu_priv tpu_priv = {
+       .cs = {
+               .name = "H8S_TPU",
+               .rating = 200,
+               .read = tpu_clocksource_read,
+               .enable = tpu_clocksource_enable,
+               .disable = tpu_clocksource_disable,
+               .mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8),
+               .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+       },
+};
+
 #define CH_L 0
 #define CH_H 1
 
-static int __init tpu_setup(struct tpu_priv *p, struct platform_device *pdev)
+static void __init h8300_tpu_init(struct device_node *node)
 {
-       struct resource *res[2];
-
-       p->pdev = pdev;
+       void __iomem *base[2];
+       struct clk *clk;
 
-       res[CH_L] = platform_get_resource(p->pdev, IORESOURCE_MEM, CH_L);
-       res[CH_H] = platform_get_resource(p->pdev, IORESOURCE_MEM, CH_H);
-       if (!res[CH_L] || !res[CH_H]) {
-               dev_err(&p->pdev->dev, "failed to get I/O memory\n");
-               return -ENXIO;
+       clk = of_clk_get(node, 0);
+       if (IS_ERR(clk)) {
+               pr_err("failed to get clock for clocksource\n");
+               return;
        }
 
-       p->clk = clk_get(&p->pdev->dev, "fck");
-       if (IS_ERR(p->clk)) {
-               dev_err(&p->pdev->dev, "can't get clk\n");
-               return PTR_ERR(p->clk);
+       base[CH_L] = of_iomap(node, CH_L);
+       if (!base[CH_L]) {
+               pr_err("failed to map registers for clocksource\n");
+               goto free_clk;
        }
-
-       p->mapbase1 = res[CH_L]->start;
-       p->mapbase2 = res[CH_H]->start;
-
-       p->cs.name = pdev->name;
-       p->cs.rating = 200;
-       p->cs.read = tpu_clocksource_read;
-       p->cs.enable = tpu_clocksource_enable;
-       p->cs.disable = tpu_clocksource_disable;
-       p->cs.mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
-       p->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
-       clocksource_register_hz(&p->cs, clk_get_rate(p->clk) / 64);
-       platform_set_drvdata(pdev, p);
-
-       return 0;
-}
-
-static int tpu_probe(struct platform_device *pdev)
-{
-       struct tpu_priv *p = platform_get_drvdata(pdev);
-
-       if (p) {
-               dev_info(&pdev->dev, "kept as earlytimer\n");
-               return 0;
+       base[CH_H] = of_iomap(node, CH_H);
+       if (!base[CH_H]) {
+               pr_err("failed to map registers for clocksource\n");
+               goto unmap_L;
        }
 
-       p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
-       if (!p)
-               return -ENOMEM;
+       tpu_priv.mapbase1 = base[CH_L];
+       tpu_priv.mapbase2 = base[CH_H];
 
-       return tpu_setup(p, pdev);
-}
-
-static int tpu_remove(struct platform_device *pdev)
-{
-       return -EBUSY;
-}
-
-static const struct of_device_id tpu_of_table[] = {
-       { .compatible = "renesas,tpu" },
-       { }
-};
+       clocksource_register_hz(&tpu_priv.cs, clk_get_rate(clk) / 64);
 
-static struct platform_driver tpu_driver = {
-       .probe          = tpu_probe,
-       .remove         = tpu_remove,
-       .driver         = {
-               .name   = "h8s-tpu",
-               .of_match_table = of_match_ptr(tpu_of_table),
-       }
-};
-
-static int __init tpu_init(void)
-{
-       return platform_driver_register(&tpu_driver);
-}
+       return;
 
-static void __exit tpu_exit(void)
-{
-       platform_driver_unregister(&tpu_driver);
+unmap_L:
+       iounmap(base[CH_H]);
+free_clk:
+       clk_put(clk);
 }
 
-subsys_initcall(tpu_init);
-module_exit(tpu_exit);
-MODULE_AUTHOR("Yoshinori Sato");
-MODULE_DESCRIPTION("H8S Timer Pulse Unit Driver");
-MODULE_LICENSE("GPL v2");
+CLOCKSOURCE_OF_DECLARE(h8300_tpu, "renesas,tpu", h8300_tpu_init);
index fbfc74685e6afba837ae549021f7fe763f7c0de4..d67bc356488ffd0590f76abea3c28087c051ffcb 100644 (file)
@@ -16,6 +16,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
 #include <linux/clk.h>
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
@@ -187,10 +189,8 @@ static void __init mtk_timer_init(struct device_node *node)
        struct clk *clk;
 
        evt = kzalloc(sizeof(*evt), GFP_KERNEL);
-       if (!evt) {
-               pr_warn("Can't allocate mtk clock event driver struct");
+       if (!evt)
                return;
-       }
 
        evt->dev.name = "mtk_tick";
        evt->dev.rating = 300;
@@ -204,31 +204,31 @@ static void __init mtk_timer_init(struct device_node *node)
 
        evt->gpt_base = of_io_request_and_map(node, 0, "mtk-timer");
        if (IS_ERR(evt->gpt_base)) {
-               pr_warn("Can't get resource\n");
-               return;
+               pr_err("Can't get resource\n");
+               goto err_kzalloc;
        }
 
        evt->dev.irq = irq_of_parse_and_map(node, 0);
        if (evt->dev.irq <= 0) {
-               pr_warn("Can't parse IRQ");
+               pr_err("Can't parse IRQ\n");
                goto err_mem;
        }
 
        clk = of_clk_get(node, 0);
        if (IS_ERR(clk)) {
-               pr_warn("Can't get timer clock");
+               pr_err("Can't get timer clock\n");
                goto err_irq;
        }
 
        if (clk_prepare_enable(clk)) {
-               pr_warn("Can't prepare clock");
+               pr_err("Can't prepare clock\n");
                goto err_clk_put;
        }
        rate = clk_get_rate(clk);
 
        if (request_irq(evt->dev.irq, mtk_timer_interrupt,
                        IRQF_TIMER | IRQF_IRQPOLL, "mtk_timer", evt)) {
-               pr_warn("failed to setup irq %d\n", evt->dev.irq);
+               pr_err("failed to setup irq %d\n", evt->dev.irq);
                goto err_clk_disable;
        }
 
@@ -260,5 +260,7 @@ err_mem:
        iounmap(evt->gpt_base);
        of_address_to_resource(node, 0, &res);
        release_mem_region(res.start, resource_size(&res));
+err_kzalloc:
+       kfree(evt);
 }
 CLOCKSOURCE_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init);
index d3c1742ded1af7655c3e2e77031ab3801ea84761..8c77a529d0d445bb91583f3256e7fdc4a6da6caf 100644 (file)
 
 #define TIMER_NAME "rk_timer"
 
-#define TIMER_LOAD_COUNT0 0x00
-#define TIMER_LOAD_COUNT1 0x04
-#define TIMER_CONTROL_REG 0x10
-#define TIMER_INT_STATUS 0x18
+#define TIMER_LOAD_COUNT0      0x00
+#define TIMER_LOAD_COUNT1      0x04
+#define TIMER_CONTROL_REG      0x10
+#define TIMER_INT_STATUS       0x18
 
-#define TIMER_DISABLE 0x0
-#define TIMER_ENABLE 0x1
-#define TIMER_MODE_FREE_RUNNING (0 << 1)
-#define TIMER_MODE_USER_DEFINED_COUNT (1 << 1)
-#define TIMER_INT_UNMASK (1 << 2)
+#define TIMER_DISABLE          0x0
+#define TIMER_ENABLE           0x1
+#define TIMER_MODE_FREE_RUNNING                        (0 << 1)
+#define TIMER_MODE_USER_DEFINED_COUNT          (1 << 1)
+#define TIMER_INT_UNMASK                       (1 << 2)
 
 struct bc_timer {
        struct clock_event_device ce;
@@ -49,14 +49,12 @@ static inline void __iomem *rk_base(struct clock_event_device *ce)
 static inline void rk_timer_disable(struct clock_event_device *ce)
 {
        writel_relaxed(TIMER_DISABLE, rk_base(ce) + TIMER_CONTROL_REG);
-       dsb();
 }
 
 static inline void rk_timer_enable(struct clock_event_device *ce, u32 flags)
 {
        writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags,
                       rk_base(ce) + TIMER_CONTROL_REG);
-       dsb();
 }
 
 static void rk_timer_update_counter(unsigned long cycles,
@@ -64,13 +62,11 @@ static void rk_timer_update_counter(unsigned long cycles,
 {
        writel_relaxed(cycles, rk_base(ce) + TIMER_LOAD_COUNT0);
        writel_relaxed(0, rk_base(ce) + TIMER_LOAD_COUNT1);
-       dsb();
 }
 
 static void rk_timer_interrupt_clear(struct clock_event_device *ce)
 {
        writel_relaxed(1, rk_base(ce) + TIMER_INT_STATUS);
-       dsb();
 }
 
 static inline int rk_timer_set_next_event(unsigned long cycles,
@@ -173,4 +169,5 @@ static void __init rk_timer_init(struct device_node *np)
 
        clockevents_config_and_register(ce, bc_timer.freq, 1, UINT_MAX);
 }
+
 CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init);
index d297b30d2bc03cb5f19e195fdf18d765b4b6a3e9..2bcecafdeaeac76b2e4decf3dda66d8d7a6f027b 100644 (file)
@@ -19,19 +19,6 @@ static u64 notrace read_sched_clock(void)
        return read_xtal_counter();
 }
 
-static cycle_t read_clocksource(struct clocksource *cs)
-{
-       return read_xtal_counter();
-}
-
-static struct clocksource tango_xtal = {
-       .name   = "tango-xtal",
-       .rating = 350,
-       .read   = read_clocksource,
-       .mask   = CLOCKSOURCE_MASK(32),
-       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
 static void __init tango_clocksource_init(struct device_node *np)
 {
        struct clk *clk;
@@ -53,8 +40,9 @@ static void __init tango_clocksource_init(struct device_node *np)
        delay_timer.freq = xtal_freq;
        delay_timer.read_current_timer = read_xtal_counter;
 
-       ret = clocksource_register_hz(&tango_xtal, xtal_freq);
-       if (ret != 0) {
+       ret = clocksource_mmio_init(xtal_in_cnt, "tango-xtal", xtal_freq, 350,
+                                   32, clocksource_mmio_readl_up);
+       if (!ret) {
                pr_err("%s: registration failed\n", np->full_name);
                return;
        }
index 6ebda1177e791373e6db749f10620ef785bf198d..38333aba3055b3e376bb163ad0517c348178ec7b 100644 (file)
@@ -96,7 +96,8 @@ static struct clock_event_device tegra_clockevent = {
        .name                   = "timer0",
        .rating                 = 300,
        .features               = CLOCK_EVT_FEAT_ONESHOT |
-                                 CLOCK_EVT_FEAT_PERIODIC,
+                                 CLOCK_EVT_FEAT_PERIODIC |
+                                 CLOCK_EVT_FEAT_DYNIRQ,
        .set_next_event         = tegra_timer_set_next_event,
        .set_state_shutdown     = tegra_timer_shutdown,
        .set_state_periodic     = tegra_timer_set_periodic,
index a1c06a2bc77c55160fa8283378877cb8d1062820..1316876b487a715bf12bd03e007c4f178ec9136f 100644 (file)
@@ -125,7 +125,7 @@ static int __init lpc32xx_clocksource_init(struct device_node *np)
 
        clk = of_clk_get_by_name(np, "timerclk");
        if (IS_ERR(clk)) {
-               pr_err("clock get failed (%lu)\n", PTR_ERR(clk));
+               pr_err("clock get failed (%ld)\n", PTR_ERR(clk));
                return PTR_ERR(clk);
        }
 
@@ -184,7 +184,7 @@ static int __init lpc32xx_clockevent_init(struct device_node *np)
 
        clk = of_clk_get_by_name(np, "timerclk");
        if (IS_ERR(clk)) {
-               pr_err("clock get failed (%lu)\n", PTR_ERR(clk));
+               pr_err("clock get failed (%ld)\n", PTR_ERR(clk));
                return PTR_ERR(clk);
        }
 
index bba6799000541d360081b41e4e87ee8d9bf7596a..3269d9ef7a18a1d0f1e505ea77878b87c529d5f7 100644 (file)
@@ -84,7 +84,7 @@ pistachio_clocksource_read_cycles(struct clocksource *cs)
        counter = gpt_readl(pcs->base, TIMER_CURRENT_VALUE, 0);
        raw_spin_unlock_irqrestore(&pcs->lock, flags);
 
-       return ~(cycle_t)counter;
+       return (cycle_t)~counter;
 }
 
 static u64 notrace pistachio_read_sched_clock(void)
index bca9573e036a7ece133a64476cd0dd1208d9a816..24c83f9efd87f5f5df361eb9e4b0ecd76b6827f9 100644 (file)
@@ -152,13 +152,6 @@ static irqreturn_t sun5i_timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static cycle_t sun5i_clksrc_read(struct clocksource *clksrc)
-{
-       struct sun5i_timer_clksrc *cs = to_sun5i_timer_clksrc(clksrc);
-
-       return ~readl(cs->timer.base + TIMER_CNTVAL_LO_REG(1));
-}
-
 static int sun5i_rate_cb_clksrc(struct notifier_block *nb,
                                unsigned long event, void *data)
 {
@@ -217,13 +210,8 @@ static int __init sun5i_setup_clocksource(struct device_node *node,
        writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
               base + TIMER_CTL_REG(1));
 
-       cs->clksrc.name = node->name;
-       cs->clksrc.rating = 340;
-       cs->clksrc.read = sun5i_clksrc_read;
-       cs->clksrc.mask = CLOCKSOURCE_MASK(32);
-       cs->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
-
-       ret = clocksource_register_hz(&cs->clksrc, rate);
+       ret = clocksource_mmio_init(base + TIMER_CNTVAL_LO_REG(1), node->name,
+                                   rate, 340, 32, clocksource_mmio_readl_down);
        if (ret) {
                pr_err("Couldn't register clock source.\n");
                goto err_remove_notifier;
index a92e94b40b5b031e12074e26483e2e0c61b1d986..de49805fbb0978bb2eac2bd019c252604cd6afe2 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
 #include <linux/delay.h>
-#include <asm/mach/time.h>
 
 #include <linux/of.h>
 #include <linux/of_address.h>
index d7373ca69c9947a83dd8a1d67b77c7fc9e77209e..25693b0453714ca8bb1e610fdda0786a1fc3798e 100644 (file)
@@ -179,26 +179,21 @@ static int cn_call_callback(struct sk_buff *skb)
  *
  * It checks skb, netlink header and msg sizes, and calls callback helper.
  */
-static void cn_rx_skb(struct sk_buff *__skb)
+static void cn_rx_skb(struct sk_buff *skb)
 {
        struct nlmsghdr *nlh;
-       struct sk_buff *skb;
        int len, err;
 
-       skb = skb_get(__skb);
-
        if (skb->len >= NLMSG_HDRLEN) {
                nlh = nlmsg_hdr(skb);
                len = nlmsg_len(nlh);
 
                if (len < (int)sizeof(struct cn_msg) ||
                    skb->len < nlh->nlmsg_len ||
-                   len > CONNECTOR_MAX_MSG_SIZE) {
-                       kfree_skb(skb);
+                   len > CONNECTOR_MAX_MSG_SIZE)
                        return;
-               }
 
-               err = cn_call_callback(skb);
+               err = cn_call_callback(skb_get(skb));
                if (err < 0)
                        kfree_skb(skb);
        }
index da2d6777bd092f0a373e14cc960514b8a4f5d148..97a364694bfced664b33498505fa6510d8979d7c 100644 (file)
@@ -515,7 +515,7 @@ static int __init padlock_init(void)
        if (!x86_match_cpu(padlock_cpu_id))
                return -ENODEV;
 
-       if (!cpu_has_xcrypt_enabled) {
+       if (!boot_cpu_has(X86_FEATURE_XCRYPT_EN)) {
                printk(KERN_NOTICE PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
                return -ENODEV;
        }
index 4e154c9b92064bb1fbafeb805bcb77f9cc2d1bdf..8c5f90647b7a773112365e8a86ad979edaaed190 100644 (file)
@@ -540,7 +540,7 @@ static int __init padlock_init(void)
        struct shash_alg *sha1;
        struct shash_alg *sha256;
 
-       if (!x86_match_cpu(padlock_sha_ids) || !cpu_has_phe_enabled)
+       if (!x86_match_cpu(padlock_sha_ids) || !boot_cpu_has(X86_FEATURE_PHE_EN))
                return -ENODEV;
 
        /* Register the newly added algorithm module if on *
index cddfa8dbf4bdfb421508e8d10e74faa8a165c4f0..068e920ecb68d5ec681a1ca8a84642796a39a704 100644 (file)
@@ -317,7 +317,6 @@ mic_dma_prep_memcpy_lock(struct dma_chan *ch, dma_addr_t dma_dest,
        struct mic_dma_chan *mic_ch = to_mic_dma_chan(ch);
        struct device *dev = mic_dma_ch_to_device(mic_ch);
        int result;
-       struct dma_async_tx_descriptor *tx = NULL;
 
        if (!len && !flags)
                return NULL;
@@ -325,13 +324,10 @@ mic_dma_prep_memcpy_lock(struct dma_chan *ch, dma_addr_t dma_dest,
        spin_lock(&mic_ch->prep_lock);
        result = mic_dma_do_dma(mic_ch, flags, dma_src, dma_dest, len);
        if (result >= 0)
-               tx = allocate_tx(mic_ch);
-
-       if (!tx)
-               dev_err(dev, "Error enqueueing dma, error=%d\n", result);
-
+               return allocate_tx(mic_ch);
+       dev_err(dev, "Error enqueueing dma, error=%d\n", result);
        spin_unlock(&mic_ch->prep_lock);
-       return tx;
+       return NULL;
 }
 
 static struct dma_async_tx_descriptor *
@@ -339,14 +335,13 @@ mic_dma_prep_interrupt_lock(struct dma_chan *ch, unsigned long flags)
 {
        struct mic_dma_chan *mic_ch = to_mic_dma_chan(ch);
        int ret;
-       struct dma_async_tx_descriptor *tx = NULL;
 
        spin_lock(&mic_ch->prep_lock);
        ret = mic_dma_do_dma(mic_ch, flags, 0, 0, 0);
        if (!ret)
-               tx = allocate_tx(mic_ch);
+               return allocate_tx(mic_ch);
        spin_unlock(&mic_ch->prep_lock);
-       return tx;
+       return NULL;
 }
 
 /* Return the status of the transaction */
index 9dfa2b0fa5daf0e395b69fce370c6ba5889d3715..9cb93c5b655d80f411079aff95e02f612b7f3ec0 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/dmapool.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
 
@@ -1610,6 +1611,7 @@ static int xgene_dma_request_irqs(struct xgene_dma *pdma)
        /* Register DMA channel rx irq */
        for (i = 0; i < XGENE_DMA_MAX_CHANNEL; i++) {
                chan = &pdma->chan[i];
+               irq_set_status_flags(chan->rx_irq, IRQ_DISABLE_UNLAZY);
                ret = devm_request_irq(chan->dev, chan->rx_irq,
                                       xgene_dma_chan_ring_isr,
                                       0, chan->name, chan);
@@ -1620,6 +1622,7 @@ static int xgene_dma_request_irqs(struct xgene_dma *pdma)
 
                        for (j = 0; j < i; j++) {
                                chan = &pdma->chan[i];
+                               irq_clear_status_flags(chan->rx_irq, IRQ_DISABLE_UNLAZY);
                                devm_free_irq(chan->dev, chan->rx_irq, chan);
                        }
 
@@ -1640,6 +1643,7 @@ static void xgene_dma_free_irqs(struct xgene_dma *pdma)
 
        for (i = 0; i < XGENE_DMA_MAX_CHANNEL; i++) {
                chan = &pdma->chan[i];
+               irq_clear_status_flags(chan->rx_irq, IRQ_DISABLE_UNLAZY);
                devm_free_irq(chan->dev, chan->rx_irq, chan);
        }
 }
index dbf53e08bdd1a38261fc883bd812e881e4152fd8..be163e20fe56870c1bddad7a85c53035423ad4f2 100644 (file)
@@ -10,7 +10,7 @@ obj-$(CONFIG_EDAC)                    := edac_stub.o
 obj-$(CONFIG_EDAC_MM_EDAC)             += edac_core.o
 
 edac_core-y    := edac_mc.o edac_device.o edac_mc_sysfs.o
-edac_core-y    += edac_module.o edac_device_sysfs.o
+edac_core-y    += edac_module.o edac_device_sysfs.o wq.o
 
 edac_core-$(CONFIG_EDAC_DEBUG)         += debugfs.o
 
index 592af5f0cf391d292e05fd5c3a94b5589c7cb684..a97900333e2dfdc0bd61a22bf9927b0bf2c2b907 100644 (file)
@@ -390,11 +390,9 @@ static void edac_device_workq_function(struct work_struct *work_req)
         * between integral seconds
         */
        if (edac_dev->poll_msec == 1000)
-               queue_delayed_work(edac_workqueue, &edac_dev->work,
-                               round_jiffies_relative(edac_dev->delay));
+               edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay));
        else
-               queue_delayed_work(edac_workqueue, &edac_dev->work,
-                               edac_dev->delay);
+               edac_queue_work(&edac_dev->work, edac_dev->delay);
 }
 
 /*
@@ -402,8 +400,8 @@ static void edac_device_workq_function(struct work_struct *work_req)
  *     initialize a workq item for this edac_device instance
  *     passing in the new delay period in msec
  */
-void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
-                               unsigned msec)
+static void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
+                                   unsigned msec)
 {
        edac_dbg(0, "\n");
 
@@ -422,29 +420,23 @@ void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
         * to fire together on the 1 second exactly
         */
        if (edac_dev->poll_msec == 1000)
-               queue_delayed_work(edac_workqueue, &edac_dev->work,
-                               round_jiffies_relative(edac_dev->delay));
+               edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay));
        else
-               queue_delayed_work(edac_workqueue, &edac_dev->work,
-                               edac_dev->delay);
+               edac_queue_work(&edac_dev->work, edac_dev->delay);
 }
 
 /*
  * edac_device_workq_teardown
  *     stop the workq processing on this edac_dev
  */
-void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
+static void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
 {
-       int status;
-
        if (!edac_dev->edac_check)
                return;
 
-       status = cancel_delayed_work(&edac_dev->work);
-       if (status == 0) {
-               /* workq instance might be running, wait for it */
-               flush_workqueue(edac_workqueue);
-       }
+       edac_dev->op_state = OP_OFFLINE;
+
+       edac_stop_work(&edac_dev->work);
 }
 
 /*
@@ -457,16 +449,15 @@ void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
 void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev,
                                        unsigned long value)
 {
-       /* cancel the current workq request, without the mutex lock */
-       edac_device_workq_teardown(edac_dev);
+       unsigned long jiffs = msecs_to_jiffies(value);
 
-       /* acquire the mutex before doing the workq setup */
-       mutex_lock(&device_ctls_mutex);
+       if (value == 1000)
+               jiffs = round_jiffies_relative(value);
 
-       /* restart the workq request, with new delay value */
-       edac_device_workq_setup(edac_dev, value);
+       edac_dev->poll_msec = value;
+       edac_dev->delay     = jiffs;
 
-       mutex_unlock(&device_ctls_mutex);
+       edac_mod_work(&edac_dev->work, jiffs);
 }
 
 /*
index fb68a06ad6837fcce67b3a3baefb98026ad146c3..93da1a45c7161a83cd021cbbf1ac73c300b2b9e9 100644 (file)
@@ -237,11 +237,6 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
 
        /* get the /sys/devices/system/edac reference */
        edac_subsys = edac_get_sysfs_subsys();
-       if (edac_subsys == NULL) {
-               edac_dbg(1, "no edac_subsys error\n");
-               err = -ENODEV;
-               goto err_out;
-       }
 
        /* Point to the 'edac_subsys' this instance 'reports' to */
        edac_dev->edac_subsys = edac_subsys;
@@ -256,7 +251,7 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
 
        if (!try_module_get(edac_dev->owner)) {
                err = -ENODEV;
-               goto err_mod_get;
+               goto err_out;
        }
 
        /* register */
@@ -282,9 +277,6 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
 err_kobj_reg:
        module_put(edac_dev->owner);
 
-err_mod_get:
-       edac_put_sysfs_subsys();
-
 err_out:
        return err;
 }
@@ -306,7 +298,6 @@ void edac_device_unregister_sysfs_main_kobj(struct edac_device_ctl_info *dev)
         *   b) 'kfree' the memory
         */
        kobject_put(&dev->kobj);
-       edac_put_sysfs_subsys();
 }
 
 /* edac_dev -> instance information */
index 77ecd6a4179aaa2e2b6504da395debe6351508d9..8adfc167c2e38e7de64c0a08224a803ad737ae7a 100644 (file)
@@ -548,8 +548,7 @@ static void edac_mc_workq_function(struct work_struct *work_req)
        mutex_unlock(&mem_ctls_mutex);
 
        /* Reschedule */
-       queue_delayed_work(edac_workqueue, &mci->work,
-                       msecs_to_jiffies(edac_mc_get_poll_msec()));
+       edac_queue_work(&mci->work, msecs_to_jiffies(edac_mc_get_poll_msec()));
 }
 
 /*
@@ -561,8 +560,7 @@ static void edac_mc_workq_function(struct work_struct *work_req)
  *
  *             called with the mem_ctls_mutex held
  */
-static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec,
-                               bool init)
+static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
 {
        edac_dbg(0, "\n");
 
@@ -570,10 +568,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec,
        if (mci->op_state != OP_RUNNING_POLL)
                return;
 
-       if (init)
-               INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
+       INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
 
-       mod_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));
+       edac_queue_work(&mci->work, msecs_to_jiffies(msec));
 }
 
 /*
@@ -586,18 +583,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec,
  */
 static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
 {
-       int status;
-
-       if (mci->op_state != OP_RUNNING_POLL)
-               return;
-
-       status = cancel_delayed_work(&mci->work);
-       if (status == 0) {
-               edac_dbg(0, "not canceled, flush the queue\n");
+       mci->op_state = OP_OFFLINE;
 
-               /* workq instance might be running, wait for it */
-               flush_workqueue(edac_workqueue);
-       }
+       edac_stop_work(&mci->work);
 }
 
 /*
@@ -616,9 +604,8 @@ void edac_mc_reset_delay_period(unsigned long value)
        list_for_each(item, &mc_devices) {
                mci = list_entry(item, struct mem_ctl_info, link);
 
-               edac_mc_workq_setup(mci, value, false);
+               edac_mod_work(&mci->work, value);
        }
-
        mutex_unlock(&mem_ctls_mutex);
 }
 
@@ -789,7 +776,7 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci,
                /* This instance is NOW RUNNING */
                mci->op_state = OP_RUNNING_POLL;
 
-               edac_mc_workq_setup(mci, edac_mc_get_poll_msec(), true);
+               edac_mc_workq_setup(mci, edac_mc_get_poll_msec());
        } else {
                mci->op_state = OP_RUNNING_INTERRUPT;
        }
index a75acea0f674ed7ca9101ca7ce8a65e5b0961905..26e65ab5932abbb6e766f54f2cfc9009fe61df44 100644 (file)
@@ -880,21 +880,26 @@ static struct device_type mci_attr_type = {
 int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
                                 const struct attribute_group **groups)
 {
+       char *name;
        int i, err;
 
        /*
         * The memory controller needs its own bus, in order to avoid
         * namespace conflicts at /sys/bus/edac.
         */
-       mci->bus->name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
-       if (!mci->bus->name)
+       name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
+       if (!name)
                return -ENOMEM;
 
+       mci->bus->name = name;
+
        edac_dbg(0, "creating bus %s\n", mci->bus->name);
 
        err = bus_register(mci->bus);
-       if (err < 0)
-               goto fail_free_name;
+       if (err < 0) {
+               kfree(name);
+               return err;
+       }
 
        /* get the /sys/devices/system/edac subsys reference */
        mci->dev.type = &mci_attr_type;
@@ -961,8 +966,8 @@ fail_unregister_dimm:
        device_unregister(&mci->dev);
 fail_unregister_bus:
        bus_unregister(mci->bus);
-fail_free_name:
-       kfree(mci->bus->name);
+       kfree(name);
+
        return err;
 }
 
@@ -993,10 +998,12 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
 
 void edac_unregister_sysfs(struct mem_ctl_info *mci)
 {
+       const char *name = mci->bus->name;
+
        edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev));
        device_unregister(&mci->dev);
        bus_unregister(mci->bus);
-       kfree(mci->bus->name);
+       kfree(name);
 }
 
 static void mc_attr_release(struct device *dev)
@@ -1018,24 +1025,15 @@ static struct device_type mc_attr_type = {
  */
 int __init edac_mc_sysfs_init(void)
 {
-       struct bus_type *edac_subsys;
        int err;
 
-       /* get the /sys/devices/system/edac subsys reference */
-       edac_subsys = edac_get_sysfs_subsys();
-       if (edac_subsys == NULL) {
-               edac_dbg(1, "no edac_subsys\n");
-               err = -EINVAL;
-               goto out;
-       }
-
        mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL);
        if (!mci_pdev) {
                err = -ENOMEM;
-               goto out_put_sysfs;
+               goto out;
        }
 
-       mci_pdev->bus = edac_subsys;
+       mci_pdev->bus = edac_get_sysfs_subsys();
        mci_pdev->type = &mc_attr_type;
        device_initialize(mci_pdev);
        dev_set_name(mci_pdev, "mc");
@@ -1050,8 +1048,6 @@ int __init edac_mc_sysfs_init(void)
 
  out_dev_free:
        kfree(mci_pdev);
- out_put_sysfs:
-       edac_put_sysfs_subsys();
  out:
        return err;
 }
@@ -1059,5 +1055,4 @@ int __init edac_mc_sysfs_init(void)
 void edac_mc_sysfs_exit(void)
 {
        device_unregister(mci_pdev);
-       edac_put_sysfs_subsys();
 }
index 9cb082a19d8a7ae2fbd7a2ae146bd3cd98a59618..5f8543be995ab6584ffe479558133de016649194 100644 (file)
@@ -43,9 +43,6 @@ module_param_call(edac_debug_level, edac_set_debug_level, param_get_int,
 MODULE_PARM_DESC(edac_debug_level, "EDAC debug level: [0-4], default: 2");
 #endif
 
-/* scope is to module level only */
-struct workqueue_struct *edac_workqueue;
-
 /*
  * edac_op_state_to_string()
  */
@@ -66,31 +63,37 @@ char *edac_op_state_to_string(int opstate)
 }
 
 /*
- * edac_workqueue_setup
- *     initialize the edac work queue for polling operations
+ * sysfs object: /sys/devices/system/edac
+ *     need to export to other files
  */
-static int edac_workqueue_setup(void)
+static struct bus_type edac_subsys = {
+       .name = "edac",
+       .dev_name = "edac",
+};
+
+static int edac_subsys_init(void)
 {
-       edac_workqueue = create_singlethread_workqueue("edac-poller");
-       if (edac_workqueue == NULL)
-               return -ENODEV;
-       else
-               return 0;
+       int err;
+
+       /* create the /sys/devices/system/edac directory */
+       err = subsys_system_register(&edac_subsys, NULL);
+       if (err)
+               printk(KERN_ERR "Error registering toplevel EDAC sysfs dir\n");
+
+       return err;
 }
 
-/*
- * edac_workqueue_teardown
- *     teardown the edac workqueue
- */
-static void edac_workqueue_teardown(void)
+static void edac_subsys_exit(void)
 {
-       if (edac_workqueue) {
-               flush_workqueue(edac_workqueue);
-               destroy_workqueue(edac_workqueue);
-               edac_workqueue = NULL;
-       }
+       bus_unregister(&edac_subsys);
 }
 
+/* return pointer to the 'edac' node in sysfs */
+struct bus_type *edac_get_sysfs_subsys(void)
+{
+       return &edac_subsys;
+}
+EXPORT_SYMBOL_GPL(edac_get_sysfs_subsys);
 /*
  * edac_init
  *      module initialization entry point
@@ -101,6 +104,10 @@ static int __init edac_init(void)
 
        edac_printk(KERN_INFO, EDAC_MC, EDAC_VERSION "\n");
 
+       err = edac_subsys_init();
+       if (err)
+               return err;
+
        /*
         * Harvest and clear any boot/initialization PCI parity errors
         *
@@ -129,6 +136,8 @@ err_wq:
        edac_mc_sysfs_exit();
 
 err_sysfs:
+       edac_subsys_exit();
+
        return err;
 }
 
@@ -144,6 +153,7 @@ static void __exit edac_exit(void)
        edac_workqueue_teardown();
        edac_mc_sysfs_exit();
        edac_debugfs_exit();
+       edac_subsys_exit();
 }
 
 /*
index b95a48fc723d587dce62116f330b46034fc3ecf1..cfaacb99c97322cab89e27576797505fae75b628 100644 (file)
@@ -47,10 +47,12 @@ extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev);
 extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev);
 
 /* edac core workqueue: single CPU mode */
-extern struct workqueue_struct *edac_workqueue;
-extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
-                                   unsigned msec);
-extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev);
+int edac_workqueue_setup(void);
+void edac_workqueue_teardown(void);
+bool edac_queue_work(struct delayed_work *work, unsigned long delay);
+bool edac_stop_work(struct delayed_work *work);
+bool edac_mod_work(struct delayed_work *work, unsigned long delay);
+
 extern void edac_device_reset_delay_period(struct edac_device_ctl_info
                                           *edac_dev, unsigned long value);
 extern void edac_mc_reset_delay_period(unsigned long value);
index 2cf44b4db80c8beac0a5575cf00d1ed4cca32c4d..99685388d3fb5a1a8c6f52f5fbb675a61fa4a065 100644 (file)
@@ -178,41 +178,6 @@ static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci)
        INIT_LIST_HEAD(&pci->link);
 }
 
-#if 0
-/* Older code, but might use in the future */
-
-/*
- * edac_pci_find()
- *     Search for an edac_pci_ctl_info structure whose index is 'idx'
- *
- * If found, return a pointer to the structure
- * Else return NULL.
- *
- * Caller must hold pci_ctls_mutex.
- */
-struct edac_pci_ctl_info *edac_pci_find(int idx)
-{
-       struct list_head *item;
-       struct edac_pci_ctl_info *pci;
-
-       /* Iterage over list, looking for exact match of ID */
-       list_for_each(item, &edac_pci_list) {
-               pci = list_entry(item, struct edac_pci_ctl_info, link);
-
-               if (pci->pci_idx >= idx) {
-                       if (pci->pci_idx == idx)
-                               return pci;
-
-                       /* not on list, so terminate early */
-                       break;
-               }
-       }
-
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(edac_pci_find);
-#endif
-
 /*
  * edac_pci_workq_function()
  *
@@ -244,7 +209,7 @@ static void edac_pci_workq_function(struct work_struct *work_req)
                        delay = msecs_to_jiffies(msec);
 
                /* Reschedule only if we are in POLL mode */
-               queue_delayed_work(edac_workqueue, &pci->work, delay);
+               edac_queue_work(&pci->work, delay);
        }
 
        mutex_unlock(&edac_pci_ctls_mutex);
@@ -264,8 +229,8 @@ static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci,
        edac_dbg(0, "\n");
 
        INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function);
-       queue_delayed_work(edac_workqueue, &pci->work,
-                       msecs_to_jiffies(edac_pci_get_poll_msec()));
+
+       edac_queue_work(&pci->work, msecs_to_jiffies(edac_pci_get_poll_msec()));
 }
 
 /*
@@ -273,38 +238,13 @@ static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci,
  *     stop the workq processing on this edac_pci instance
  */
 static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci)
-{
-       int status;
-
-       edac_dbg(0, "\n");
-
-       status = cancel_delayed_work(&pci->work);
-       if (status == 0)
-               flush_workqueue(edac_workqueue);
-}
-
-/*
- * edac_pci_reset_delay_period
- *
- *     called with a new period value for the workq period
- *     a) stop current workq timer
- *     b) restart workq timer with new value
- */
-void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
-                                unsigned long value)
 {
        edac_dbg(0, "\n");
 
-       edac_pci_workq_teardown(pci);
-
-       /* need to lock for the setup */
-       mutex_lock(&edac_pci_ctls_mutex);
-
-       edac_pci_workq_setup(pci, value);
+       pci->op_state = OP_OFFLINE;
 
-       mutex_unlock(&edac_pci_ctls_mutex);
+       edac_stop_work(&pci->work);
 }
-EXPORT_SYMBOL_GPL(edac_pci_reset_delay_period);
 
 /*
  * edac_pci_alloc_index: Allocate a unique PCI index number
index 24d877f6e57751b07123771c2f9e7b898c17cee6..6e3428ba400f38774f7ac562b51b3759b81913d2 100644 (file)
@@ -331,10 +331,7 @@ static struct kobj_type ktype_edac_pci_main_kobj = {
 };
 
 /**
- * edac_pci_main_kobj_setup()
- *
- *     setup the sysfs for EDAC PCI attributes
- *     assumes edac_subsys has already been initialized
+ * edac_pci_main_kobj_setup: Setup the sysfs for EDAC PCI attributes.
  */
 static int edac_pci_main_kobj_setup(void)
 {
@@ -351,11 +348,6 @@ static int edac_pci_main_kobj_setup(void)
         * controls and attributes
         */
        edac_subsys = edac_get_sysfs_subsys();
-       if (edac_subsys == NULL) {
-               edac_dbg(1, "no edac_subsys\n");
-               err = -ENODEV;
-               goto decrement_count_fail;
-       }
 
        /* Bump the reference count on this module to ensure the
         * modules isn't unloaded until we deconstruct the top
@@ -364,7 +356,7 @@ static int edac_pci_main_kobj_setup(void)
        if (!try_module_get(THIS_MODULE)) {
                edac_dbg(1, "try_module_get() failed\n");
                err = -ENODEV;
-               goto mod_get_fail;
+               goto decrement_count_fail;
        }
 
        edac_pci_top_main_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
@@ -399,9 +391,6 @@ kobject_init_and_add_fail:
 kzalloc_fail:
        module_put(THIS_MODULE);
 
-mod_get_fail:
-       edac_put_sysfs_subsys();
-
 decrement_count_fail:
        /* if are on this error exit, nothing to tear down */
        atomic_dec(&edac_pci_sysfs_refcount);
@@ -426,7 +415,6 @@ static void edac_pci_main_kobj_teardown(void)
        if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) {
                edac_dbg(0, "called kobject_put on main kobj\n");
                kobject_put(edac_pci_top_main_kobj);
-               edac_put_sysfs_subsys();
        }
 }
 
index ff07aae5b7fbd963b59a72e9fdfed2cc3ad721aa..952e411f01f2fc38d4d12426807491b4b5e4f2e8 100644 (file)
@@ -26,8 +26,6 @@ EXPORT_SYMBOL_GPL(edac_handlers);
 int edac_err_assert = 0;
 EXPORT_SYMBOL_GPL(edac_err_assert);
 
-static atomic_t edac_subsys_valid = ATOMIC_INIT(0);
-
 int edac_report_status = EDAC_REPORTING_ENABLED;
 EXPORT_SYMBOL_GPL(edac_report_status);
 
@@ -68,42 +66,3 @@ void edac_atomic_assert_error(void)
        edac_err_assert++;
 }
 EXPORT_SYMBOL_GPL(edac_atomic_assert_error);
-
-/*
- * sysfs object: /sys/devices/system/edac
- *     need to export to other files
- */
-struct bus_type edac_subsys = {
-       .name = "edac",
-       .dev_name = "edac",
-};
-EXPORT_SYMBOL_GPL(edac_subsys);
-
-/* return pointer to the 'edac' node in sysfs */
-struct bus_type *edac_get_sysfs_subsys(void)
-{
-       int err = 0;
-
-       if (atomic_read(&edac_subsys_valid))
-               goto out;
-
-       /* create the /sys/devices/system/edac directory */
-       err = subsys_system_register(&edac_subsys, NULL);
-       if (err) {
-               printk(KERN_ERR "Error registering toplevel EDAC sysfs dir\n");
-               return NULL;
-       }
-
-out:
-       atomic_inc(&edac_subsys_valid);
-       return &edac_subsys;
-}
-EXPORT_SYMBOL_GPL(edac_get_sysfs_subsys);
-
-void edac_put_sysfs_subsys(void)
-{
-       /* last user unregisters it */
-       if (atomic_dec_and_test(&edac_subsys_valid))
-               bus_unregister(&edac_subsys);
-}
-EXPORT_SYMBOL_GPL(edac_put_sysfs_subsys);
index 40917775dca1c84fa2f84acbea9a988ec94060e3..c655162caf08fe4a9f08dfe161a31543b6b9b1d5 100644 (file)
@@ -575,9 +575,7 @@ static void i5100_check_error(struct mem_ctl_info *mci)
 
 static void i5100_refresh_scrubbing(struct work_struct *work)
 {
-       struct delayed_work *i5100_scrubbing = container_of(work,
-                                                           struct delayed_work,
-                                                           work);
+       struct delayed_work *i5100_scrubbing = to_delayed_work(work);
        struct i5100_priv *priv = container_of(i5100_scrubbing,
                                               struct i5100_priv,
                                               i5100_scrubbing);
index 23ef8e9f2c9a851f52e43b57bce305bb4cffbf5c..b7139c160bafdaf71a4e3a2d45a00b5e67e6cc7f 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/edac.h>
 #include <linux/smp.h>
 #include <linux/gfp.h>
+#include <linux/fsl/edac.h>
 
 #include <linux/of_platform.h>
 #include <linux/of_device.h>
@@ -238,10 +239,12 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-int mpc85xx_pci_err_probe(struct platform_device *op)
+static int mpc85xx_pci_err_probe(struct platform_device *op)
 {
        struct edac_pci_ctl_info *pci;
        struct mpc85xx_pci_pdata *pdata;
+       struct mpc85xx_edac_pci_plat_data *plat_data;
+       struct device_node *of_node;
        struct resource r;
        int res = 0;
 
@@ -266,7 +269,15 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
        pdata->name = "mpc85xx_pci_err";
        pdata->irq = NO_IRQ;
 
-       if (mpc85xx_pcie_find_capability(op->dev.of_node) > 0)
+       plat_data = op->dev.platform_data;
+       if (!plat_data) {
+               dev_err(&op->dev, "no platform data");
+               res = -ENXIO;
+               goto err;
+       }
+       of_node = plat_data->of_node;
+
+       if (mpc85xx_pcie_find_capability(of_node) > 0)
                pdata->is_pcie = true;
 
        dev_set_drvdata(&op->dev, pci);
@@ -284,7 +295,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
 
        pdata->edac_idx = edac_pci_idx++;
 
-       res = of_address_to_resource(op->dev.of_node, 0, &r);
+       res = of_address_to_resource(of_node, 0, &r);
        if (res) {
                printk(KERN_ERR "%s: Unable to get resource for "
                       "PCI err regs\n", __func__);
@@ -339,7 +350,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
        }
 
        if (edac_op_state == EDAC_OPSTATE_INT) {
-               pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
+               pdata->irq = irq_of_parse_and_map(of_node, 0);
                res = devm_request_irq(&op->dev, pdata->irq,
                                       mpc85xx_pci_isr,
                                       IRQF_SHARED,
@@ -386,8 +397,22 @@ err:
        devres_release_group(&op->dev, mpc85xx_pci_err_probe);
        return res;
 }
-EXPORT_SYMBOL(mpc85xx_pci_err_probe);
 
+static const struct platform_device_id mpc85xx_pci_err_match[] = {
+       {
+               .name = "mpc85xx-pci-edac"
+       },
+       {}
+};
+
+static struct platform_driver mpc85xx_pci_err_driver = {
+       .probe = mpc85xx_pci_err_probe,
+       .id_table = mpc85xx_pci_err_match,
+       .driver = {
+               .name = "mpc85xx_pci_err",
+               .suppress_bind_attrs = true,
+       },
+};
 #endif                         /* CONFIG_PCI */
 
 /**************************** L2 Err device ***************************/
@@ -1208,6 +1233,14 @@ static void __init mpc85xx_mc_clear_rfxe(void *data)
 }
 #endif
 
+static struct platform_driver * const drivers[] = {
+       &mpc85xx_mc_err_driver,
+       &mpc85xx_l2_err_driver,
+#ifdef CONFIG_PCI
+       &mpc85xx_pci_err_driver,
+#endif
+};
+
 static int __init mpc85xx_mc_init(void)
 {
        int res = 0;
@@ -1226,13 +1259,9 @@ static int __init mpc85xx_mc_init(void)
                break;
        }
 
-       res = platform_driver_register(&mpc85xx_mc_err_driver);
-       if (res)
-               printk(KERN_WARNING EDAC_MOD_STR "MC fails to register\n");
-
-       res = platform_driver_register(&mpc85xx_l2_err_driver);
+       res = platform_register_drivers(drivers, ARRAY_SIZE(drivers));
        if (res)
-               printk(KERN_WARNING EDAC_MOD_STR "L2 fails to register\n");
+               printk(KERN_WARNING EDAC_MOD_STR "drivers fail to register\n");
 
 #ifdef CONFIG_FSL_SOC_BOOKE
        pvr = mfspr(SPRN_PVR);
@@ -1270,8 +1299,7 @@ static void __exit mpc85xx_mc_exit(void)
                on_each_cpu(mpc85xx_mc_restore_hid1, NULL, 0);
        }
 #endif
-       platform_driver_unregister(&mpc85xx_l2_err_driver);
-       platform_driver_unregister(&mpc85xx_mc_err_driver);
+       platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
 }
 
 module_exit(mpc85xx_mc_exit);
index 0574e1bbe45cf224cee26ac59e56d98c77f419b4..6c54127e6eae79295b12277bec860aa1f9fb3cd2 100644 (file)
@@ -847,6 +847,15 @@ static struct platform_driver mv64x60_mc_err_driver = {
        }
 };
 
+static struct platform_driver * const drivers[] = {
+       &mv64x60_mc_err_driver,
+       &mv64x60_cpu_err_driver,
+       &mv64x60_sram_err_driver,
+#ifdef CONFIG_PCI
+       &mv64x60_pci_err_driver,
+#endif
+};
+
 static int __init mv64x60_edac_init(void)
 {
        int ret = 0;
@@ -863,39 +872,13 @@ static int __init mv64x60_edac_init(void)
                break;
        }
 
-       ret = platform_driver_register(&mv64x60_mc_err_driver);
-       if (ret)
-               printk(KERN_WARNING EDAC_MOD_STR "MC err failed to register\n");
-
-       ret = platform_driver_register(&mv64x60_cpu_err_driver);
-       if (ret)
-               printk(KERN_WARNING EDAC_MOD_STR
-                       "CPU err failed to register\n");
-
-       ret = platform_driver_register(&mv64x60_sram_err_driver);
-       if (ret)
-               printk(KERN_WARNING EDAC_MOD_STR
-                       "SRAM err failed to register\n");
-
-#ifdef CONFIG_PCI
-       ret = platform_driver_register(&mv64x60_pci_err_driver);
-       if (ret)
-               printk(KERN_WARNING EDAC_MOD_STR
-                       "PCI err failed to register\n");
-#endif
-
-       return ret;
+       return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
 }
 module_init(mv64x60_edac_init);
 
 static void __exit mv64x60_edac_exit(void)
 {
-#ifdef CONFIG_PCI
-       platform_driver_unregister(&mv64x60_pci_err_driver);
-#endif
-       platform_driver_unregister(&mv64x60_sram_err_driver);
-       platform_driver_unregister(&mv64x60_cpu_err_driver);
-       platform_driver_unregister(&mv64x60_mc_err_driver);
+       platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
 }
 module_exit(mv64x60_edac_exit);
 
index 429309c62699ff9ea536a90b839dbb99b7305ecc..e438ee5b433f3f498cba20df890730a3fc77220c 100644 (file)
@@ -65,15 +65,20 @@ static const u32 ibridge_dram_rule[] = {
        0xd8, 0xe0, 0xe8, 0xf0, 0xf8,
 };
 
-#define SAD_LIMIT(reg)         ((GET_BITFIELD(reg, 6, 25) << 26) | 0x3ffffff)
-#define DRAM_ATTR(reg)         GET_BITFIELD(reg, 2,  3)
-#define INTERLEAVE_MODE(reg)   GET_BITFIELD(reg, 1,  1)
+static const u32 knl_dram_rule[] = {
+       0x60, 0x68, 0x70, 0x78, 0x80, /* 0-4 */
+       0x88, 0x90, 0x98, 0xa0, 0xa8, /* 5-9 */
+       0xb0, 0xb8, 0xc0, 0xc8, 0xd0, /* 10-14 */
+       0xd8, 0xe0, 0xe8, 0xf0, 0xf8, /* 15-19 */
+       0x100, 0x108, 0x110, 0x118,   /* 20-23 */
+};
+
 #define DRAM_RULE_ENABLE(reg)  GET_BITFIELD(reg, 0,  0)
 #define A7MODE(reg)            GET_BITFIELD(reg, 26, 26)
 
-static char *get_dram_attr(u32 reg)
+static char *show_dram_attr(u32 attr)
 {
-       switch(DRAM_ATTR(reg)) {
+       switch (attr) {
                case 0:
                        return "DRAM";
                case 1:
@@ -97,6 +102,14 @@ static const u32 ibridge_interleave_list[] = {
        0xdc, 0xe4, 0xec, 0xf4, 0xfc,
 };
 
+static const u32 knl_interleave_list[] = {
+       0x64, 0x6c, 0x74, 0x7c, 0x84, /* 0-4 */
+       0x8c, 0x94, 0x9c, 0xa4, 0xac, /* 5-9 */
+       0xb4, 0xbc, 0xc4, 0xcc, 0xd4, /* 10-14 */
+       0xdc, 0xe4, 0xec, 0xf4, 0xfc, /* 15-19 */
+       0x104, 0x10c, 0x114, 0x11c,   /* 20-23 */
+};
+
 struct interleave_pkg {
        unsigned char start;
        unsigned char end;
@@ -134,10 +147,13 @@ static inline int sad_pkg(const struct interleave_pkg *table, u32 reg,
 /* Devices 12 Function 7 */
 
 #define TOLM           0x80
-#define        TOHM            0x84
+#define TOHM           0x84
 #define HASWELL_TOLM   0xd0
 #define HASWELL_TOHM_0 0xd4
 #define HASWELL_TOHM_1 0xd8
+#define KNL_TOLM       0xd0
+#define KNL_TOHM_0     0xd4
+#define KNL_TOHM_1     0xd8
 
 #define GET_TOLM(reg)          ((GET_BITFIELD(reg, 0,  3) << 28) | 0x3ffffff)
 #define GET_TOHM(reg)          ((GET_BITFIELD(reg, 0, 20) << 25) | 0x3ffffff)
@@ -148,6 +164,8 @@ static inline int sad_pkg(const struct interleave_pkg *table, u32 reg,
 
 #define SOURCE_ID(reg)         GET_BITFIELD(reg, 9, 11)
 
+#define SOURCE_ID_KNL(reg)     GET_BITFIELD(reg, 12, 14)
+
 #define SAD_CONTROL    0xf4
 
 /* Device 14 function 0 */
@@ -170,6 +188,7 @@ static const u32 tad_dram_rule[] = {
 /* Device 15, function 0 */
 
 #define MCMTR                  0x7c
+#define KNL_MCMTR              0x624
 
 #define IS_ECC_ENABLED(mcmtr)          GET_BITFIELD(mcmtr, 2, 2)
 #define IS_LOCKSTEP_ENABLED(mcmtr)     GET_BITFIELD(mcmtr, 1, 1)
@@ -186,6 +205,8 @@ static const int mtr_regs[] = {
        0x80, 0x84, 0x88,
 };
 
+static const int knl_mtr_reg = 0xb60;
+
 #define RANK_DISABLE(mtr)              GET_BITFIELD(mtr, 16, 19)
 #define IS_DIMM_PRESENT(mtr)           GET_BITFIELD(mtr, 14, 14)
 #define RANK_CNT_BITS(mtr)             GET_BITFIELD(mtr, 12, 13)
@@ -256,6 +277,9 @@ static const u32 correrrthrsld[] = {
 
 #define NUM_CHANNELS           8       /* 2MC per socket, four chan per MC */
 #define MAX_DIMMS              3       /* Max DIMMS per channel */
+#define KNL_MAX_CHAS           38      /* KNL max num. of Cache Home Agents */
+#define KNL_MAX_CHANNELS       6       /* KNL max num. of PCI channels */
+#define KNL_MAX_EDCS           8       /* Embedded DRAM controllers */
 #define CHANNEL_UNSPECIFIED    0xf     /* Intel IA32 SDM 15-14 */
 
 enum type {
@@ -263,6 +287,7 @@ enum type {
        IVY_BRIDGE,
        HASWELL,
        BROADWELL,
+       KNIGHTS_LANDING,
 };
 
 struct sbridge_pvt;
@@ -273,6 +298,10 @@ struct sbridge_info {
        u64             (*get_tolm)(struct sbridge_pvt *pvt);
        u64             (*get_tohm)(struct sbridge_pvt *pvt);
        u64             (*rir_limit)(u32 reg);
+       u64             (*sad_limit)(u32 reg);
+       u32             (*interleave_mode)(u32 reg);
+       char*           (*show_interleave_mode)(u32 reg);
+       u32             (*dram_attr)(u32 reg);
        const u32       *dram_rule;
        const u32       *interleave_list;
        const struct interleave_pkg *interleave_pkg;
@@ -308,6 +337,16 @@ struct sbridge_dev {
        struct mem_ctl_info     *mci;
 };
 
+struct knl_pvt {
+       struct pci_dev          *pci_cha[KNL_MAX_CHAS];
+       struct pci_dev          *pci_channel[KNL_MAX_CHANNELS];
+       struct pci_dev          *pci_mc0;
+       struct pci_dev          *pci_mc1;
+       struct pci_dev          *pci_mc0_misc;
+       struct pci_dev          *pci_mc1_misc;
+       struct pci_dev          *pci_mc_info; /* tolm, tohm */
+};
+
 struct sbridge_pvt {
        struct pci_dev          *pci_ta, *pci_ddrio, *pci_ras;
        struct pci_dev          *pci_sad0, *pci_sad1;
@@ -336,6 +375,7 @@ struct sbridge_pvt {
 
        /* Memory description */
        u64                     tolm, tohm;
+       struct knl_pvt knl;
 };
 
 #define PCI_DESCR(device_id, opt)      \
@@ -509,6 +549,50 @@ static const struct pci_id_table pci_dev_descr_haswell_table[] = {
        {0,}                    /* 0 terminated list. */
 };
 
+/* Knight's Landing Support */
+/*
+ * KNL's memory channels are swizzled between memory controllers.
+ * MC0 is mapped to CH3,5,6 and MC1 is mapped to CH0,1,2
+ */
+#define knl_channel_remap(channel) ((channel + 3) % 6)
+
+/* Memory controller, TAD tables, error injection - 2-8-0, 2-9-0 (2 of these) */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_MC       0x7840
+/* DRAM channel stuff; bank addrs, dimmmtr, etc.. 2-8-2 - 2-9-4 (6 of these) */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_CHANNEL  0x7843
+/* kdrwdbu TAD limits/offsets, MCMTR - 2-10-1, 2-11-1 (2 of these) */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_TA       0x7844
+/* CHA broadcast registers, dram rules - 1-29-0 (1 of these) */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0     0x782a
+/* SAD target - 1-29-1 (1 of these) */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_SAD1     0x782b
+/* Caching / Home Agent */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_CHA      0x782c
+/* Device with TOLM and TOHM, 0-5-0 (1 of these) */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_TOLHM    0x7810
+
+/*
+ * KNL differs from SB, IB, and Haswell in that it has multiple
+ * instances of the same device with the same device ID, so we handle that
+ * by creating as many copies in the table as we expect to find.
+ * (Like device ID must be grouped together.)
+ */
+
+static const struct pci_id_descr pci_dev_descr_knl[] = {
+       [0]         = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0, 0) },
+       [1]         = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_SAD1, 0) },
+       [2 ... 3]   = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_MC, 0)},
+       [4 ... 41]  = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_CHA, 0) },
+       [42 ... 47] = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_CHANNEL, 0) },
+       [48]        = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_TA, 0) },
+       [49]        = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_TOLHM, 0) },
+};
+
+static const struct pci_id_table pci_dev_descr_knl_table[] = {
+       PCI_ID_TABLE_ENTRY(pci_dev_descr_knl),
+       {0,}
+};
+
 /*
  * Broadwell support
  *
@@ -585,6 +669,7 @@ static const struct pci_device_id sbridge_pci_tbl[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0)},
        {0,}                    /* 0 terminated list. */
 };
 
@@ -598,7 +683,7 @@ static inline int numrank(enum type type, u32 mtr)
        int ranks = (1 << RANK_CNT_BITS(mtr));
        int max = 4;
 
-       if (type == HASWELL || type == BROADWELL)
+       if (type == HASWELL || type == BROADWELL || type == KNIGHTS_LANDING)
                max = 8;
 
        if (ranks > max) {
@@ -636,10 +721,19 @@ static inline int numcol(u32 mtr)
        return 1 << cols;
 }
 
-static struct sbridge_dev *get_sbridge_dev(u8 bus)
+static struct sbridge_dev *get_sbridge_dev(u8 bus, int multi_bus)
 {
        struct sbridge_dev *sbridge_dev;
 
+       /*
+        * If we have devices scattered across several busses that pertain
+        * to the same memory controller, we'll lump them all together.
+        */
+       if (multi_bus) {
+               return list_first_entry_or_null(&sbridge_edac_list,
+                               struct sbridge_dev, list);
+       }
+
        list_for_each_entry(sbridge_dev, &sbridge_edac_list, list) {
                if (sbridge_dev->bus == bus)
                        return sbridge_dev;
@@ -718,6 +812,67 @@ static u64 rir_limit(u32 reg)
        return ((u64)GET_BITFIELD(reg,  1, 10) << 29) | 0x1fffffff;
 }
 
+static u64 sad_limit(u32 reg)
+{
+       return (GET_BITFIELD(reg, 6, 25) << 26) | 0x3ffffff;
+}
+
+static u32 interleave_mode(u32 reg)
+{
+       return GET_BITFIELD(reg, 1, 1);
+}
+
+char *show_interleave_mode(u32 reg)
+{
+       return interleave_mode(reg) ? "8:6" : "[8:6]XOR[18:16]";
+}
+
+static u32 dram_attr(u32 reg)
+{
+       return GET_BITFIELD(reg, 2, 3);
+}
+
+static u64 knl_sad_limit(u32 reg)
+{
+       return (GET_BITFIELD(reg, 7, 26) << 26) | 0x3ffffff;
+}
+
+static u32 knl_interleave_mode(u32 reg)
+{
+       return GET_BITFIELD(reg, 1, 2);
+}
+
+static char *knl_show_interleave_mode(u32 reg)
+{
+       char *s;
+
+       switch (knl_interleave_mode(reg)) {
+       case 0:
+               s = "use address bits [8:6]";
+               break;
+       case 1:
+               s = "use address bits [10:8]";
+               break;
+       case 2:
+               s = "use address bits [14:12]";
+               break;
+       case 3:
+               s = "use address bits [32:30]";
+               break;
+       default:
+               WARN_ON(1);
+               break;
+       }
+
+       return s;
+}
+
+static u32 dram_attr_knl(u32 reg)
+{
+       return GET_BITFIELD(reg, 3, 4);
+}
+
+
 static enum mem_type get_memory_type(struct sbridge_pvt *pvt)
 {
        u32 reg;
@@ -769,6 +924,12 @@ out:
        return mtype;
 }
 
+static enum dev_type knl_get_width(struct sbridge_pvt *pvt, u32 mtr)
+{
+       /* for KNL value is fixed */
+       return DEV_X16;
+}
+
 static enum dev_type sbridge_get_width(struct sbridge_pvt *pvt, u32 mtr)
 {
        /* there's no way to figure out */
@@ -812,6 +973,12 @@ static enum dev_type broadwell_get_width(struct sbridge_pvt *pvt, u32 mtr)
        return __ibridge_get_width(GET_BITFIELD(mtr, 8, 9));
 }
 
+static enum mem_type knl_get_memory_type(struct sbridge_pvt *pvt)
+{
+       /* DDR4 RDIMMS and LRDIMMS are supported */
+       return MEM_RDDR4;
+}
+
 static u8 get_node_id(struct sbridge_pvt *pvt)
 {
        u32 reg;
@@ -827,6 +994,15 @@ static u8 haswell_get_node_id(struct sbridge_pvt *pvt)
        return GET_BITFIELD(reg, 0, 3);
 }
 
+static u8 knl_get_node_id(struct sbridge_pvt *pvt)
+{
+       u32 reg;
+
+       pci_read_config_dword(pvt->pci_sad1, SAD_CONTROL, &reg);
+       return GET_BITFIELD(reg, 0, 2);
+}
+
+
 static u64 haswell_get_tolm(struct sbridge_pvt *pvt)
 {
        u32 reg;
@@ -848,6 +1024,26 @@ static u64 haswell_get_tohm(struct sbridge_pvt *pvt)
        return rc | 0x1ffffff;
 }
 
+static u64 knl_get_tolm(struct sbridge_pvt *pvt)
+{
+       u32 reg;
+
+       pci_read_config_dword(pvt->knl.pci_mc_info, KNL_TOLM, &reg);
+       return (GET_BITFIELD(reg, 26, 31) << 26) | 0x3ffffff;
+}
+
+static u64 knl_get_tohm(struct sbridge_pvt *pvt)
+{
+       u64 rc;
+       u32 reg_lo, reg_hi;
+
+       pci_read_config_dword(pvt->knl.pci_mc_info, KNL_TOHM_0, &reg_lo);
+       pci_read_config_dword(pvt->knl.pci_mc_info, KNL_TOHM_1, &reg_hi);
+       rc = ((u64)reg_hi << 32) | reg_lo;
+       return rc | 0x3ffffff;
+}
+
+
 static u64 haswell_rir_limit(u32 reg)
 {
        return (((u64)GET_BITFIELD(reg,  1, 11) + 1) << 29) - 1;
@@ -905,11 +1101,22 @@ static int check_if_ecc_is_active(const u8 bus, enum type type)
        case BROADWELL:
                id = PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA;
                break;
+       case KNIGHTS_LANDING:
+               /*
+                * KNL doesn't group things by bus the same way
+                * SB/IB/Haswell does.
+                */
+               id = PCI_DEVICE_ID_INTEL_KNL_IMC_TA;
+               break;
        default:
                return -ENODEV;
        }
 
-       pdev = get_pdev_same_bus(bus, id);
+       if (type != KNIGHTS_LANDING)
+               pdev = get_pdev_same_bus(bus, id);
+       else
+               pdev = pci_get_device(PCI_VENDOR_ID_INTEL, id, 0);
+
        if (!pdev) {
                sbridge_printk(KERN_ERR, "Couldn't find PCI device "
                                        "%04x:%04x! on bus %02d\n",
@@ -917,7 +1124,8 @@ static int check_if_ecc_is_active(const u8 bus, enum type type)
                return -ENODEV;
        }
 
-       pci_read_config_dword(pdev, MCMTR, &mcmtr);
+       pci_read_config_dword(pdev,
+                       type == KNIGHTS_LANDING ? KNL_MCMTR : MCMTR, &mcmtr);
        if (!IS_ECC_ENABLED(mcmtr)) {
                sbridge_printk(KERN_ERR, "ECC is disabled. Aborting\n");
                return -ENODEV;
@@ -925,6 +1133,476 @@ static int check_if_ecc_is_active(const u8 bus, enum type type)
        return 0;
 }
 
+/* Low bits of TAD limit, and some metadata. */
+static const u32 knl_tad_dram_limit_lo[] = {
+       0x400, 0x500, 0x600, 0x700,
+       0x800, 0x900, 0xa00, 0xb00,
+};
+
+/* Low bits of TAD offset. */
+static const u32 knl_tad_dram_offset_lo[] = {
+       0x404, 0x504, 0x604, 0x704,
+       0x804, 0x904, 0xa04, 0xb04,
+};
+
+/* High 16 bits of TAD limit and offset. */
+static const u32 knl_tad_dram_hi[] = {
+       0x408, 0x508, 0x608, 0x708,
+       0x808, 0x908, 0xa08, 0xb08,
+};
+
+/* Number of ways a tad entry is interleaved. */
+static const u32 knl_tad_ways[] = {
+       8, 6, 4, 3, 2, 1,
+};
+
+/*
+ * Retrieve the n'th Target Address Decode table entry
+ * from the memory controller's TAD table.
+ *
+ * @pvt:       driver private data
+ * @entry:     which entry you want to retrieve
+ * @mc:                which memory controller (0 or 1)
+ * @offset:    output tad range offset
+ * @limit:     output address of first byte above tad range
+ * @ways:      output number of interleave ways
+ *
+ * The offset value has curious semantics.  It's a sort of running total
+ * of the sizes of all the memory regions that aren't mapped in this
+ * tad table.
+ */
+static int knl_get_tad(const struct sbridge_pvt *pvt,
+               const int entry,
+               const int mc,
+               u64 *offset,
+               u64 *limit,
+               int *ways)
+{
+       u32 reg_limit_lo, reg_offset_lo, reg_hi;
+       struct pci_dev *pci_mc;
+       int way_id;
+
+       switch (mc) {
+       case 0:
+               pci_mc = pvt->knl.pci_mc0;
+               break;
+       case 1:
+               pci_mc = pvt->knl.pci_mc1;
+               break;
+       default:
+               WARN_ON(1);
+               return -EINVAL;
+       }
+
+       pci_read_config_dword(pci_mc,
+                       knl_tad_dram_limit_lo[entry], &reg_limit_lo);
+       pci_read_config_dword(pci_mc,
+                       knl_tad_dram_offset_lo[entry], &reg_offset_lo);
+       pci_read_config_dword(pci_mc,
+                       knl_tad_dram_hi[entry], &reg_hi);
+
+       /* Is this TAD entry enabled? */
+       if (!GET_BITFIELD(reg_limit_lo, 0, 0))
+               return -ENODEV;
+
+       way_id = GET_BITFIELD(reg_limit_lo, 3, 5);
+
+       if (way_id < ARRAY_SIZE(knl_tad_ways)) {
+               *ways = knl_tad_ways[way_id];
+       } else {
+               *ways = 0;
+               sbridge_printk(KERN_ERR,
+                               "Unexpected value %d in mc_tad_limit_lo wayness field\n",
+                               way_id);
+               return -ENODEV;
+       }
+
+       /*
+        * The least significant 6 bits of base and limit are truncated.
+        * For limit, we fill the missing bits with 1s.
+        */
+       *offset = ((u64) GET_BITFIELD(reg_offset_lo, 6, 31) << 6) |
+                               ((u64) GET_BITFIELD(reg_hi, 0,  15) << 32);
+       *limit = ((u64) GET_BITFIELD(reg_limit_lo,  6, 31) << 6) | 63 |
+                               ((u64) GET_BITFIELD(reg_hi, 16, 31) << 32);
+
+       return 0;
+}
+
+/* Determine which memory controller is responsible for a given channel. */
+static int knl_channel_mc(int channel)
+{
+       WARN_ON(channel < 0 || channel >= 6);
+
+       return channel < 3 ? 1 : 0;
+}
+
+/*
+ * Get the Nth entry from EDC_ROUTE_TABLE register.
+ * (This is the per-tile mapping of logical interleave targets to
+ *  physical EDC modules.)
+ *
+ * entry 0: 0:2
+ *       1: 3:5
+ *       2: 6:8
+ *       3: 9:11
+ *       4: 12:14
+ *       5: 15:17
+ *       6: 18:20
+ *       7: 21:23
+ * reserved: 24:31
+ */
+static u32 knl_get_edc_route(int entry, u32 reg)
+{
+       WARN_ON(entry >= KNL_MAX_EDCS);
+       return GET_BITFIELD(reg, entry*3, (entry*3)+2);
+}
+
+/*
+ * Get the Nth entry from MC_ROUTE_TABLE register.
+ * (This is the per-tile mapping of logical interleave targets to
+ *  physical DRAM channels modules.)
+ *
+ * entry 0: mc 0:2   channel 18:19
+ *       1: mc 3:5   channel 20:21
+ *       2: mc 6:8   channel 22:23
+ *       3: mc 9:11  channel 24:25
+ *       4: mc 12:14 channel 26:27
+ *       5: mc 15:17 channel 28:29
+ * reserved: 30:31
+ *
+ * Though we have 3 bits to identify the MC, we should only see
+ * the values 0 or 1.
+ */
+
+static u32 knl_get_mc_route(int entry, u32 reg)
+{
+       int mc, chan;
+
+       WARN_ON(entry >= KNL_MAX_CHANNELS);
+
+       mc = GET_BITFIELD(reg, entry*3, (entry*3)+2);
+       chan = GET_BITFIELD(reg, (entry*2) + 18, (entry*2) + 18 + 1);
+
+       return knl_channel_remap(mc*3 + chan);
+}
+
+/*
+ * Render the EDC_ROUTE register in human-readable form.
+ * Output string s should be at least KNL_MAX_EDCS*2 bytes.
+ */
+static void knl_show_edc_route(u32 reg, char *s)
+{
+       int i;
+
+       for (i = 0; i < KNL_MAX_EDCS; i++) {
+               s[i*2] = knl_get_edc_route(i, reg) + '0';
+               s[i*2+1] = '-';
+       }
+
+       s[KNL_MAX_EDCS*2 - 1] = '\0';
+}
+
+/*
+ * Render the MC_ROUTE register in human-readable form.
+ * Output string s should be at least KNL_MAX_CHANNELS*2 bytes.
+ */
+static void knl_show_mc_route(u32 reg, char *s)
+{
+       int i;
+
+       for (i = 0; i < KNL_MAX_CHANNELS; i++) {
+               s[i*2] = knl_get_mc_route(i, reg) + '0';
+               s[i*2+1] = '-';
+       }
+
+       s[KNL_MAX_CHANNELS*2 - 1] = '\0';
+}
+
+#define KNL_EDC_ROUTE 0xb8
+#define KNL_MC_ROUTE 0xb4
+
+/* Is this dram rule backed by regular DRAM in flat mode? */
+#define KNL_EDRAM(reg) GET_BITFIELD(reg, 29, 29)
+
+/* Is this dram rule cached? */
+#define KNL_CACHEABLE(reg) GET_BITFIELD(reg, 28, 28)
+
+/* Is this rule backed by edc ? */
+#define KNL_EDRAM_ONLY(reg) GET_BITFIELD(reg, 29, 29)
+
+/* Is this rule backed by DRAM, cacheable in EDRAM? */
+#define KNL_CACHEABLE(reg) GET_BITFIELD(reg, 28, 28)
+
+/* Is this rule mod3? */
+#define KNL_MOD3(reg) GET_BITFIELD(reg, 27, 27)
+
+/*
+ * Figure out how big our RAM modules are.
+ *
+ * The DIMMMTR register in KNL doesn't tell us the size of the DIMMs, so we
+ * have to figure this out from the SAD rules, interleave lists, route tables,
+ * and TAD rules.
+ *
+ * SAD rules can have holes in them (e.g. the 3G-4G hole), so we have to
+ * inspect the TAD rules to figure out how large the SAD regions really are.
+ *
+ * When we know the real size of a SAD region and how many ways it's
+ * interleaved, we know the individual contribution of each channel to
+ * TAD is size/ways.
+ *
+ * Finally, we have to check whether each channel participates in each SAD
+ * region.
+ *
+ * Fortunately, KNL only supports one DIMM per channel, so once we know how
+ * much memory the channel uses, we know the DIMM is at least that large.
+ * (The BIOS might possibly choose not to map all available memory, in which
+ * case we will underreport the size of the DIMM.)
+ *
+ * In theory, we could try to determine the EDC sizes as well, but that would
+ * only work in flat mode, not in cache mode.
+ *
+ * @mc_sizes: Output sizes of channels (must have space for KNL_MAX_CHANNELS
+ *            elements)
+ */
+static int knl_get_dimm_capacity(struct sbridge_pvt *pvt, u64 *mc_sizes)
+{
+       u64 sad_base, sad_size, sad_limit = 0;
+       u64 tad_base, tad_size, tad_limit, tad_deadspace, tad_livespace;
+       int sad_rule = 0;
+       int tad_rule = 0;
+       int intrlv_ways, tad_ways;
+       u32 first_pkg, pkg;
+       int i;
+       u64 sad_actual_size[2]; /* sad size accounting for holes, per mc */
+       u32 dram_rule, interleave_reg;
+       u32 mc_route_reg[KNL_MAX_CHAS];
+       u32 edc_route_reg[KNL_MAX_CHAS];
+       int edram_only;
+       char edc_route_string[KNL_MAX_EDCS*2];
+       char mc_route_string[KNL_MAX_CHANNELS*2];
+       int cur_reg_start;
+       int mc;
+       int channel;
+       int way;
+       int participants[KNL_MAX_CHANNELS];
+       int participant_count = 0;
+
+       for (i = 0; i < KNL_MAX_CHANNELS; i++)
+               mc_sizes[i] = 0;
+
+       /* Read the EDC route table in each CHA. */
+       cur_reg_start = 0;
+       for (i = 0; i < KNL_MAX_CHAS; i++) {
+               pci_read_config_dword(pvt->knl.pci_cha[i],
+                               KNL_EDC_ROUTE, &edc_route_reg[i]);
+
+               if (i > 0 && edc_route_reg[i] != edc_route_reg[i-1]) {
+                       knl_show_edc_route(edc_route_reg[i-1],
+                                       edc_route_string);
+                       if (cur_reg_start == i-1)
+                               edac_dbg(0, "edc route table for CHA %d: %s\n",
+                                       cur_reg_start, edc_route_string);
+                       else
+                               edac_dbg(0, "edc route table for CHA %d-%d: %s\n",
+                                       cur_reg_start, i-1, edc_route_string);
+                       cur_reg_start = i;
+               }
+       }
+       knl_show_edc_route(edc_route_reg[i-1], edc_route_string);
+       if (cur_reg_start == i-1)
+               edac_dbg(0, "edc route table for CHA %d: %s\n",
+                       cur_reg_start, edc_route_string);
+       else
+               edac_dbg(0, "edc route table for CHA %d-%d: %s\n",
+                       cur_reg_start, i-1, edc_route_string);
+
+       /* Read the MC route table in each CHA. */
+       cur_reg_start = 0;
+       for (i = 0; i < KNL_MAX_CHAS; i++) {
+               pci_read_config_dword(pvt->knl.pci_cha[i],
+                       KNL_MC_ROUTE, &mc_route_reg[i]);
+
+               if (i > 0 && mc_route_reg[i] != mc_route_reg[i-1]) {
+                       knl_show_mc_route(mc_route_reg[i-1], mc_route_string);
+                       if (cur_reg_start == i-1)
+                               edac_dbg(0, "mc route table for CHA %d: %s\n",
+                                       cur_reg_start, mc_route_string);
+                       else
+                               edac_dbg(0, "mc route table for CHA %d-%d: %s\n",
+                                       cur_reg_start, i-1, mc_route_string);
+                       cur_reg_start = i;
+               }
+       }
+       knl_show_mc_route(mc_route_reg[i-1], mc_route_string);
+       if (cur_reg_start == i-1)
+               edac_dbg(0, "mc route table for CHA %d: %s\n",
+                       cur_reg_start, mc_route_string);
+       else
+               edac_dbg(0, "mc route table for CHA %d-%d: %s\n",
+                       cur_reg_start, i-1, mc_route_string);
+
+       /* Process DRAM rules */
+       for (sad_rule = 0; sad_rule < pvt->info.max_sad; sad_rule++) {
+               /* previous limit becomes the new base */
+               sad_base = sad_limit;
+
+               pci_read_config_dword(pvt->pci_sad0,
+                       pvt->info.dram_rule[sad_rule], &dram_rule);
+
+               if (!DRAM_RULE_ENABLE(dram_rule))
+                       break;
+
+               edram_only = KNL_EDRAM_ONLY(dram_rule);
+
+               sad_limit = pvt->info.sad_limit(dram_rule)+1;
+               sad_size = sad_limit - sad_base;
+
+               pci_read_config_dword(pvt->pci_sad0,
+                       pvt->info.interleave_list[sad_rule], &interleave_reg);
+
+               /*
+                * Find out how many ways this dram rule is interleaved.
+                * We stop when we see the first channel again.
+                */
+               first_pkg = sad_pkg(pvt->info.interleave_pkg,
+                                               interleave_reg, 0);
+               for (intrlv_ways = 1; intrlv_ways < 8; intrlv_ways++) {
+                       pkg = sad_pkg(pvt->info.interleave_pkg,
+                                               interleave_reg, intrlv_ways);
+
+                       if ((pkg & 0x8) == 0) {
+                               /*
+                                * 0 bit means memory is non-local,
+                                * which KNL doesn't support
+                                */
+                               edac_dbg(0, "Unexpected interleave target %d\n",
+                                       pkg);
+                               return -1;
+                       }
+
+                       if (pkg == first_pkg)
+                               break;
+               }
+               if (KNL_MOD3(dram_rule))
+                       intrlv_ways *= 3;
+
+               edac_dbg(3, "dram rule %d (base 0x%llx, limit 0x%llx), %d way interleave%s\n",
+                       sad_rule,
+                       sad_base,
+                       sad_limit,
+                       intrlv_ways,
+                       edram_only ? ", EDRAM" : "");
+
+               /*
+                * Find out how big the SAD region really is by iterating
+                * over TAD tables (SAD regions may contain holes).
+                * Each memory controller might have a different TAD table, so
+                * we have to look at both.
+                *
+                * Livespace is the memory that's mapped in this TAD table,
+                * deadspace is the holes (this could be the MMIO hole, or it
+                * could be memory that's mapped by the other TAD table but
+                * not this one).
+                */
+               for (mc = 0; mc < 2; mc++) {
+                       sad_actual_size[mc] = 0;
+                       tad_livespace = 0;
+                       for (tad_rule = 0;
+                                       tad_rule < ARRAY_SIZE(
+                                               knl_tad_dram_limit_lo);
+                                       tad_rule++) {
+                               if (knl_get_tad(pvt,
+                                               tad_rule,
+                                               mc,
+                                               &tad_deadspace,
+                                               &tad_limit,
+                                               &tad_ways))
+                                       break;
+
+                               tad_size = (tad_limit+1) -
+                                       (tad_livespace + tad_deadspace);
+                               tad_livespace += tad_size;
+                               tad_base = (tad_limit+1) - tad_size;
+
+                               if (tad_base < sad_base) {
+                                       if (tad_limit > sad_base)
+                                               edac_dbg(0, "TAD region overlaps lower SAD boundary -- TAD tables may be configured incorrectly.\n");
+                               } else if (tad_base < sad_limit) {
+                                       if (tad_limit+1 > sad_limit) {
+                                               edac_dbg(0, "TAD region overlaps upper SAD boundary -- TAD tables may be configured incorrectly.\n");
+                                       } else {
+                                               /* TAD region is completely inside SAD region */
+                                               edac_dbg(3, "TAD region %d 0x%llx - 0x%llx (%lld bytes) table%d\n",
+                                                       tad_rule, tad_base,
+                                                       tad_limit, tad_size,
+                                                       mc);
+                                               sad_actual_size[mc] += tad_size;
+                                       }
+                               }
+                               tad_base = tad_limit+1;
+                       }
+               }
+
+               for (mc = 0; mc < 2; mc++) {
+                       edac_dbg(3, " total TAD DRAM footprint in table%d : 0x%llx (%lld bytes)\n",
+                               mc, sad_actual_size[mc], sad_actual_size[mc]);
+               }
+
+               /* Ignore EDRAM rule */
+               if (edram_only)
+                       continue;
+
+               /* Figure out which channels participate in interleave. */
+               for (channel = 0; channel < KNL_MAX_CHANNELS; channel++)
+                       participants[channel] = 0;
+
+               /* For each channel, does at least one CHA have
+                * this channel mapped to the given target?
+                */
+               for (channel = 0; channel < KNL_MAX_CHANNELS; channel++) {
+                       for (way = 0; way < intrlv_ways; way++) {
+                               int target;
+                               int cha;
+
+                               if (KNL_MOD3(dram_rule))
+                                       target = way;
+                               else
+                                       target = 0x7 & sad_pkg(
+                               pvt->info.interleave_pkg, interleave_reg, way);
+
+                               for (cha = 0; cha < KNL_MAX_CHAS; cha++) {
+                                       if (knl_get_mc_route(target,
+                                               mc_route_reg[cha]) == channel
+                                               && participants[channel]) {
+                                               participant_count++;
+                                               participants[channel] = 1;
+                                               break;
+                                       }
+                               }
+                       }
+               }
+
+               if (participant_count != intrlv_ways)
+                       edac_dbg(0, "participant_count (%d) != interleave_ways (%d): DIMM size may be incorrect\n",
+                               participant_count, intrlv_ways);
+
+               for (channel = 0; channel < KNL_MAX_CHANNELS; channel++) {
+                       mc = knl_channel_mc(channel);
+                       if (participants[channel]) {
+                               edac_dbg(4, "mc channel %d contributes %lld bytes via sad entry %d\n",
+                                       channel,
+                                       sad_actual_size[mc]/intrlv_ways,
+                                       sad_rule);
+                               mc_sizes[channel] +=
+                                       sad_actual_size[mc]/intrlv_ways;
+                       }
+               }
+       }
+
+       return 0;
+}
+
 static int get_dimm_config(struct mem_ctl_info *mci)
 {
        struct sbridge_pvt *pvt = mci->pvt_info;
@@ -934,13 +1612,20 @@ static int get_dimm_config(struct mem_ctl_info *mci)
        u32 reg;
        enum edac_type mode;
        enum mem_type mtype;
+       int channels = pvt->info.type == KNIGHTS_LANDING ?
+               KNL_MAX_CHANNELS : NUM_CHANNELS;
+       u64 knl_mc_sizes[KNL_MAX_CHANNELS];
 
-       if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL)
+       if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL ||
+                       pvt->info.type == KNIGHTS_LANDING)
                pci_read_config_dword(pvt->pci_sad1, SAD_TARGET, &reg);
        else
                pci_read_config_dword(pvt->pci_br0, SAD_TARGET, &reg);
 
-       pvt->sbridge_dev->source_id = SOURCE_ID(reg);
+       if (pvt->info.type == KNIGHTS_LANDING)
+               pvt->sbridge_dev->source_id = SOURCE_ID_KNL(reg);
+       else
+               pvt->sbridge_dev->source_id = SOURCE_ID(reg);
 
        pvt->sbridge_dev->node_id = pvt->info.get_node_id(pvt);
        edac_dbg(0, "mc#%d: Node ID: %d, source ID: %d\n",
@@ -948,31 +1633,42 @@ static int get_dimm_config(struct mem_ctl_info *mci)
                 pvt->sbridge_dev->node_id,
                 pvt->sbridge_dev->source_id);
 
-       pci_read_config_dword(pvt->pci_ras, RASENABLES, &reg);
-       if (IS_MIRROR_ENABLED(reg)) {
-               edac_dbg(0, "Memory mirror is enabled\n");
-               pvt->is_mirrored = true;
-       } else {
-               edac_dbg(0, "Memory mirror is disabled\n");
+       /* KNL doesn't support mirroring or lockstep,
+        * and is always closed page
+        */
+       if (pvt->info.type == KNIGHTS_LANDING) {
+               mode = EDAC_S4ECD4ED;
                pvt->is_mirrored = false;
-       }
 
-       pci_read_config_dword(pvt->pci_ta, MCMTR, &pvt->info.mcmtr);
-       if (IS_LOCKSTEP_ENABLED(pvt->info.mcmtr)) {
-               edac_dbg(0, "Lockstep is enabled\n");
-               mode = EDAC_S8ECD8ED;
-               pvt->is_lockstep = true;
+               if (knl_get_dimm_capacity(pvt, knl_mc_sizes) != 0)
+                       return -1;
        } else {
-               edac_dbg(0, "Lockstep is disabled\n");
-               mode = EDAC_S4ECD4ED;
-               pvt->is_lockstep = false;
-       }
-       if (IS_CLOSE_PG(pvt->info.mcmtr)) {
-               edac_dbg(0, "address map is on closed page mode\n");
-               pvt->is_close_pg = true;
-       } else {
-               edac_dbg(0, "address map is on open page mode\n");
-               pvt->is_close_pg = false;
+               pci_read_config_dword(pvt->pci_ras, RASENABLES, &reg);
+               if (IS_MIRROR_ENABLED(reg)) {
+                       edac_dbg(0, "Memory mirror is enabled\n");
+                       pvt->is_mirrored = true;
+               } else {
+                       edac_dbg(0, "Memory mirror is disabled\n");
+                       pvt->is_mirrored = false;
+               }
+
+               pci_read_config_dword(pvt->pci_ta, MCMTR, &pvt->info.mcmtr);
+               if (IS_LOCKSTEP_ENABLED(pvt->info.mcmtr)) {
+                       edac_dbg(0, "Lockstep is enabled\n");
+                       mode = EDAC_S8ECD8ED;
+                       pvt->is_lockstep = true;
+               } else {
+                       edac_dbg(0, "Lockstep is disabled\n");
+                       mode = EDAC_S4ECD4ED;
+                       pvt->is_lockstep = false;
+               }
+               if (IS_CLOSE_PG(pvt->info.mcmtr)) {
+                       edac_dbg(0, "address map is on closed page mode\n");
+                       pvt->is_close_pg = true;
+               } else {
+                       edac_dbg(0, "address map is on open page mode\n");
+                       pvt->is_close_pg = false;
+               }
        }
 
        mtype = pvt->info.get_memory_type(pvt);
@@ -988,23 +1684,46 @@ static int get_dimm_config(struct mem_ctl_info *mci)
        else
                banks = 8;
 
-       for (i = 0; i < NUM_CHANNELS; i++) {
+       for (i = 0; i < channels; i++) {
                u32 mtr;
 
-               if (!pvt->pci_tad[i])
-                       continue;
-               for (j = 0; j < ARRAY_SIZE(mtr_regs); j++) {
+               int max_dimms_per_channel;
+
+               if (pvt->info.type == KNIGHTS_LANDING) {
+                       max_dimms_per_channel = 1;
+                       if (!pvt->knl.pci_channel[i])
+                               continue;
+               } else {
+                       max_dimms_per_channel = ARRAY_SIZE(mtr_regs);
+                       if (!pvt->pci_tad[i])
+                               continue;
+               }
+
+               for (j = 0; j < max_dimms_per_channel; j++) {
                        dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, mci->n_layers,
                                       i, j, 0);
-                       pci_read_config_dword(pvt->pci_tad[i],
-                                             mtr_regs[j], &mtr);
+                       if (pvt->info.type == KNIGHTS_LANDING) {
+                               pci_read_config_dword(pvt->knl.pci_channel[i],
+                                       knl_mtr_reg, &mtr);
+                       } else {
+                               pci_read_config_dword(pvt->pci_tad[i],
+                                       mtr_regs[j], &mtr);
+                       }
                        edac_dbg(4, "Channel #%d  MTR%d = %x\n", i, j, mtr);
                        if (IS_DIMM_PRESENT(mtr)) {
                                pvt->channel[i].dimms++;
 
                                ranks = numrank(pvt->info.type, mtr);
-                               rows = numrow(mtr);
-                               cols = numcol(mtr);
+
+                               if (pvt->info.type == KNIGHTS_LANDING) {
+                                       /* For DDR4, this is fixed. */
+                                       cols = 1 << 10;
+                                       rows = knl_mc_sizes[i] /
+                                               ((u64) cols * ranks * banks * 8);
+                               } else {
+                                       rows = numrow(mtr);
+                                       cols = numcol(mtr);
+                               }
 
                                size = ((u64)rows * cols * banks * ranks) >> (20 - 3);
                                npages = MiB_TO_PAGES(size);
@@ -1069,7 +1788,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
                /* SAD_LIMIT Address range is 45:26 */
                pci_read_config_dword(pvt->pci_sad0, pvt->info.dram_rule[n_sads],
                                      &reg);
-               limit = SAD_LIMIT(reg);
+               limit = pvt->info.sad_limit(reg);
 
                if (!DRAM_RULE_ENABLE(reg))
                        continue;
@@ -1081,10 +1800,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
                gb = div_u64_rem(tmp_mb, 1024, &mb);
                edac_dbg(0, "SAD#%d %s up to %u.%03u GB (0x%016Lx) Interleave: %s reg=0x%08x\n",
                         n_sads,
-                        get_dram_attr(reg),
+                        show_dram_attr(pvt->info.dram_attr(reg)),
                         gb, (mb*1000)/1024,
                         ((u64)tmp_mb) << 20L,
-                        INTERLEAVE_MODE(reg) ? "8:6" : "[8:6]XOR[18:16]",
+                        pvt->info.show_interleave_mode(reg),
                         reg);
                prv = limit;
 
@@ -1101,6 +1820,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
                }
        }
 
+       if (pvt->info.type == KNIGHTS_LANDING)
+               return;
+
        /*
         * Step 3) Get TAD range
         */
@@ -1248,7 +1970,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
                if (!DRAM_RULE_ENABLE(reg))
                        continue;
 
-               limit = SAD_LIMIT(reg);
+               limit = pvt->info.sad_limit(reg);
                if (limit <= prv) {
                        sprintf(msg, "Can't discover the memory socket");
                        return -EINVAL;
@@ -1262,8 +1984,8 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
                return -EINVAL;
        }
        dram_rule = reg;
-       *area_type = get_dram_attr(dram_rule);
-       interleave_mode = INTERLEAVE_MODE(dram_rule);
+       *area_type = show_dram_attr(pvt->info.dram_attr(dram_rule));
+       interleave_mode = pvt->info.interleave_mode(dram_rule);
 
        pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads],
                              &reg);
@@ -1567,7 +2289,8 @@ static void sbridge_put_all_devices(void)
 static int sbridge_get_onedevice(struct pci_dev **prev,
                                 u8 *num_mc,
                                 const struct pci_id_table *table,
-                                const unsigned devno)
+                                const unsigned devno,
+                                const int multi_bus)
 {
        struct sbridge_dev *sbridge_dev;
        const struct pci_id_descr *dev_descr = &table->descr[devno];
@@ -1603,7 +2326,7 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
        }
        bus = pdev->bus->number;
 
-       sbridge_dev = get_sbridge_dev(bus);
+       sbridge_dev = get_sbridge_dev(bus, multi_bus);
        if (!sbridge_dev) {
                sbridge_dev = alloc_sbridge_dev(bus, table);
                if (!sbridge_dev) {
@@ -1652,21 +2375,32 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
  * @num_mc: pointer to the memory controllers count, to be incremented in case
  *         of success.
  * @table: model specific table
+ * @allow_dups: allow for multiple devices to exist with the same device id
+ *              (as implemented, this isn't expected to work correctly in the
+ *              multi-socket case).
+ * @multi_bus: don't assume devices on different buses belong to different
+ *             memory controllers.
  *
  * returns 0 in case of success or error code
  */
-static int sbridge_get_all_devices(u8 *num_mc,
-                                  const struct pci_id_table *table)
+static int sbridge_get_all_devices_full(u8 *num_mc,
+                                       const struct pci_id_table *table,
+                                       int allow_dups,
+                                       int multi_bus)
 {
        int i, rc;
        struct pci_dev *pdev = NULL;
 
        while (table && table->descr) {
                for (i = 0; i < table->n_devs; i++) {
-                       pdev = NULL;
+                       if (!allow_dups || i == 0 ||
+                                       table->descr[i].dev_id !=
+                                               table->descr[i-1].dev_id) {
+                               pdev = NULL;
+                       }
                        do {
                                rc = sbridge_get_onedevice(&pdev, num_mc,
-                                                          table, i);
+                                                          table, i, multi_bus);
                                if (rc < 0) {
                                        if (i == 0) {
                                                i = table->n_devs;
@@ -1675,7 +2409,7 @@ static int sbridge_get_all_devices(u8 *num_mc,
                                        sbridge_put_all_devices();
                                        return -ENODEV;
                                }
-                       } while (pdev);
+                       } while (pdev && !allow_dups);
                }
                table++;
        }
@@ -1683,6 +2417,11 @@ static int sbridge_get_all_devices(u8 *num_mc,
        return 0;
 }
 
+#define sbridge_get_all_devices(num_mc, table) \
+               sbridge_get_all_devices_full(num_mc, table, 0, 0)
+#define sbridge_get_all_devices_knl(num_mc, table) \
+               sbridge_get_all_devices_full(num_mc, table, 1, 1)
+
 static int sbridge_mci_bind_devs(struct mem_ctl_info *mci,
                                 struct sbridge_dev *sbridge_dev)
 {
@@ -2038,6 +2777,131 @@ enodev:
        return -ENODEV;
 }
 
+static int knl_mci_bind_devs(struct mem_ctl_info *mci,
+                       struct sbridge_dev *sbridge_dev)
+{
+       struct sbridge_pvt *pvt = mci->pvt_info;
+       struct pci_dev *pdev;
+       int dev, func;
+
+       int i;
+       int devidx;
+
+       for (i = 0; i < sbridge_dev->n_devs; i++) {
+               pdev = sbridge_dev->pdev[i];
+               if (!pdev)
+                       continue;
+
+               /* Extract PCI device and function. */
+               dev = (pdev->devfn >> 3) & 0x1f;
+               func = pdev->devfn & 0x7;
+
+               switch (pdev->device) {
+               case PCI_DEVICE_ID_INTEL_KNL_IMC_MC:
+                       if (dev == 8)
+                               pvt->knl.pci_mc0 = pdev;
+                       else if (dev == 9)
+                               pvt->knl.pci_mc1 = pdev;
+                       else {
+                               sbridge_printk(KERN_ERR,
+                                       "Memory controller in unexpected place! (dev %d, fn %d)\n",
+                                       dev, func);
+                               continue;
+                       }
+                       break;
+
+               case PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0:
+                       pvt->pci_sad0 = pdev;
+                       break;
+
+               case PCI_DEVICE_ID_INTEL_KNL_IMC_SAD1:
+                       pvt->pci_sad1 = pdev;
+                       break;
+
+               case PCI_DEVICE_ID_INTEL_KNL_IMC_CHA:
+                       /* There are one of these per tile, and range from
+                        * 1.14.0 to 1.18.5.
+                        */
+                       devidx = ((dev-14)*8)+func;
+
+                       if (devidx < 0 || devidx >= KNL_MAX_CHAS) {
+                               sbridge_printk(KERN_ERR,
+                                       "Caching and Home Agent in unexpected place! (dev %d, fn %d)\n",
+                                       dev, func);
+                               continue;
+                       }
+
+                       WARN_ON(pvt->knl.pci_cha[devidx] != NULL);
+
+                       pvt->knl.pci_cha[devidx] = pdev;
+                       break;
+
+               case PCI_DEVICE_ID_INTEL_KNL_IMC_CHANNEL:
+                       devidx = -1;
+
+                       /*
+                        *  MC0 channels 0-2 are device 9 function 2-4,
+                        *  MC1 channels 3-5 are device 8 function 2-4.
+                        */
+
+                       if (dev == 9)
+                               devidx = func-2;
+                       else if (dev == 8)
+                               devidx = 3 + (func-2);
+
+                       if (devidx < 0 || devidx >= KNL_MAX_CHANNELS) {
+                               sbridge_printk(KERN_ERR,
+                                       "DRAM Channel Registers in unexpected place! (dev %d, fn %d)\n",
+                                       dev, func);
+                               continue;
+                       }
+
+                       WARN_ON(pvt->knl.pci_channel[devidx] != NULL);
+                       pvt->knl.pci_channel[devidx] = pdev;
+                       break;
+
+               case PCI_DEVICE_ID_INTEL_KNL_IMC_TOLHM:
+                       pvt->knl.pci_mc_info = pdev;
+                       break;
+
+               case PCI_DEVICE_ID_INTEL_KNL_IMC_TA:
+                       pvt->pci_ta = pdev;
+                       break;
+
+               default:
+                       sbridge_printk(KERN_ERR, "Unexpected device %d\n",
+                               pdev->device);
+                       break;
+               }
+       }
+
+       if (!pvt->knl.pci_mc0  || !pvt->knl.pci_mc1 ||
+           !pvt->pci_sad0     || !pvt->pci_sad1    ||
+           !pvt->pci_ta) {
+               goto enodev;
+       }
+
+       for (i = 0; i < KNL_MAX_CHANNELS; i++) {
+               if (!pvt->knl.pci_channel[i]) {
+                       sbridge_printk(KERN_ERR, "Missing channel %d\n", i);
+                       goto enodev;
+               }
+       }
+
+       for (i = 0; i < KNL_MAX_CHAS; i++) {
+               if (!pvt->knl.pci_cha[i]) {
+                       sbridge_printk(KERN_ERR, "Missing CHA %d\n", i);
+                       goto enodev;
+               }
+       }
+
+       return 0;
+
+enodev:
+       sbridge_printk(KERN_ERR, "Some needed devices are missing\n");
+       return -ENODEV;
+}
+
 /****************************************************************************
                        Error check routines
  ****************************************************************************/
@@ -2127,8 +2991,36 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
        if (!GET_BITFIELD(m->status, 58, 58))
                return;
 
-       rc = get_memory_error_data(mci, m->addr, &socket, &ha,
-                                  &channel_mask, &rank, &area_type, msg);
+       if (pvt->info.type == KNIGHTS_LANDING) {
+               if (channel == 14) {
+                       edac_dbg(0, "%s%s err_code:%04x:%04x EDRAM bank %d\n",
+                               overflow ? " OVERFLOW" : "",
+                               (uncorrected_error && recoverable)
+                               ? " recoverable" : "",
+                               mscod, errcode,
+                               m->bank);
+               } else {
+                       char A = *("A");
+
+                       channel = knl_channel_remap(channel);
+                       channel_mask = 1 << channel;
+                       snprintf(msg, sizeof(msg),
+                               "%s%s err_code:%04x:%04x channel:%d (DIMM_%c)",
+                               overflow ? " OVERFLOW" : "",
+                               (uncorrected_error && recoverable)
+                               ? " recoverable" : " ",
+                               mscod, errcode, channel, A + channel);
+                       edac_mc_handle_error(tp_event, mci, core_err_cnt,
+                               m->addr >> PAGE_SHIFT, m->addr & ~PAGE_MASK, 0,
+                               channel, 0, -1,
+                               optype, msg);
+               }
+               return;
+       } else {
+               rc = get_memory_error_data(mci, m->addr, &socket, &ha,
+                               &channel_mask, &rank, &area_type, msg);
+       }
+
        if (rc < 0)
                goto err_parsing;
        new_mci = get_mci_for_node_id(socket);
@@ -2359,10 +3251,11 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
 
        /* allocate a new MC control structure */
        layers[0].type = EDAC_MC_LAYER_CHANNEL;
-       layers[0].size = NUM_CHANNELS;
+       layers[0].size = type == KNIGHTS_LANDING ?
+               KNL_MAX_CHANNELS : NUM_CHANNELS;
        layers[0].is_virt_csrow = false;
        layers[1].type = EDAC_MC_LAYER_SLOT;
-       layers[1].size = MAX_DIMMS;
+       layers[1].size = type == KNIGHTS_LANDING ? 1 : MAX_DIMMS;
        layers[1].is_virt_csrow = true;
        mci = edac_mc_alloc(sbridge_dev->mc, ARRAY_SIZE(layers), layers,
                            sizeof(*pvt));
@@ -2380,7 +3273,8 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
        pvt->sbridge_dev = sbridge_dev;
        sbridge_dev->mci = mci;
 
-       mci->mtype_cap = MEM_FLAG_DDR3;
+       mci->mtype_cap = type == KNIGHTS_LANDING ?
+               MEM_FLAG_DDR4 : MEM_FLAG_DDR3;
        mci->edac_ctl_cap = EDAC_FLAG_NONE;
        mci->edac_cap = EDAC_FLAG_NONE;
        mci->mod_name = "sbridge_edac.c";
@@ -2401,6 +3295,10 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
                pvt->info.get_memory_type = get_memory_type;
                pvt->info.get_node_id = get_node_id;
                pvt->info.rir_limit = rir_limit;
+               pvt->info.sad_limit = sad_limit;
+               pvt->info.interleave_mode = interleave_mode;
+               pvt->info.show_interleave_mode = show_interleave_mode;
+               pvt->info.dram_attr = dram_attr;
                pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
                pvt->info.interleave_list = ibridge_interleave_list;
                pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
@@ -2421,6 +3319,10 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
                pvt->info.get_memory_type = get_memory_type;
                pvt->info.get_node_id = get_node_id;
                pvt->info.rir_limit = rir_limit;
+               pvt->info.sad_limit = sad_limit;
+               pvt->info.interleave_mode = interleave_mode;
+               pvt->info.show_interleave_mode = show_interleave_mode;
+               pvt->info.dram_attr = dram_attr;
                pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule);
                pvt->info.interleave_list = sbridge_interleave_list;
                pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list);
@@ -2441,6 +3343,10 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
                pvt->info.get_memory_type = haswell_get_memory_type;
                pvt->info.get_node_id = haswell_get_node_id;
                pvt->info.rir_limit = haswell_rir_limit;
+               pvt->info.sad_limit = sad_limit;
+               pvt->info.interleave_mode = interleave_mode;
+               pvt->info.show_interleave_mode = show_interleave_mode;
+               pvt->info.dram_attr = dram_attr;
                pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
                pvt->info.interleave_list = ibridge_interleave_list;
                pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
@@ -2461,6 +3367,10 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
                pvt->info.get_memory_type = haswell_get_memory_type;
                pvt->info.get_node_id = haswell_get_node_id;
                pvt->info.rir_limit = haswell_rir_limit;
+               pvt->info.sad_limit = sad_limit;
+               pvt->info.interleave_mode = interleave_mode;
+               pvt->info.show_interleave_mode = show_interleave_mode;
+               pvt->info.dram_attr = dram_attr;
                pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
                pvt->info.interleave_list = ibridge_interleave_list;
                pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
@@ -2473,6 +3383,30 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
                if (unlikely(rc < 0))
                        goto fail0;
                break;
+       case KNIGHTS_LANDING:
+               /* pvt->info.rankcfgr == ??? */
+               pvt->info.get_tolm = knl_get_tolm;
+               pvt->info.get_tohm = knl_get_tohm;
+               pvt->info.dram_rule = knl_dram_rule;
+               pvt->info.get_memory_type = knl_get_memory_type;
+               pvt->info.get_node_id = knl_get_node_id;
+               pvt->info.rir_limit = NULL;
+               pvt->info.sad_limit = knl_sad_limit;
+               pvt->info.interleave_mode = knl_interleave_mode;
+               pvt->info.show_interleave_mode = knl_show_interleave_mode;
+               pvt->info.dram_attr = dram_attr_knl;
+               pvt->info.max_sad = ARRAY_SIZE(knl_dram_rule);
+               pvt->info.interleave_list = knl_interleave_list;
+               pvt->info.max_interleave = ARRAY_SIZE(knl_interleave_list);
+               pvt->info.interleave_pkg = ibridge_interleave_pkg;
+               pvt->info.get_width = knl_get_width;
+               mci->ctl_name = kasprintf(GFP_KERNEL,
+                       "Knights Landing Socket#%d", mci->mc_idx);
+
+               rc = knl_mci_bind_devs(mci, sbridge_dev);
+               if (unlikely(rc < 0))
+                       goto fail0;
+               break;
        }
 
        /* Get dimm basic config and the memory layout */
@@ -2527,20 +3461,29 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        switch (pdev->device) {
        case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA:
-               rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_ibridge_table);
+               rc = sbridge_get_all_devices(&num_mc,
+                                       pci_dev_descr_ibridge_table);
                type = IVY_BRIDGE;
                break;
        case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0:
-               rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table);
+               rc = sbridge_get_all_devices(&num_mc,
+                                       pci_dev_descr_sbridge_table);
                type = SANDY_BRIDGE;
                break;
        case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0:
-               rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_haswell_table);
+               rc = sbridge_get_all_devices(&num_mc,
+                                       pci_dev_descr_haswell_table);
                type = HASWELL;
                break;
        case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0:
-               rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_broadwell_table);
+               rc = sbridge_get_all_devices(&num_mc,
+                                       pci_dev_descr_broadwell_table);
                type = BROADWELL;
+           break;
+       case PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0:
+               rc = sbridge_get_all_devices_knl(&num_mc,
+                                       pci_dev_descr_knl_table);
+               type = KNIGHTS_LANDING;
                break;
        }
        if (unlikely(rc < 0)) {
diff --git a/drivers/edac/wq.c b/drivers/edac/wq.c
new file mode 100644 (file)
index 0000000..1b8c07e
--- /dev/null
@@ -0,0 +1,42 @@
+#include "edac_module.h"
+
+static struct workqueue_struct *wq;
+
+bool edac_queue_work(struct delayed_work *work, unsigned long delay)
+{
+       return queue_delayed_work(wq, work, delay);
+}
+EXPORT_SYMBOL_GPL(edac_queue_work);
+
+bool edac_mod_work(struct delayed_work *work, unsigned long delay)
+{
+       return mod_delayed_work(wq, work, delay);
+}
+EXPORT_SYMBOL_GPL(edac_mod_work);
+
+bool edac_stop_work(struct delayed_work *work)
+{
+       bool ret;
+
+       ret = cancel_delayed_work_sync(work);
+       flush_workqueue(wq);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(edac_stop_work);
+
+int edac_workqueue_setup(void)
+{
+       wq = create_singlethread_workqueue("edac-poller");
+       if (!wq)
+               return -ENODEV;
+       else
+               return 0;
+}
+
+void edac_workqueue_teardown(void)
+{
+       flush_workqueue(wq);
+       destroy_workqueue(wq);
+       wq = NULL;
+}
index cf478fe6b335bc2cde8da7ae7f6695f9576f38ef..49a3a1185bb607ed45297fe4dea5ff2c6344f37f 100644 (file)
@@ -173,6 +173,9 @@ config QCOM_SCM_64
        def_bool y
        depends on QCOM_SCM && ARM64
 
+config HAVE_ARM_SMCCC
+       bool
+
 source "drivers/firmware/broadcom/Kconfig"
 source "drivers/firmware/google/Kconfig"
 source "drivers/firmware/efi/Kconfig"
index ac1ce4a73edfc6160924f3ebcb1b0ddb2baf3792..0e08e665f715fb1de98b3118553f858c5b4c2c64 100644 (file)
@@ -521,6 +521,7 @@ static int __init dmi_present(const u8 *buf)
                        dmi_ver = smbios_ver;
                else
                        dmi_ver = (buf[14] & 0xF0) << 4 | (buf[14] & 0x0F);
+               dmi_ver <<= 8;
                dmi_num = get_unaligned_le16(buf + 12);
                dmi_len = get_unaligned_le16(buf + 6);
                dmi_base = get_unaligned_le32(buf + 8);
@@ -528,15 +529,14 @@ static int __init dmi_present(const u8 *buf)
                if (dmi_walk_early(dmi_decode) == 0) {
                        if (smbios_ver) {
                                pr_info("SMBIOS %d.%d present.\n",
-                                      dmi_ver >> 8, dmi_ver & 0xFF);
+                                       dmi_ver >> 16, (dmi_ver >> 8) & 0xFF);
                        } else {
                                smbios_entry_point_size = 15;
                                memcpy(smbios_entry_point, buf,
                                       smbios_entry_point_size);
                                pr_info("Legacy DMI %d.%d present.\n",
-                                      dmi_ver >> 8, dmi_ver & 0xFF);
+                                       dmi_ver >> 16, (dmi_ver >> 8) & 0xFF);
                        }
-                       dmi_ver <<= 8;
                        dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string));
                        printk(KERN_DEBUG "DMI: %s\n", dmi_ids_string);
                        return 0;
index ec379a4164cc07474fd5f2c193cbe6437df0e6fd..62e654f255f4d1e4cb1ee1b955e8fd03ca689221 100644 (file)
@@ -18,3 +18,7 @@ obj-$(CONFIG_EFI_RUNTIME_MAP)         += runtime-map.o
 obj-$(CONFIG_EFI_RUNTIME_WRAPPERS)     += runtime-wrappers.o
 obj-$(CONFIG_EFI_STUB)                 += libstub/
 obj-$(CONFIG_EFI_FAKE_MEMMAP)          += fake_mem.o
+
+arm-obj-$(CONFIG_EFI)                  := arm-init.o arm-runtime.o
+obj-$(CONFIG_ARM)                      += $(arm-obj-y)
+obj-$(CONFIG_ARM64)                    += $(arm-obj-y)
diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c
new file mode 100644 (file)
index 0000000..9e15d57
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Extensible Firmware Interface
+ *
+ * Based on Extensible Firmware Interface Specification version 2.4
+ *
+ * Copyright (C) 2013 - 2015 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/efi.h>
+#include <linux/init.h>
+#include <linux/memblock.h>
+#include <linux/mm_types.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+
+#include <asm/efi.h>
+
+struct efi_memory_map memmap;
+
+u64 efi_system_table;
+
+static int __init is_normal_ram(efi_memory_desc_t *md)
+{
+       if (md->attribute & EFI_MEMORY_WB)
+               return 1;
+       return 0;
+}
+
+/*
+ * Translate a EFI virtual address into a physical address: this is necessary,
+ * as some data members of the EFI system table are virtually remapped after
+ * SetVirtualAddressMap() has been called.
+ */
+static phys_addr_t efi_to_phys(unsigned long addr)
+{
+       efi_memory_desc_t *md;
+
+       for_each_efi_memory_desc(&memmap, md) {
+               if (!(md->attribute & EFI_MEMORY_RUNTIME))
+                       continue;
+               if (md->virt_addr == 0)
+                       /* no virtual mapping has been installed by the stub */
+                       break;
+               if (md->virt_addr <= addr &&
+                   (addr - md->virt_addr) < (md->num_pages << EFI_PAGE_SHIFT))
+                       return md->phys_addr + addr - md->virt_addr;
+       }
+       return addr;
+}
+
+static int __init uefi_init(void)
+{
+       efi_char16_t *c16;
+       void *config_tables;
+       size_t table_size;
+       char vendor[100] = "unknown";
+       int i, retval;
+
+       efi.systab = early_memremap(efi_system_table,
+                                   sizeof(efi_system_table_t));
+       if (efi.systab == NULL) {
+               pr_warn("Unable to map EFI system table.\n");
+               return -ENOMEM;
+       }
+
+       set_bit(EFI_BOOT, &efi.flags);
+       if (IS_ENABLED(CONFIG_64BIT))
+               set_bit(EFI_64BIT, &efi.flags);
+
+       /*
+        * Verify the EFI Table
+        */
+       if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
+               pr_err("System table signature incorrect\n");
+               retval = -EINVAL;
+               goto out;
+       }
+       if ((efi.systab->hdr.revision >> 16) < 2)
+               pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n",
+                       efi.systab->hdr.revision >> 16,
+                       efi.systab->hdr.revision & 0xffff);
+
+       /* Show what we know for posterity */
+       c16 = early_memremap(efi_to_phys(efi.systab->fw_vendor),
+                            sizeof(vendor) * sizeof(efi_char16_t));
+       if (c16) {
+               for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
+                       vendor[i] = c16[i];
+               vendor[i] = '\0';
+               early_memunmap(c16, sizeof(vendor) * sizeof(efi_char16_t));
+       }
+
+       pr_info("EFI v%u.%.02u by %s\n",
+               efi.systab->hdr.revision >> 16,
+               efi.systab->hdr.revision & 0xffff, vendor);
+
+       table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables;
+       config_tables = early_memremap(efi_to_phys(efi.systab->tables),
+                                      table_size);
+       if (config_tables == NULL) {
+               pr_warn("Unable to map EFI config table array.\n");
+               retval = -ENOMEM;
+               goto out;
+       }
+       retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables,
+                                        sizeof(efi_config_table_t), NULL);
+
+       early_memunmap(config_tables, table_size);
+out:
+       early_memunmap(efi.systab,  sizeof(efi_system_table_t));
+       return retval;
+}
+
+/*
+ * Return true for RAM regions we want to permanently reserve.
+ */
+static __init int is_reserve_region(efi_memory_desc_t *md)
+{
+       switch (md->type) {
+       case EFI_LOADER_CODE:
+       case EFI_LOADER_DATA:
+       case EFI_BOOT_SERVICES_CODE:
+       case EFI_BOOT_SERVICES_DATA:
+       case EFI_CONVENTIONAL_MEMORY:
+       case EFI_PERSISTENT_MEMORY:
+               return 0;
+       default:
+               break;
+       }
+       return is_normal_ram(md);
+}
+
+static __init void reserve_regions(void)
+{
+       efi_memory_desc_t *md;
+       u64 paddr, npages, size;
+
+       if (efi_enabled(EFI_DBG))
+               pr_info("Processing EFI memory map:\n");
+
+       for_each_efi_memory_desc(&memmap, md) {
+               paddr = md->phys_addr;
+               npages = md->num_pages;
+
+               if (efi_enabled(EFI_DBG)) {
+                       char buf[64];
+
+                       pr_info("  0x%012llx-0x%012llx %s",
+                               paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1,
+                               efi_md_typeattr_format(buf, sizeof(buf), md));
+               }
+
+               memrange_efi_to_native(&paddr, &npages);
+               size = npages << PAGE_SHIFT;
+
+               if (is_normal_ram(md))
+                       early_init_dt_add_memory_arch(paddr, size);
+
+               if (is_reserve_region(md)) {
+                       memblock_mark_nomap(paddr, size);
+                       if (efi_enabled(EFI_DBG))
+                               pr_cont("*");
+               }
+
+               if (efi_enabled(EFI_DBG))
+                       pr_cont("\n");
+       }
+
+       set_bit(EFI_MEMMAP, &efi.flags);
+}
+
+void __init efi_init(void)
+{
+       struct efi_fdt_params params;
+
+       /* Grab UEFI information placed in FDT by stub */
+       if (!efi_get_fdt_params(&params))
+               return;
+
+       efi_system_table = params.system_table;
+
+       memmap.phys_map = params.mmap;
+       memmap.map = early_memremap(params.mmap, params.mmap_size);
+       if (memmap.map == NULL) {
+               /*
+               * If we are booting via UEFI, the UEFI memory map is the only
+               * description of memory we have, so there is little point in
+               * proceeding if we cannot access it.
+               */
+               panic("Unable to map EFI memory map.\n");
+       }
+       memmap.map_end = memmap.map + params.mmap_size;
+       memmap.desc_size = params.desc_size;
+       memmap.desc_version = params.desc_ver;
+
+       if (uefi_init() < 0)
+               return;
+
+       reserve_regions();
+       early_memunmap(memmap.map, params.mmap_size);
+       memblock_mark_nomap(params.mmap & PAGE_MASK,
+                           PAGE_ALIGN(params.mmap_size +
+                                      (params.mmap & ~PAGE_MASK)));
+}
diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c
new file mode 100644 (file)
index 0000000..6ae21e4
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Extensible Firmware Interface
+ *
+ * Based on Extensible Firmware Interface Specification version 2.4
+ *
+ * Copyright (C) 2013, 2014 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/efi.h>
+#include <linux/io.h>
+#include <linux/memblock.h>
+#include <linux/mm_types.h>
+#include <linux/preempt.h>
+#include <linux/rbtree.h>
+#include <linux/rwsem.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <asm/cacheflush.h>
+#include <asm/efi.h>
+#include <asm/mmu.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+
+extern u64 efi_system_table;
+
+static struct mm_struct efi_mm = {
+       .mm_rb                  = RB_ROOT,
+       .mm_users               = ATOMIC_INIT(2),
+       .mm_count               = ATOMIC_INIT(1),
+       .mmap_sem               = __RWSEM_INITIALIZER(efi_mm.mmap_sem),
+       .page_table_lock        = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock),
+       .mmlist                 = LIST_HEAD_INIT(efi_mm.mmlist),
+};
+
+static bool __init efi_virtmap_init(void)
+{
+       efi_memory_desc_t *md;
+
+       efi_mm.pgd = pgd_alloc(&efi_mm);
+       init_new_context(NULL, &efi_mm);
+
+       for_each_efi_memory_desc(&memmap, md) {
+               phys_addr_t phys = md->phys_addr;
+               int ret;
+
+               if (!(md->attribute & EFI_MEMORY_RUNTIME))
+                       continue;
+               if (md->virt_addr == 0)
+                       return false;
+
+               ret = efi_create_mapping(&efi_mm, md);
+               if  (!ret) {
+                       pr_info("  EFI remap %pa => %p\n",
+                               &phys, (void *)(unsigned long)md->virt_addr);
+               } else {
+                       pr_warn("  EFI remap %pa: failed to create mapping (%d)\n",
+                               &phys, ret);
+                       return false;
+               }
+       }
+       return true;
+}
+
+/*
+ * Enable the UEFI Runtime Services if all prerequisites are in place, i.e.,
+ * non-early mapping of the UEFI system table and virtual mappings for all
+ * EFI_MEMORY_RUNTIME regions.
+ */
+static int __init arm_enable_runtime_services(void)
+{
+       u64 mapsize;
+
+       if (!efi_enabled(EFI_BOOT)) {
+               pr_info("EFI services will not be available.\n");
+               return 0;
+       }
+
+       if (efi_runtime_disabled()) {
+               pr_info("EFI runtime services will be disabled.\n");
+               return 0;
+       }
+
+       pr_info("Remapping and enabling EFI services.\n");
+
+       mapsize = memmap.map_end - memmap.map;
+       memmap.map = (__force void *)ioremap_cache(memmap.phys_map,
+                                                  mapsize);
+       if (!memmap.map) {
+               pr_err("Failed to remap EFI memory map\n");
+               return -ENOMEM;
+       }
+       memmap.map_end = memmap.map + mapsize;
+       efi.memmap = &memmap;
+
+       efi.systab = (__force void *)ioremap_cache(efi_system_table,
+                                                  sizeof(efi_system_table_t));
+       if (!efi.systab) {
+               pr_err("Failed to remap EFI System Table\n");
+               return -ENOMEM;
+       }
+       set_bit(EFI_SYSTEM_TABLES, &efi.flags);
+
+       if (!efi_virtmap_init()) {
+               pr_err("No UEFI virtual mapping was installed -- runtime services will not be available\n");
+               return -ENOMEM;
+       }
+
+       /* Set up runtime services function pointers */
+       efi_native_runtime_setup();
+       set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+
+       efi.runtime_version = efi.systab->hdr.revision;
+
+       return 0;
+}
+early_initcall(arm_enable_runtime_services);
+
+void efi_virtmap_load(void)
+{
+       preempt_disable();
+       efi_set_pgd(&efi_mm);
+}
+
+void efi_virtmap_unload(void)
+{
+       efi_set_pgd(current->active_mm);
+       preempt_enable();
+}
index 027ca212179f7f81276733d0bda6b97a636c6770..cffa89b3317b59f0194c01e1caaafe52bb3496bc 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 
+#include <asm/efi.h>
+
 struct efi __read_mostly efi = {
        .mps                    = EFI_INVALID_TABLE_ADDR,
        .acpi                   = EFI_INVALID_TABLE_ADDR,
index 3c0467d3688cff14df877fea66d61c3fbb3279bd..9c12e18031d57b29b1a18547447b17207b3054de 100644 (file)
@@ -8,7 +8,7 @@ cflags-$(CONFIG_X86_32)         := -march=i386
 cflags-$(CONFIG_X86_64)                := -mcmodel=small
 cflags-$(CONFIG_X86)           += -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2 \
                                   -fPIC -fno-strict-aliasing -mno-red-zone \
-                                  -mno-mmx -mno-sse -DDISABLE_BRANCH_PROFILING
+                                  -mno-mmx -mno-sse
 
 cflags-$(CONFIG_ARM64)         := $(subst -pg,,$(KBUILD_CFLAGS))
 cflags-$(CONFIG_ARM)           := $(subst -pg,,$(KBUILD_CFLAGS)) \
@@ -16,7 +16,7 @@ cflags-$(CONFIG_ARM)          := $(subst -pg,,$(KBUILD_CFLAGS)) \
 
 cflags-$(CONFIG_EFI_ARMSTUB)   += -I$(srctree)/scripts/dtc/libfdt
 
-KBUILD_CFLAGS                  := $(cflags-y) \
+KBUILD_CFLAGS                  := $(cflags-y) -DDISABLE_BRANCH_PROFILING \
                                   $(call cc-option,-ffreestanding) \
                                   $(call cc-option,-fno-stack-protector)
 
@@ -34,6 +34,7 @@ $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
 lib-$(CONFIG_EFI_ARMSTUB)      += arm-stub.o fdt.o string.o \
                                   $(patsubst %.c,lib-%.o,$(arm-deps))
 
+lib-$(CONFIG_ARM)              += arm32-stub.o
 lib-$(CONFIG_ARM64)            += arm64-stub.o
 CFLAGS_arm64-stub.o            := -DTEXT_OFFSET=$(TEXT_OFFSET)
 
@@ -67,3 +68,11 @@ quiet_cmd_stubcopy = STUBCPY $@
                     $(OBJDUMP) -r $@ | grep $(STUBCOPY_RELOC-y)        \
                     && (echo >&2 "$@: absolute symbol references not allowed in the EFI stub"; \
                         rm -f $@; /bin/false); else /bin/false; fi
+
+#
+# ARM discards the .data section because it disallows r/w data in the
+# decompressor. So move our .data to .data.efistub, which is preserved
+# explicitly by the decompressor linker script.
+#
+STUBCOPY_FLAGS-$(CONFIG_ARM)   += --rename-section .data=.data.efistub
+STUBCOPY_RELOC-$(CONFIG_ARM)   := R_ARM_ABS
index 950c87f5d279335210088e4154eda135b24304d5..3397902e4040a30f566ff4b84555f17d7150d8f8 100644 (file)
@@ -303,8 +303,10 @@ fail:
  * The value chosen is the largest non-zero power of 2 suitable for this purpose
  * both on 32-bit and 64-bit ARM CPUs, to maximize the likelihood that it can
  * be mapped efficiently.
+ * Since 32-bit ARM could potentially execute with a 1G/3G user/kernel split,
+ * map everything below 1 GB.
  */
-#define EFI_RT_VIRTUAL_BASE    0x40000000
+#define EFI_RT_VIRTUAL_BASE    SZ_512M
 
 static int cmp_mem_desc(const void *l, const void *r)
 {
diff --git a/drivers/firmware/efi/libstub/arm32-stub.c b/drivers/firmware/efi/libstub/arm32-stub.c
new file mode 100644 (file)
index 0000000..495ebd6
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2013 Linaro Ltd;  <roy.franz@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/efi.h>
+#include <asm/efi.h>
+
+efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
+                                unsigned long *image_addr,
+                                unsigned long *image_size,
+                                unsigned long *reserve_addr,
+                                unsigned long *reserve_size,
+                                unsigned long dram_base,
+                                efi_loaded_image_t *image)
+{
+       unsigned long nr_pages;
+       efi_status_t status;
+       /* Use alloc_addr to tranlsate between types */
+       efi_physical_addr_t alloc_addr;
+
+       /*
+        * Verify that the DRAM base address is compatible with the ARM
+        * boot protocol, which determines the base of DRAM by masking
+        * off the low 27 bits of the address at which the zImage is
+        * loaded. These assumptions are made by the decompressor,
+        * before any memory map is available.
+        */
+       dram_base = round_up(dram_base, SZ_128M);
+
+       /*
+        * Reserve memory for the uncompressed kernel image. This is
+        * all that prevents any future allocations from conflicting
+        * with the kernel. Since we can't tell from the compressed
+        * image how much DRAM the kernel actually uses (due to BSS
+        * size uncertainty) we allocate the maximum possible size.
+        * Do this very early, as prints can cause memory allocations
+        * that may conflict with this.
+        */
+       alloc_addr = dram_base;
+       *reserve_size = MAX_UNCOMP_KERNEL_SIZE;
+       nr_pages = round_up(*reserve_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
+       status = sys_table->boottime->allocate_pages(EFI_ALLOCATE_ADDRESS,
+                                                    EFI_LOADER_DATA,
+                                                    nr_pages, &alloc_addr);
+       if (status != EFI_SUCCESS) {
+               *reserve_size = 0;
+               pr_efi_err(sys_table, "Unable to allocate memory for uncompressed kernel.\n");
+               return status;
+       }
+       *reserve_addr = alloc_addr;
+
+       /*
+        * Relocate the zImage, so that it appears in the lowest 128 MB
+        * memory window.
+        */
+       *image_size = image->image_size;
+       status = efi_relocate_kernel(sys_table, image_addr, *image_size,
+                                    *image_size,
+                                    dram_base + MAX_UNCOMP_KERNEL_SIZE, 0);
+       if (status != EFI_SUCCESS) {
+               pr_efi_err(sys_table, "Failed to relocate kernel.\n");
+               efi_free(sys_table, *reserve_size, *reserve_addr);
+               *reserve_size = 0;
+               return status;
+       }
+
+       /*
+        * Check to see if we were able to allocate memory low enough
+        * in memory. The kernel determines the base of DRAM from the
+        * address at which the zImage is loaded.
+        */
+       if (*image_addr + *image_size > dram_base + ZIMAGE_OFFSET_LIMIT) {
+               pr_efi_err(sys_table, "Failed to relocate kernel, no low memory available.\n");
+               efi_free(sys_table, *reserve_size, *reserve_addr);
+               *reserve_size = 0;
+               efi_free(sys_table, *image_size, *image_addr);
+               *image_size = 0;
+               return EFI_LOAD_ERROR;
+       }
+       return EFI_SUCCESS;
+}
index d24f35d74b27079afeae5c08d601c3bcd899dee6..f25cd79c8a79f834f8d3e169684d20ee4ced08e6 100644 (file)
@@ -13,6 +13,7 @@
 
 #define pr_fmt(fmt) "psci: " fmt
 
+#include <linux/arm-smccc.h>
 #include <linux/errno.h>
 #include <linux/linkage.h>
 #include <linux/of.h>
@@ -58,8 +59,6 @@ struct psci_operations psci_ops;
 
 typedef unsigned long (psci_fn)(unsigned long, unsigned long,
                                unsigned long, unsigned long);
-asmlinkage psci_fn __invoke_psci_fn_hvc;
-asmlinkage psci_fn __invoke_psci_fn_smc;
 static psci_fn *invoke_psci_fn;
 
 enum psci_function {
@@ -107,6 +106,26 @@ bool psci_power_state_is_valid(u32 state)
        return !(state & ~valid_mask);
 }
 
+static unsigned long __invoke_psci_fn_hvc(unsigned long function_id,
+                       unsigned long arg0, unsigned long arg1,
+                       unsigned long arg2)
+{
+       struct arm_smccc_res res;
+
+       arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
+       return res.a0;
+}
+
+static unsigned long __invoke_psci_fn_smc(unsigned long function_id,
+                       unsigned long arg0, unsigned long arg1,
+                       unsigned long arg2)
+{
+       struct arm_smccc_res res;
+
+       arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
+       return res.a0;
+}
+
 static int psci_to_linux_errno(int errno)
 {
        switch (errno) {
index beb0374a19f199d23c73116dcfcd08c3d500dde0..32cf973469785cb916eb3c2bdd125a741efb5e4c 100644 (file)
@@ -12123,18 +12123,22 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
 static bool check_digital_port_conflicts(struct drm_atomic_state *state)
 {
        struct drm_device *dev = state->dev;
-       struct intel_encoder *encoder;
        struct drm_connector *connector;
-       struct drm_connector_state *connector_state;
        unsigned int used_ports = 0;
-       int i;
 
        /*
         * Walk the connector list instead of the encoder
         * list to detect the problem on ddi platforms
         * where there's just one encoder per digital port.
         */
-       for_each_connector_in_state(state, connector, connector_state, i) {
+       drm_for_each_connector(connector, dev) {
+               struct drm_connector_state *connector_state;
+               struct intel_encoder *encoder;
+
+               connector_state = drm_atomic_get_existing_connector_state(state, connector);
+               if (!connector_state)
+                       connector_state = connector->state;
+
                if (!connector_state->best_encoder)
                        continue;
 
index 64086f2d4e26c7a46144a2e1eebea8ef7154a06a..e6c035b0fc1ce2d2e674aec93cb50c0ad7b7db67 100644 (file)
@@ -1381,7 +1381,7 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
 
        intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
 
-       for (try = 0; !live_status && try < 4; try++) {
+       for (try = 0; !live_status && try < 9; try++) {
                if (try)
                        msleep(10);
                live_status = intel_digital_port_connected(dev_priv,
index ffa902ece87234420d2b25d1603995f5679b5245..05a895496fc66f6f96efd64cbdbe822e4baaf1cc 100644 (file)
@@ -156,6 +156,7 @@ nv40_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
                return -ENOMEM;
        nvkm_object_ctor(&nv40_gr_chan, oclass, &chan->object);
        chan->gr = gr;
+       chan->fifo = fifoch;
        *pobject = &chan->object;
 
        spin_lock_irqsave(&chan->gr->base.engine.lock, flags);
index 63eb16bf2cf0a886aec1b3fc3967daea8a12fb95..883a314cd83ae5841dc2fd14ba03bd9228297a09 100644 (file)
@@ -161,7 +161,7 @@ static u32 ipu_ch_param_read_field(struct ipuv3_channel *ch, u32 wbs)
  * The DRM pixel formats and IPU internal representation are ordered the other
  * way around, with the first named component ordered at the most significant
  * bits. Further, V4L2 formats are not well defined:
- *     http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
+ *     https://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
  * We choose the interpretation which matches GStreamer behavior.
  */
 static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
index 3782636562a1b0c2b7d16273c14db14e8549e768..678663e2085fb15ab037f63c2760cc44e088085d 100644 (file)
@@ -63,10 +63,6 @@ enum hv_cpuid_function {
 /* Define version of the synthetic interrupt controller. */
 #define HV_SYNIC_VERSION               (1)
 
-/* Define synthetic interrupt controller message constants. */
-#define HV_MESSAGE_SIZE                        (256)
-#define HV_MESSAGE_PAYLOAD_BYTE_COUNT  (240)
-#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30)
 #define HV_ANY_VP                      (0xFFFFFFFF)
 
 /* Define synthetic interrupt controller flag constants. */
@@ -74,48 +70,9 @@ enum hv_cpuid_function {
 #define HV_EVENT_FLAGS_BYTE_COUNT      (256)
 #define HV_EVENT_FLAGS_DWORD_COUNT     (256 / sizeof(u32))
 
-/* Define hypervisor message types. */
-enum hv_message_type {
-       HVMSG_NONE                      = 0x00000000,
-
-       /* Memory access messages. */
-       HVMSG_UNMAPPED_GPA              = 0x80000000,
-       HVMSG_GPA_INTERCEPT             = 0x80000001,
-
-       /* Timer notification messages. */
-       HVMSG_TIMER_EXPIRED                     = 0x80000010,
-
-       /* Error messages. */
-       HVMSG_INVALID_VP_REGISTER_VALUE = 0x80000020,
-       HVMSG_UNRECOVERABLE_EXCEPTION   = 0x80000021,
-       HVMSG_UNSUPPORTED_FEATURE               = 0x80000022,
-
-       /* Trace buffer complete messages. */
-       HVMSG_EVENTLOG_BUFFERCOMPLETE   = 0x80000040,
-
-       /* Platform-specific processor intercept messages. */
-       HVMSG_X64_IOPORT_INTERCEPT              = 0x80010000,
-       HVMSG_X64_MSR_INTERCEPT         = 0x80010001,
-       HVMSG_X64_CPUID_INTERCEPT               = 0x80010002,
-       HVMSG_X64_EXCEPTION_INTERCEPT   = 0x80010003,
-       HVMSG_X64_APIC_EOI                      = 0x80010004,
-       HVMSG_X64_LEGACY_FP_ERROR               = 0x80010005
-};
-
-#define HV_SYNIC_STIMER_COUNT          (4)
-
 /* Define invalid partition identifier. */
 #define HV_PARTITION_ID_INVALID                ((u64)0x0)
 
-/* Define port identifier type. */
-union hv_port_id {
-       u32 asu32;
-       struct {
-               u32 id:24;
-               u32 reserved:8;
-       } u ;
-};
-
 /* Define port type. */
 enum hv_port_type {
        HVPORT_MSG      = 1,
@@ -163,27 +120,6 @@ struct hv_connection_info {
        };
 };
 
-/* Define synthetic interrupt controller message flags. */
-union hv_message_flags {
-       u8 asu8;
-       struct {
-               u8 msg_pending:1;
-               u8 reserved:7;
-       };
-};
-
-/* Define synthetic interrupt controller message header. */
-struct hv_message_header {
-       enum hv_message_type message_type;
-       u8 payload_size;
-       union hv_message_flags message_flags;
-       u8 reserved[2];
-       union {
-               u64 sender;
-               union hv_port_id port;
-       };
-};
-
 /*
  * Timer configuration register.
  */
@@ -200,31 +136,9 @@ union hv_timer_config {
        };
 };
 
-
-/* Define timer message payload structure. */
-struct hv_timer_message_payload {
-       u32 timer_index;
-       u32 reserved;
-       u64 expiration_time;    /* When the timer expired */
-       u64 delivery_time;      /* When the message was delivered */
-};
-
-/* Define synthetic interrupt controller message format. */
-struct hv_message {
-       struct hv_message_header header;
-       union {
-               u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
-       } u ;
-};
-
 /* Define the number of message buffers associated with each port. */
 #define HV_PORT_MESSAGE_BUFFER_COUNT   (16)
 
-/* Define the synthetic interrupt message page layout. */
-struct hv_message_page {
-       struct hv_message sint_message[HV_SYNIC_SINT_COUNT];
-};
-
 /* Define the synthetic interrupt controller event flags format. */
 union hv_synic_event_flags {
        u8 flags8[HV_EVENT_FLAGS_BYTE_COUNT];
@@ -347,7 +261,7 @@ enum hv_call_code {
 struct hv_input_post_message {
        union hv_connection_id connectionid;
        u32 reserved;
-       enum hv_message_type message_type;
+       u32 message_type;
        u32 payload_size;
        u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
 };
index 80a73bfc1a65807db6fc276e3027f11500d2f96b..60fb80bd353d601563c57710d8e897d0af50bd30 100644 (file)
@@ -859,16 +859,6 @@ config SENSORS_MAX31790
          This driver can also be built as a module.  If so, the module
          will be called max31790.
 
-config SENSORS_HTU21
-       tristate "Measurement Specialties HTU21D humidity/temperature sensors"
-       depends on I2C
-       help
-         If you say yes here you get support for the Measurement Specialties
-         HTU21D humidity and temperature sensors.
-
-         This driver can also be built as a module.  If so, the module
-         will be called htu21.
-
 config SENSORS_MCP3021
        tristate "Microchip MCP3021 and compatibles"
        depends on I2C
index 12a32398fdcc6c2e92a5645aebacddc4da0f52f2..30c94df314658fc8f9dcb04c7ae05eb141c979e1 100644 (file)
@@ -68,7 +68,6 @@ obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
 obj-$(CONFIG_SENSORS_GL520SM)  += gl520sm.o
 obj-$(CONFIG_SENSORS_GPIO_FAN) += gpio-fan.o
 obj-$(CONFIG_SENSORS_HIH6130)  += hih6130.o
-obj-$(CONFIG_SENSORS_HTU21)    += htu21.o
 obj-$(CONFIG_SENSORS_ULTRA45)  += ultra45_env.o
 obj-$(CONFIG_SENSORS_I5500)    += i5500_temp.o
 obj-$(CONFIG_SENSORS_I5K_AMB)  += i5k_amb.o
index 5f7067d7b625c6578c4b135becd159d50e8b0eee..f77eb971ce959a6d3501dfdf740e8f8f566383e5 100644 (file)
@@ -47,6 +47,8 @@ MODULE_LICENSE("GPL");
 
 #define MSR_F15H_CU_MAX_PWR_ACCUMULATOR        0xc001007b
 
+#define PCI_DEVICE_ID_AMD_15H_M70H_NB_F4 0x15b4
+
 struct fam15h_power_data {
        struct pci_dev *pdev;
        unsigned int tdp_to_watts;
@@ -124,7 +126,7 @@ static int fam15h_power_init_attrs(struct pci_dev *pdev,
 
        if (c->x86 == 0x15 &&
            (c->x86_model <= 0xf ||
-            (c->x86_model >= 0x60 && c->x86_model <= 0x6f)))
+            (c->x86_model >= 0x60 && c->x86_model <= 0x7f)))
                n += 1;
 
        fam15h_power_attrs = devm_kcalloc(&pdev->dev, n,
@@ -138,7 +140,7 @@ static int fam15h_power_init_attrs(struct pci_dev *pdev,
        fam15h_power_attrs[n++] = &dev_attr_power1_crit.attr;
        if (c->x86 == 0x15 &&
            (c->x86_model <= 0xf ||
-            (c->x86_model >= 0x60 && c->x86_model <= 0x6f)))
+            (c->x86_model >= 0x60 && c->x86_model <= 0x7f)))
                fam15h_power_attrs[n++] = &dev_attr_power1_input.attr;
 
        data->group.attrs = fam15h_power_attrs;
@@ -296,6 +298,7 @@ static const struct pci_device_id fam15h_power_id_table[] = {
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F4) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F4) },
+       { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M70H_NB_F4) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F4) },
        {}
diff --git a/drivers/hwmon/htu21.c b/drivers/hwmon/htu21.c
deleted file mode 100644 (file)
index 4c3bbb7..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Measurement Specialties HTU21D humidity and temperature sensor driver
- *
- * Copyright (C) 2013 William Markezana <william.markezana@meas-spec.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/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/err.h>
-#include <linux/mutex.h>
-#include <linux/device.h>
-#include <linux/jiffies.h>
-
-/* HTU21 Commands */
-#define HTU21_T_MEASUREMENT_HM 0xE3
-#define HTU21_RH_MEASUREMENT_HM        0xE5
-
-struct htu21 {
-       struct i2c_client *client;
-       struct mutex lock;
-       bool valid;
-       unsigned long last_update;
-       int temperature;
-       int humidity;
-};
-
-static inline int htu21_temp_ticks_to_millicelsius(int ticks)
-{
-       ticks &= ~0x0003; /* clear status bits */
-       /*
-        * Formula T = -46.85 + 175.72 * ST / 2^16 from datasheet p14,
-        * optimized for integer fixed point (3 digits) arithmetic
-        */
-       return ((21965 * ticks) >> 13) - 46850;
-}
-
-static inline int htu21_rh_ticks_to_per_cent_mille(int ticks)
-{
-       ticks &= ~0x0003; /* clear status bits */
-       /*
-        * Formula RH = -6 + 125 * SRH / 2^16 from datasheet p14,
-        * optimized for integer fixed point (3 digits) arithmetic
-        */
-       return ((15625 * ticks) >> 13) - 6000;
-}
-
-static int htu21_update_measurements(struct device *dev)
-{
-       struct htu21 *htu21 = dev_get_drvdata(dev);
-       struct i2c_client *client = htu21->client;
-       int ret = 0;
-
-       mutex_lock(&htu21->lock);
-
-       if (time_after(jiffies, htu21->last_update + HZ / 2) ||
-           !htu21->valid) {
-               ret = i2c_smbus_read_word_swapped(client,
-                                                 HTU21_T_MEASUREMENT_HM);
-               if (ret < 0)
-                       goto out;
-               htu21->temperature = htu21_temp_ticks_to_millicelsius(ret);
-               ret = i2c_smbus_read_word_swapped(client,
-                                                 HTU21_RH_MEASUREMENT_HM);
-               if (ret < 0)
-                       goto out;
-               htu21->humidity = htu21_rh_ticks_to_per_cent_mille(ret);
-               htu21->last_update = jiffies;
-               htu21->valid = true;
-       }
-out:
-       mutex_unlock(&htu21->lock);
-
-       return ret >= 0 ? 0 : ret;
-}
-
-static ssize_t htu21_show_temperature(struct device *dev,
-                                     struct device_attribute *attr, char *buf)
-{
-       struct htu21 *htu21 = dev_get_drvdata(dev);
-       int ret;
-
-       ret = htu21_update_measurements(dev);
-       if (ret < 0)
-               return ret;
-       return sprintf(buf, "%d\n", htu21->temperature);
-}
-
-static ssize_t htu21_show_humidity(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
-{
-       struct htu21 *htu21 = dev_get_drvdata(dev);
-       int ret;
-
-       ret = htu21_update_measurements(dev);
-       if (ret < 0)
-               return ret;
-       return sprintf(buf, "%d\n", htu21->humidity);
-}
-
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
-                         htu21_show_temperature, NULL, 0);
-static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO,
-                         htu21_show_humidity, NULL, 0);
-
-static struct attribute *htu21_attrs[] = {
-       &sensor_dev_attr_temp1_input.dev_attr.attr,
-       &sensor_dev_attr_humidity1_input.dev_attr.attr,
-       NULL
-};
-
-ATTRIBUTE_GROUPS(htu21);
-
-static int htu21_probe(struct i2c_client *client,
-                      const struct i2c_device_id *id)
-{
-       struct device *dev = &client->dev;
-       struct htu21 *htu21;
-       struct device *hwmon_dev;
-
-       if (!i2c_check_functionality(client->adapter,
-                                    I2C_FUNC_SMBUS_READ_WORD_DATA)) {
-               dev_err(&client->dev,
-                       "adapter does not support SMBus word transactions\n");
-               return -ENODEV;
-       }
-
-       htu21 = devm_kzalloc(dev, sizeof(*htu21), GFP_KERNEL);
-       if (!htu21)
-               return -ENOMEM;
-
-       htu21->client = client;
-       mutex_init(&htu21->lock);
-
-       hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
-                                                          htu21,
-                                                          htu21_groups);
-       return PTR_ERR_OR_ZERO(hwmon_dev);
-}
-
-static const struct i2c_device_id htu21_id[] = {
-       { "htu21", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, htu21_id);
-
-static struct i2c_driver htu21_driver = {
-       .class = I2C_CLASS_HWMON,
-       .driver = {
-               .name   = "htu21",
-       },
-       .probe       = htu21_probe,
-       .id_table    = htu21_id,
-};
-
-module_i2c_driver(htu21_driver);
-
-MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
-MODULE_DESCRIPTION("MEAS HTU21D humidity and temperature sensor driver");
-MODULE_LICENSE("GPL");
index 7a8a6fbf11ff9618c482ad4dfe67da7804c65b35..1f643782ce04742730cb5c08b23e9be4f242c826 100644 (file)
@@ -920,8 +920,8 @@ static ssize_t aem_set_power_period(struct device *dev,
 
 /* Discover sensors on an AEM device */
 static int aem_register_sensors(struct aem_data *data,
-                               struct aem_ro_sensor_template *ro,
-                               struct aem_rw_sensor_template *rw)
+                               const struct aem_ro_sensor_template *ro,
+                               const struct aem_rw_sensor_template *rw)
 {
        struct device *dev = &data->pdev->dev;
        struct sensor_device_attribute *sensors = data->sensors;
@@ -1020,19 +1020,19 @@ static void aem_remove_sensors(struct aem_data *data)
 /* Sensor probe functions */
 
 /* Description of AEM1 sensors */
-static struct aem_ro_sensor_template aem1_ro_sensors[] = {
+static const struct aem_ro_sensor_template aem1_ro_sensors[] = {
 {"energy1_input",  aem_show_energy, 0},
 {"power1_average", aem_show_power,  0},
 {NULL,            NULL,            0},
 };
 
-static struct aem_rw_sensor_template aem1_rw_sensors[] = {
+static const struct aem_rw_sensor_template aem1_rw_sensors[] = {
 {"power1_average_interval", aem_show_power_period, aem_set_power_period, 0},
 {NULL,                     NULL,                  NULL,                 0},
 };
 
 /* Description of AEM2 sensors */
-static struct aem_ro_sensor_template aem2_ro_sensors[] = {
+static const struct aem_ro_sensor_template aem2_ro_sensors[] = {
 {"energy1_input",        aem_show_energy,      0},
 {"energy2_input",        aem_show_energy,      1},
 {"power1_average",       aem_show_power,       0},
@@ -1050,7 +1050,7 @@ static struct aem_ro_sensor_template aem2_ro_sensors[] = {
 {NULL,                    NULL,                 0},
 };
 
-static struct aem_rw_sensor_template aem2_rw_sensors[] = {
+static const struct aem_rw_sensor_template aem2_rw_sensors[] = {
 {"power1_average_interval", aem_show_power_period, aem_set_power_period, 0},
 {"power2_average_interval", aem_show_power_period, aem_set_power_period, 1},
 {NULL,                     NULL,                  NULL,                 0},
index 37f01702d08195b1a9bab1f82fe88434302556b9..559c596b24f9b916d9f1fe6b85c7eabc8f1868d9 100644 (file)
@@ -29,7 +29,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/acpi.h>
-#include <linux/dmi.h>
+#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -45,7 +45,7 @@ enum kinds { nct6683 };
 
 static bool force;
 module_param(force, bool, 0);
-MODULE_PARM_DESC(force, "Set to one to enable detection on non-Intel boards");
+MODULE_PARM_DESC(force, "Set to one to enable support for unknown vendors");
 
 static const char * const nct6683_device_names[] = {
        "nct6683",
@@ -141,6 +141,7 @@ superio_exit(int ioreg)
 #define NCT6683_REG_MON(x)             (0x100 + (x) * 2)
 #define NCT6683_REG_FAN_RPM(x)         (0x140 + (x) * 2)
 #define NCT6683_REG_PWM(x)             (0x160 + (x))
+#define NCT6683_REG_PWM_WRITE(x)       (0xa28 + (x))
 
 #define NCT6683_REG_MON_STS(x)         (0x174 + (x))
 #define NCT6683_REG_IDLE(x)            (0x178 + (x))
@@ -165,8 +166,13 @@ superio_exit(int ioreg)
 
 #define NCT6683_REG_FAN_MIN(x)         (0x3b8 + (x) * 2)       /* 16 bit */
 
+#define NCT6683_REG_FAN_CFG_CTRL       0xa01
+#define NCT6683_FAN_CFG_REQ            0x80
+#define NCT6683_FAN_CFG_DONE           0x40
+
 #define NCT6683_REG_CUSTOMER_ID                0x602
 #define NCT6683_CUSTOMER_ID_INTEL      0x805
+#define NCT6683_CUSTOMER_ID_MITAC      0xa0e
 
 #define NCT6683_REG_BUILD_YEAR         0x604
 #define NCT6683_REG_BUILD_MONTH                0x605
@@ -394,7 +400,8 @@ struct sensor_template_group {
 };
 
 static struct attribute_group *
-nct6683_create_attr_group(struct device *dev, struct sensor_template_group *tg,
+nct6683_create_attr_group(struct device *dev,
+                         const struct sensor_template_group *tg,
                          int repeat)
 {
        struct sensor_device_attribute_2 *a2;
@@ -559,6 +566,7 @@ static int get_temp_reg(struct nct6683_data *data, int nr, int index)
                        break;
                }
                break;
+       case NCT6683_CUSTOMER_ID_MITAC:
        default:
                switch (nr) {
                default:
@@ -703,7 +711,7 @@ static struct sensor_device_template *nct6683_attributes_in_template[] = {
        NULL
 };
 
-static struct sensor_template_group nct6683_in_template_group = {
+static const struct sensor_template_group nct6683_in_template_group = {
        .templates = nct6683_attributes_in_template,
        .is_visible = nct6683_in_is_visible,
 };
@@ -774,7 +782,7 @@ static struct sensor_device_template *nct6683_attributes_fan_template[] = {
        NULL
 };
 
-static struct sensor_template_group nct6683_fan_template_group = {
+static const struct sensor_template_group nct6683_fan_template_group = {
        .templates = nct6683_attributes_fan_template,
        .is_visible = nct6683_fan_is_visible,
        .base = 1,
@@ -902,7 +910,7 @@ static struct sensor_device_template *nct6683_attributes_temp_template[] = {
        NULL
 };
 
-static struct sensor_template_group nct6683_temp_template_group = {
+static const struct sensor_template_group nct6683_temp_template_group = {
        .templates = nct6683_attributes_temp_template,
        .is_visible = nct6683_temp_is_visible,
        .base = 1,
@@ -918,7 +926,29 @@ show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
        return sprintf(buf, "%d\n", data->pwm[index]);
 }
 
-SENSOR_TEMPLATE(pwm, "pwm%d", S_IRUGO, show_pwm, NULL, 0);
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
+         size_t count)
+{
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       struct nct6683_data *data = dev_get_drvdata(dev);
+       int index = sattr->index;
+       unsigned long val;
+
+       if (kstrtoul(buf, 10, &val) || val > 255)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+       nct6683_write(data, NCT6683_REG_FAN_CFG_CTRL, NCT6683_FAN_CFG_REQ);
+       usleep_range(1000, 2000);
+       nct6683_write(data, NCT6683_REG_PWM_WRITE(index), val);
+       nct6683_write(data, NCT6683_REG_FAN_CFG_CTRL, NCT6683_FAN_CFG_DONE);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+SENSOR_TEMPLATE(pwm, "pwm%d", S_IRUGO, show_pwm, store_pwm, 0);
 
 static umode_t nct6683_pwm_is_visible(struct kobject *kobj,
                                      struct attribute *attr, int index)
@@ -930,6 +960,10 @@ static umode_t nct6683_pwm_is_visible(struct kobject *kobj,
        if (!(data->have_pwm & (1 << pwm)))
                return 0;
 
+       /* Only update pwm values for Mitac boards */
+       if (data->customer_id == NCT6683_CUSTOMER_ID_MITAC)
+               return attr->mode | S_IWUSR;
+
        return attr->mode;
 }
 
@@ -938,7 +972,7 @@ static struct sensor_device_template *nct6683_attributes_pwm_template[] = {
        NULL
 };
 
-static struct sensor_template_group nct6683_pwm_template_group = {
+static const struct sensor_template_group nct6683_pwm_template_group = {
        .templates = nct6683_attributes_pwm_template,
        .is_visible = nct6683_pwm_is_visible,
        .base = 1,
@@ -1170,6 +1204,7 @@ static int nct6683_probe(struct platform_device *pdev)
        struct device *hwmon_dev;
        struct resource *res;
        int groups = 0;
+       char build[16];
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
        if (!devm_request_region(dev, res->start, IOREGION_LENGTH, DRVNAME))
@@ -1187,6 +1222,17 @@ static int nct6683_probe(struct platform_device *pdev)
 
        data->customer_id = nct6683_read16(data, NCT6683_REG_CUSTOMER_ID);
 
+       /* By default only instantiate driver if the customer ID is known */
+       switch (data->customer_id) {
+       case NCT6683_CUSTOMER_ID_INTEL:
+               break;
+       case NCT6683_CUSTOMER_ID_MITAC:
+               break;
+       default:
+               if (!force)
+                       return -ENODEV;
+       }
+
        nct6683_init_device(data);
        nct6683_setup_fans(data);
        nct6683_setup_sensors(data);
@@ -1230,13 +1276,22 @@ static int nct6683_probe(struct platform_device *pdev)
        }
        data->groups[groups++] = &nct6683_group_other;
 
-       dev_info(dev, "%s EC firmware version %d.%d build %02x/%02x/%02x\n",
+       if (data->customer_id == NCT6683_CUSTOMER_ID_INTEL)
+               scnprintf(build, sizeof(build), "%02x/%02x/%02x",
+                         nct6683_read(data, NCT6683_REG_BUILD_MONTH),
+                         nct6683_read(data, NCT6683_REG_BUILD_DAY),
+                         nct6683_read(data, NCT6683_REG_BUILD_YEAR));
+       else
+               scnprintf(build, sizeof(build), "%02d/%02d/%02d",
+                         nct6683_read(data, NCT6683_REG_BUILD_MONTH),
+                         nct6683_read(data, NCT6683_REG_BUILD_DAY),
+                         nct6683_read(data, NCT6683_REG_BUILD_YEAR));
+
+       dev_info(dev, "%s EC firmware version %d.%d build %s\n",
                 nct6683_chip_names[data->kind],
                 nct6683_read(data, NCT6683_REG_VERSION_HI),
                 nct6683_read(data, NCT6683_REG_VERSION_LO),
-                nct6683_read(data, NCT6683_REG_BUILD_MONTH),
-                nct6683_read(data, NCT6683_REG_BUILD_DAY),
-                nct6683_read(data, NCT6683_REG_BUILD_YEAR));
+                build);
 
        hwmon_dev = devm_hwmon_device_register_with_groups(dev,
                        nct6683_device_names[data->kind], data, data->groups);
@@ -1292,20 +1347,10 @@ static struct platform_driver nct6683_driver = {
 
 static int __init nct6683_find(int sioaddr, struct nct6683_sio_data *sio_data)
 {
-       const char *board_vendor;
        int addr;
        u16 val;
        int err;
 
-       /*
-        * Only run on Intel boards unless the 'force' module parameter is set
-        */
-       if (!force) {
-               board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
-               if (!board_vendor || strcmp(board_vendor, "Intel Corporation"))
-                       return -ENODEV;
-       }
-
        err = superio_enter(sioaddr);
        if (err)
                return err;
index d7ebdf8651f5f57fe598197b1e0620754d1dcc55..d087a8e00cf51abede39cc653341365a841b28d3 100644 (file)
@@ -1045,7 +1045,8 @@ struct sensor_template_group {
 };
 
 static struct attribute_group *
-nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg,
+nct6775_create_attr_group(struct device *dev,
+                         const struct sensor_template_group *tg,
                          int repeat)
 {
        struct attribute_group *group;
@@ -1827,7 +1828,7 @@ static struct sensor_device_template *nct6775_attributes_in_template[] = {
        NULL
 };
 
-static struct sensor_template_group nct6775_in_template_group = {
+static const struct sensor_template_group nct6775_in_template_group = {
        .templates = nct6775_attributes_in_template,
        .is_visible = nct6775_in_is_visible,
 };
@@ -2046,7 +2047,7 @@ static struct sensor_device_template *nct6775_attributes_fan_template[] = {
        NULL
 };
 
-static struct sensor_template_group nct6775_fan_template_group = {
+static const struct sensor_template_group nct6775_fan_template_group = {
        .templates = nct6775_attributes_fan_template,
        .is_visible = nct6775_fan_is_visible,
        .base = 1,
@@ -2255,7 +2256,7 @@ static struct sensor_device_template *nct6775_attributes_temp_template[] = {
        NULL
 };
 
-static struct sensor_template_group nct6775_temp_template_group = {
+static const struct sensor_template_group nct6775_temp_template_group = {
        .templates = nct6775_attributes_temp_template,
        .is_visible = nct6775_temp_is_visible,
        .base = 1,
@@ -3117,7 +3118,7 @@ static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
        NULL
 };
 
-static struct sensor_template_group nct6775_pwm_template_group = {
+static const struct sensor_template_group nct6775_pwm_template_group = {
        .templates = nct6775_attributes_pwm_template,
        .is_visible = nct6775_pwm_is_visible,
        .base = 1,
index df6ebb2b8f0f94e3eb82ccdb6b380674f50d3b20..7e5cc3d025efece94357d369837d4806551e3d83 100644 (file)
@@ -65,6 +65,16 @@ config SENSORS_LTC2978_REGULATOR
          If you say yes here you get regulator support for Linear
          Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, and LTM4676.
 
+config SENSORS_LTC3815
+       tristate "Linear Technologies LTC3815"
+       default n
+       help
+         If you say yes here you get hardware monitoring support for Linear
+         Technology LTC3815.
+
+         This driver can also be built as a module. If so, the module will
+         be called ltc3815.
+
 config SENSORS_MAX16064
        tristate "Maxim MAX16064"
        default n
index bce046d37f0264eff48a44010ceb1cd8994f65d1..562132054aafe9e7d5154ab582ec6080f84a19a2 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_SENSORS_PMBUS)     += pmbus.o
 obj-$(CONFIG_SENSORS_ADM1275)  += adm1275.o
 obj-$(CONFIG_SENSORS_LM25066)  += lm25066.o
 obj-$(CONFIG_SENSORS_LTC2978)  += ltc2978.o
+obj-$(CONFIG_SENSORS_LTC3815)  += ltc3815.o
 obj-$(CONFIG_SENSORS_MAX16064) += max16064.o
 obj-$(CONFIG_SENSORS_MAX20751) += max20751.o
 obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
diff --git a/drivers/hwmon/pmbus/ltc3815.c b/drivers/hwmon/pmbus/ltc3815.c
new file mode 100644 (file)
index 0000000..bb32e62
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * Hardware monitoring driver for LTC3815
+ *
+ * Copyright (c) 2015 Linear Technology
+ * Copyright (c) 2015 Guenter Roeck
+ *
+ * This program is 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/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include "pmbus.h"
+
+#define LTC3815_MFR_IOUT_PEAK  0xd7
+#define LTC3815_MFR_VOUT_PEAK  0xdd
+#define LTC3815_MFR_VIN_PEAK   0xde
+#define LTC3815_MFR_TEMP_PEAK  0xdf
+#define LTC3815_MFR_IIN_PEAK   0xe1
+#define LTC3815_MFR_SPECIAL_ID 0xe7
+
+#define LTC3815_ID             0x8000
+#define LTC3815_ID_MASK                0xff00
+
+static int ltc3815_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VOUT_MODE:
+               /*
+                * The chip returns 0x3e, suggesting VID mode with manufacturer
+                * specific VID codes. Since the output voltage is reported
+                * with a LSB of 0.5mV, override and report direct mode with
+                * appropriate coefficients.
+                */
+               ret = 0x40;
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static int ltc3815_write_byte(struct i2c_client *client, int page, u8 reg)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_CLEAR_FAULTS:
+               /*
+                * LTC3815 does not support the CLEAR_FAULTS command.
+                * Emulate it by clearing the status register.
+                */
+               ret = pmbus_read_word_data(client, 0, PMBUS_STATUS_WORD);
+               if (ret > 0) {
+                       pmbus_write_word_data(client, 0, PMBUS_STATUS_WORD,
+                                             ret);
+                       ret = 0;
+               }
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static int ltc3815_read_word_data(struct i2c_client *client, int page, int reg)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_READ_VIN_MAX:
+               ret = pmbus_read_word_data(client, page, LTC3815_MFR_VIN_PEAK);
+               break;
+       case PMBUS_VIRT_READ_VOUT_MAX:
+               ret = pmbus_read_word_data(client, page, LTC3815_MFR_VOUT_PEAK);
+               break;
+       case PMBUS_VIRT_READ_TEMP_MAX:
+               ret = pmbus_read_word_data(client, page, LTC3815_MFR_TEMP_PEAK);
+               break;
+       case PMBUS_VIRT_READ_IOUT_MAX:
+               ret = pmbus_read_word_data(client, page, LTC3815_MFR_IOUT_PEAK);
+               break;
+       case PMBUS_VIRT_READ_IIN_MAX:
+               ret = pmbus_read_word_data(client, page, LTC3815_MFR_IIN_PEAK);
+               break;
+       case PMBUS_VIRT_RESET_VOUT_HISTORY:
+       case PMBUS_VIRT_RESET_VIN_HISTORY:
+       case PMBUS_VIRT_RESET_TEMP_HISTORY:
+       case PMBUS_VIRT_RESET_IOUT_HISTORY:
+       case PMBUS_VIRT_RESET_IIN_HISTORY:
+               ret = 0;
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static int ltc3815_write_word_data(struct i2c_client *client, int page,
+                                  int reg, u16 word)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_RESET_IIN_HISTORY:
+               ret = pmbus_write_word_data(client, page,
+                                           LTC3815_MFR_IIN_PEAK, 0);
+               break;
+       case PMBUS_VIRT_RESET_IOUT_HISTORY:
+               ret = pmbus_write_word_data(client, page,
+                                           LTC3815_MFR_IOUT_PEAK, 0);
+               break;
+       case PMBUS_VIRT_RESET_VOUT_HISTORY:
+               ret = pmbus_write_word_data(client, page,
+                                           LTC3815_MFR_VOUT_PEAK, 0);
+               break;
+       case PMBUS_VIRT_RESET_VIN_HISTORY:
+               ret = pmbus_write_word_data(client, page,
+                                           LTC3815_MFR_VIN_PEAK, 0);
+               break;
+       case PMBUS_VIRT_RESET_TEMP_HISTORY:
+               ret = pmbus_write_word_data(client, page,
+                                           LTC3815_MFR_TEMP_PEAK, 0);
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static const struct i2c_device_id ltc3815_id[] = {
+       {"ltc3815", 0},
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ltc3815_id);
+
+static struct pmbus_driver_info ltc3815_info = {
+       .pages = 1,
+       .format[PSC_VOLTAGE_IN] = direct,
+       .format[PSC_VOLTAGE_OUT] = direct,
+       .format[PSC_CURRENT_IN] = direct,
+       .format[PSC_CURRENT_OUT] = direct,
+       .format[PSC_TEMPERATURE] = direct,
+       .m[PSC_VOLTAGE_IN] = 250,
+       .b[PSC_VOLTAGE_IN] = 0,
+       .R[PSC_VOLTAGE_IN] = 0,
+       .m[PSC_VOLTAGE_OUT] = 2,
+       .b[PSC_VOLTAGE_OUT] = 0,
+       .R[PSC_VOLTAGE_OUT] = 3,
+       .m[PSC_CURRENT_IN] = 1,
+       .b[PSC_CURRENT_IN] = 0,
+       .R[PSC_CURRENT_IN] = 2,
+       .m[PSC_CURRENT_OUT] = 1,
+       .b[PSC_CURRENT_OUT] = 0,
+       .R[PSC_CURRENT_OUT] = 2,
+       .m[PSC_TEMPERATURE] = 1,
+       .b[PSC_TEMPERATURE] = 0,
+       .R[PSC_TEMPERATURE] = 0,
+       .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_VOUT |
+               PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP,
+       .read_byte_data = ltc3815_read_byte_data,
+       .read_word_data = ltc3815_read_word_data,
+       .write_byte = ltc3815_write_byte,
+       .write_word_data = ltc3815_write_word_data,
+};
+
+static int ltc3815_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       int chip_id;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_READ_WORD_DATA))
+               return -ENODEV;
+
+       chip_id = i2c_smbus_read_word_data(client, LTC3815_MFR_SPECIAL_ID);
+       if (chip_id < 0)
+               return chip_id;
+       if ((chip_id & LTC3815_ID_MASK) != LTC3815_ID)
+               return -ENODEV;
+
+       return pmbus_do_probe(client, id, &ltc3815_info);
+}
+
+static struct i2c_driver ltc3815_driver = {
+       .driver = {
+                  .name = "ltc3815",
+                  },
+       .probe = ltc3815_probe,
+       .remove = pmbus_do_remove,
+       .id_table = ltc3815_id,
+};
+
+module_i2c_driver(ltc3815_driver);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for LTC3815");
+MODULE_LICENSE("GPL");
index d2d5d004f16dbb11fc4a57b5ce47004da567a137..2d762a2ecd81252cde34cbc2dbc1083c1d8832dc 100644 (file)
@@ -1265,15 +1265,17 @@ static bool cma_protocol_roce(const struct rdma_cm_id *id)
        return cma_protocol_roce_dev_port(device, port_num);
 }
 
-static bool cma_match_net_dev(const struct rdma_id_private *id_priv,
-                             const struct net_device *net_dev)
+static bool cma_match_net_dev(const struct rdma_cm_id *id,
+                             const struct net_device *net_dev,
+                             u8 port_num)
 {
-       const struct rdma_addr *addr = &id_priv->id.route.addr;
+       const struct rdma_addr *addr = &id->route.addr;
 
        if (!net_dev)
                /* This request is an AF_IB request or a RoCE request */
-               return addr->src_addr.ss_family == AF_IB ||
-                      cma_protocol_roce(&id_priv->id);
+               return (!id->port_num || id->port_num == port_num) &&
+                      (addr->src_addr.ss_family == AF_IB ||
+                       cma_protocol_roce_dev_port(id->device, port_num));
 
        return !addr->dev_addr.bound_dev_if ||
               (net_eq(dev_net(net_dev), addr->dev_addr.net) &&
@@ -1295,13 +1297,13 @@ static struct rdma_id_private *cma_find_listener(
        hlist_for_each_entry(id_priv, &bind_list->owners, node) {
                if (cma_match_private_data(id_priv, ib_event->private_data)) {
                        if (id_priv->id.device == cm_id->device &&
-                           cma_match_net_dev(id_priv, net_dev))
+                           cma_match_net_dev(&id_priv->id, net_dev, req->port))
                                return id_priv;
                        list_for_each_entry(id_priv_dev,
                                            &id_priv->listen_list,
                                            listen_list) {
                                if (id_priv_dev->id.device == cm_id->device &&
-                                   cma_match_net_dev(id_priv_dev, net_dev))
+                                   cma_match_net_dev(&id_priv_dev->id, net_dev, req->port))
                                        return id_priv_dev;
                        }
                }
index 8d133c40fa0e56c658eb096c11971073b846574a..c394376ebe06f159aebca07ef899ef5933386713 100644 (file)
@@ -286,7 +286,7 @@ int mlx4_ib_destroy_srq(struct ib_srq *srq)
                mlx4_ib_db_unmap_user(to_mucontext(srq->uobject->context), &msrq->db);
                ib_umem_release(msrq->umem);
        } else {
-               kfree(msrq->wrid);
+               kvfree(msrq->wrid);
                mlx4_buf_free(dev->dev, msrq->msrq.max << msrq->msrq.wqe_shift,
                              &msrq->buf);
                mlx4_db_free(dev->dev, &msrq->db);
index ae80590aabdf7db6df756c0ee07afa4721f6c37c..040bb8b5cb15a65c34b15ab67c3c5fe14e27524c 100644 (file)
@@ -232,6 +232,10 @@ struct phy_info {
        u16 interface_type;
 };
 
+enum ocrdma_flags {
+       OCRDMA_FLAGS_LINK_STATUS_INIT = 0x01
+};
+
 struct ocrdma_dev {
        struct ib_device ibdev;
        struct ocrdma_dev_attr attr;
@@ -287,6 +291,7 @@ struct ocrdma_dev {
        atomic_t update_sl;
        u16 pvid;
        u32 asic_id;
+       u32 flags;
 
        ulong last_stats_time;
        struct mutex stats_lock; /* provide synch for debugfs operations */
@@ -591,4 +596,9 @@ static inline u8 ocrdma_is_enabled_and_synced(u32 state)
                (state & OCRDMA_STATE_FLAG_SYNC);
 }
 
+static inline u8 ocrdma_get_ae_link_state(u32 ae_state)
+{
+       return ((ae_state & OCRDMA_AE_LSC_LS_MASK) >> OCRDMA_AE_LSC_LS_SHIFT);
+}
+
 #endif
index 30f67bebffa35742189c4fc08b91654f75bfdcfa..283ca842ff7498b308fcec85a1268dcb452d56b0 100644 (file)
@@ -579,6 +579,8 @@ static int ocrdma_mbx_create_mq(struct ocrdma_dev *dev,
 
        cmd->async_event_bitmap = BIT(OCRDMA_ASYNC_GRP5_EVE_CODE);
        cmd->async_event_bitmap |= BIT(OCRDMA_ASYNC_RDMA_EVE_CODE);
+       /* Request link events on this  MQ. */
+       cmd->async_event_bitmap |= BIT(OCRDMA_ASYNC_LINK_EVE_CODE);
 
        cmd->async_cqid_ringsize = cq->id;
        cmd->async_cqid_ringsize |= (ocrdma_encoded_q_len(mq->len) <<
@@ -819,20 +821,42 @@ static void ocrdma_process_grp5_aync(struct ocrdma_dev *dev,
        }
 }
 
+static void ocrdma_process_link_state(struct ocrdma_dev *dev,
+                                     struct ocrdma_ae_mcqe *cqe)
+{
+       struct ocrdma_ae_lnkst_mcqe *evt;
+       u8 lstate;
+
+       evt = (struct ocrdma_ae_lnkst_mcqe *)cqe;
+       lstate = ocrdma_get_ae_link_state(evt->speed_state_ptn);
+
+       if (!(lstate & OCRDMA_AE_LSC_LLINK_MASK))
+               return;
+
+       if (dev->flags & OCRDMA_FLAGS_LINK_STATUS_INIT)
+               ocrdma_update_link_state(dev, (lstate & OCRDMA_LINK_ST_MASK));
+}
+
 static void ocrdma_process_acqe(struct ocrdma_dev *dev, void *ae_cqe)
 {
        /* async CQE processing */
        struct ocrdma_ae_mcqe *cqe = ae_cqe;
        u32 evt_code = (cqe->valid_ae_event & OCRDMA_AE_MCQE_EVENT_CODE_MASK) >>
                        OCRDMA_AE_MCQE_EVENT_CODE_SHIFT;
-
-       if (evt_code == OCRDMA_ASYNC_RDMA_EVE_CODE)
+       switch (evt_code) {
+       case OCRDMA_ASYNC_LINK_EVE_CODE:
+               ocrdma_process_link_state(dev, cqe);
+               break;
+       case OCRDMA_ASYNC_RDMA_EVE_CODE:
                ocrdma_dispatch_ibevent(dev, cqe);
-       else if (evt_code == OCRDMA_ASYNC_GRP5_EVE_CODE)
+               break;
+       case OCRDMA_ASYNC_GRP5_EVE_CODE:
                ocrdma_process_grp5_aync(dev, cqe);
-       else
+               break;
+       default:
                pr_err("%s(%d) invalid evt code=0x%x\n", __func__,
                       dev->id, evt_code);
+       }
 }
 
 static void ocrdma_process_mcqe(struct ocrdma_dev *dev, struct ocrdma_mcqe *cqe)
@@ -1363,7 +1387,8 @@ mbx_err:
        return status;
 }
 
-int ocrdma_mbx_get_link_speed(struct ocrdma_dev *dev, u8 *lnk_speed)
+int ocrdma_mbx_get_link_speed(struct ocrdma_dev *dev, u8 *lnk_speed,
+                             u8 *lnk_state)
 {
        int status = -ENOMEM;
        struct ocrdma_get_link_speed_rsp *rsp;
@@ -1384,8 +1409,11 @@ int ocrdma_mbx_get_link_speed(struct ocrdma_dev *dev, u8 *lnk_speed)
                goto mbx_err;
 
        rsp = (struct ocrdma_get_link_speed_rsp *)cmd;
-       *lnk_speed = (rsp->pflt_pps_ld_pnum & OCRDMA_PHY_PS_MASK)
-                       >> OCRDMA_PHY_PS_SHIFT;
+       if (lnk_speed)
+               *lnk_speed = (rsp->pflt_pps_ld_pnum & OCRDMA_PHY_PS_MASK)
+                             >> OCRDMA_PHY_PS_SHIFT;
+       if (lnk_state)
+               *lnk_state = (rsp->res_lnk_st & OCRDMA_LINK_ST_MASK);
 
 mbx_err:
        kfree(cmd);
@@ -2515,9 +2543,10 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
        ocrdma_cpu_to_le32(&cmd->params.sgid[0], sizeof(cmd->params.sgid));
        cmd->params.vlan_dmac_b4_to_b5 = mac_addr[4] | (mac_addr[5] << 8);
 
-       if (vlan_id < 0x1000) {
-               if (dev->pfc_state) {
-                       vlan_id = 0;
+       if (vlan_id == 0xFFFF)
+               vlan_id = 0;
+       if (vlan_id || dev->pfc_state) {
+               if (!vlan_id) {
                        pr_err("ocrdma%d:Using VLAN with PFC is recommended\n",
                               dev->id);
                        pr_err("ocrdma%d:Using VLAN 0 for this connection\n",
index 7ed885c1851e28740b81a0588493c0d0ca92bc42..ebc1f442aec37aabd691d374deb3fdd41acc4302 100644 (file)
@@ -106,7 +106,8 @@ void ocrdma_ring_cq_db(struct ocrdma_dev *, u16 cq_id, bool armed,
                       bool solicited, u16 cqe_popped);
 
 /* verbs specific mailbox commands */
-int ocrdma_mbx_get_link_speed(struct ocrdma_dev *dev, u8 *lnk_speed);
+int ocrdma_mbx_get_link_speed(struct ocrdma_dev *dev, u8 *lnk_speed,
+                             u8 *lnk_st);
 int ocrdma_query_config(struct ocrdma_dev *,
                        struct ocrdma_mbx_query_config *config);
 
@@ -153,5 +154,6 @@ char *port_speed_string(struct ocrdma_dev *dev);
 void ocrdma_init_service_level(struct ocrdma_dev *);
 void ocrdma_alloc_pd_pool(struct ocrdma_dev *dev);
 void ocrdma_free_pd_range(struct ocrdma_dev *dev);
+void ocrdma_update_link_state(struct ocrdma_dev *dev, u8 lstate);
 
 #endif                         /* __OCRDMA_HW_H__ */
index 62b7009daa6c18a4d21002636637b5a2d258b231..3afb40b85159bd2c10559443536f83af5e4fa9ca 100644 (file)
@@ -290,6 +290,7 @@ static void ocrdma_remove_sysfiles(struct ocrdma_dev *dev)
 static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
 {
        int status = 0, i;
+       u8 lstate = 0;
        struct ocrdma_dev *dev;
 
        dev = (struct ocrdma_dev *)ib_alloc_device(sizeof(struct ocrdma_dev));
@@ -319,6 +320,11 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
        if (status)
                goto alloc_err;
 
+       /* Query Link state and update */
+       status = ocrdma_mbx_get_link_speed(dev, NULL, &lstate);
+       if (!status)
+               ocrdma_update_link_state(dev, lstate);
+
        for (i = 0; i < ARRAY_SIZE(ocrdma_attributes); i++)
                if (device_create_file(&dev->ibdev.dev, ocrdma_attributes[i]))
                        goto sysfs_err;
@@ -373,7 +379,7 @@ static void ocrdma_remove(struct ocrdma_dev *dev)
        ocrdma_remove_free(dev);
 }
 
-static int ocrdma_open(struct ocrdma_dev *dev)
+static int ocrdma_dispatch_port_active(struct ocrdma_dev *dev)
 {
        struct ib_event port_event;
 
@@ -384,32 +390,9 @@ static int ocrdma_open(struct ocrdma_dev *dev)
        return 0;
 }
 
-static int ocrdma_close(struct ocrdma_dev *dev)
+static int ocrdma_dispatch_port_error(struct ocrdma_dev *dev)
 {
-       int i;
-       struct ocrdma_qp *qp, **cur_qp;
        struct ib_event err_event;
-       struct ib_qp_attr attrs;
-       int attr_mask = IB_QP_STATE;
-
-       attrs.qp_state = IB_QPS_ERR;
-       mutex_lock(&dev->dev_lock);
-       if (dev->qp_tbl) {
-               cur_qp = dev->qp_tbl;
-               for (i = 0; i < OCRDMA_MAX_QP; i++) {
-                       qp = cur_qp[i];
-                       if (qp && qp->ibqp.qp_type != IB_QPT_GSI) {
-                               /* change the QP state to ERROR */
-                               _ocrdma_modify_qp(&qp->ibqp, &attrs, attr_mask);
-
-                               err_event.event = IB_EVENT_QP_FATAL;
-                               err_event.element.qp = &qp->ibqp;
-                               err_event.device = &dev->ibdev;
-                               ib_dispatch_event(&err_event);
-                       }
-               }
-       }
-       mutex_unlock(&dev->dev_lock);
 
        err_event.event = IB_EVENT_PORT_ERR;
        err_event.element.port_num = 1;
@@ -420,7 +403,7 @@ static int ocrdma_close(struct ocrdma_dev *dev)
 
 static void ocrdma_shutdown(struct ocrdma_dev *dev)
 {
-       ocrdma_close(dev);
+       ocrdma_dispatch_port_error(dev);
        ocrdma_remove(dev);
 }
 
@@ -431,18 +414,28 @@ static void ocrdma_shutdown(struct ocrdma_dev *dev)
 static void ocrdma_event_handler(struct ocrdma_dev *dev, u32 event)
 {
        switch (event) {
-       case BE_DEV_UP:
-               ocrdma_open(dev);
-               break;
-       case BE_DEV_DOWN:
-               ocrdma_close(dev);
-               break;
        case BE_DEV_SHUTDOWN:
                ocrdma_shutdown(dev);
                break;
+       default:
+               break;
        }
 }
 
+void ocrdma_update_link_state(struct ocrdma_dev *dev, u8 lstate)
+{
+       if (!(dev->flags & OCRDMA_FLAGS_LINK_STATUS_INIT)) {
+               dev->flags |= OCRDMA_FLAGS_LINK_STATUS_INIT;
+               if (!lstate)
+                       return;
+       }
+
+       if (!lstate)
+               ocrdma_dispatch_port_error(dev);
+       else
+               ocrdma_dispatch_port_active(dev);
+}
+
 static struct ocrdma_driver ocrdma_drv = {
        .name                   = "ocrdma_driver",
        .add                    = ocrdma_add,
index 6a38268bbe9fb6b981e27f2ec42da8fd10adbfc2..99dd6fdf06d7b44bcea2f0fb28b90edf54aefcc0 100644 (file)
@@ -465,8 +465,11 @@ struct ocrdma_ae_qp_mcqe {
        u32 valid_ae_event;
 };
 
-#define OCRDMA_ASYNC_RDMA_EVE_CODE 0x14
-#define OCRDMA_ASYNC_GRP5_EVE_CODE 0x5
+enum ocrdma_async_event_code {
+       OCRDMA_ASYNC_LINK_EVE_CODE      = 0x01,
+       OCRDMA_ASYNC_GRP5_EVE_CODE      = 0x05,
+       OCRDMA_ASYNC_RDMA_EVE_CODE      = 0x14
+};
 
 enum ocrdma_async_grp5_events {
        OCRDMA_ASYNC_EVENT_QOS_VALUE    = 0x01,
@@ -489,6 +492,44 @@ enum OCRDMA_ASYNC_EVENT_TYPE {
        OCRDMA_MAX_ASYNC_ERRORS
 };
 
+struct ocrdma_ae_lnkst_mcqe {
+       u32 speed_state_ptn;
+       u32 qos_reason_falut;
+       u32 evt_tag;
+       u32 valid_ae_event;
+};
+
+enum {
+       OCRDMA_AE_LSC_PORT_NUM_MASK     = 0x3F,
+       OCRDMA_AE_LSC_PT_SHIFT          = 0x06,
+       OCRDMA_AE_LSC_PT_MASK           = (0x03 <<
+                       OCRDMA_AE_LSC_PT_SHIFT),
+       OCRDMA_AE_LSC_LS_SHIFT          = 0x08,
+       OCRDMA_AE_LSC_LS_MASK           = (0xFF <<
+                       OCRDMA_AE_LSC_LS_SHIFT),
+       OCRDMA_AE_LSC_LD_SHIFT          = 0x10,
+       OCRDMA_AE_LSC_LD_MASK           = (0xFF <<
+                       OCRDMA_AE_LSC_LD_SHIFT),
+       OCRDMA_AE_LSC_PPS_SHIFT         = 0x18,
+       OCRDMA_AE_LSC_PPS_MASK          = (0xFF <<
+                       OCRDMA_AE_LSC_PPS_SHIFT),
+       OCRDMA_AE_LSC_PPF_MASK          = 0xFF,
+       OCRDMA_AE_LSC_ER_SHIFT          = 0x08,
+       OCRDMA_AE_LSC_ER_MASK           = (0xFF <<
+                       OCRDMA_AE_LSC_ER_SHIFT),
+       OCRDMA_AE_LSC_QOS_SHIFT         = 0x10,
+       OCRDMA_AE_LSC_QOS_MASK          = (0xFFFF <<
+                       OCRDMA_AE_LSC_QOS_SHIFT)
+};
+
+enum {
+       OCRDMA_AE_LSC_PLINK_DOWN        = 0x00,
+       OCRDMA_AE_LSC_PLINK_UP          = 0x01,
+       OCRDMA_AE_LSC_LLINK_DOWN        = 0x02,
+       OCRDMA_AE_LSC_LLINK_MASK        = 0x02,
+       OCRDMA_AE_LSC_LLINK_UP          = 0x03
+};
+
 /* mailbox command request and responses */
 enum {
        OCRDMA_MBX_QUERY_CFG_CQ_OVERFLOW_SHIFT          = 2,
@@ -676,7 +717,7 @@ enum {
        OCRDMA_PHY_PFLT_SHIFT   = 0x18,
        OCRDMA_QOS_LNKSP_MASK   = 0xFFFF0000,
        OCRDMA_QOS_LNKSP_SHIFT  = 0x10,
-       OCRDMA_LLST_MASK        = 0xFF,
+       OCRDMA_LINK_ST_MASK     = 0x01,
        OCRDMA_PLFC_MASK        = 0x00000400,
        OCRDMA_PLFC_SHIFT       = 0x8,
        OCRDMA_PLRFC_MASK       = 0x00000200,
@@ -691,7 +732,7 @@ struct ocrdma_get_link_speed_rsp {
 
        u32 pflt_pps_ld_pnum;
        u32 qos_lsp;
-       u32 res_lls;
+       u32 res_lnk_st;
 };
 
 enum {
index 583001bcfb8fc8c10a1e088b451d7de12adc2aa8..76e96f97b3f6459e68d13c444be6e1beb6b578a9 100644 (file)
@@ -171,7 +171,7 @@ static inline void get_link_speed_and_width(struct ocrdma_dev *dev,
        int status;
        u8 speed;
 
-       status = ocrdma_mbx_get_link_speed(dev, &speed);
+       status = ocrdma_mbx_get_link_speed(dev, &speed, NULL);
        if (status)
                speed = OCRDMA_PHYS_LINK_SPEED_ZERO;
 
index d214f22ed305aab0773fe783c2e692c62fc342eb..b6c4d03de3408cc951d6c6ed03cd775f14f3f198 100644 (file)
@@ -444,7 +444,7 @@ static void sur40_process_video(struct sur40_state *sur40)
                goto err_poll;
 
        /* mark as finished */
-       v4l2_get_timestamp(&new_buf->vb.timestamp);
+       new_buf->vb.vb2_buf.timestamp = ktime_get_ns();
        new_buf->vb.sequence = sur40->sequence++;
        new_buf->vb.field = V4L2_FIELD_NONE;
        vb2_buffer_done(&new_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
@@ -644,22 +644,21 @@ static void sur40_disconnect(struct usb_interface *interface)
  * minimum number: many DMA engines need a minimum of 2 buffers in the
  * queue and you need to have another available for userspace processing.
  */
-static int sur40_queue_setup(struct vb2_queue *q, const void *parg,
+static int sur40_queue_setup(struct vb2_queue *q,
                       unsigned int *nbuffers, unsigned int *nplanes,
                       unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct sur40_state *sur40 = vb2_get_drv_priv(q);
 
        if (q->num_buffers + *nbuffers < 3)
                *nbuffers = 3 - q->num_buffers;
+       alloc_ctxs[0] = sur40->alloc_ctx;
 
-       if (fmt && fmt->fmt.pix.sizeimage < sur40_video_format.sizeimage)
-               return -EINVAL;
+       if (*nplanes)
+               return sizes[0] < sur40_video_format.sizeimage ? -EINVAL : 0;
 
        *nplanes = 1;
-       sizes[0] = fmt ? fmt->fmt.pix.sizeimage : sur40_video_format.sizeimage;
-       alloc_ctxs[0] = sur40->alloc_ctx;
+       sizes[0] = sur40_video_format.sizeimage;
 
        return 0;
 }
index 3a20db4f8604f77d7bd374c9b9278f65a8c2cb5c..72d6182666cbd24ba785fc59572c655b6f0c2c8f 100644 (file)
 
 #include <linux/device.h>
 #include <linux/dma-iommu.h>
+#include <linux/gfp.h>
 #include <linux/huge_mm.h>
 #include <linux/iommu.h>
 #include <linux/iova.h>
 #include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/vmalloc.h>
 
 int iommu_dma_init(void)
 {
@@ -191,6 +194,7 @@ static struct page **__iommu_dma_alloc_pages(unsigned int count, gfp_t gfp)
 {
        struct page **pages;
        unsigned int i = 0, array_size = count * sizeof(*pages);
+       unsigned int order = MAX_ORDER;
 
        if (array_size <= PAGE_SIZE)
                pages = kzalloc(array_size, GFP_KERNEL);
@@ -204,14 +208,15 @@ static struct page **__iommu_dma_alloc_pages(unsigned int count, gfp_t gfp)
 
        while (count) {
                struct page *page = NULL;
-               int j, order = __fls(count);
+               int j;
 
                /*
                 * Higher-order allocations are a convenience rather
                 * than a necessity, hence using __GFP_NORETRY until
                 * falling back to single-page allocations.
                 */
-               for (order = min(order, MAX_ORDER); order > 0; order--) {
+               for (order = min_t(unsigned int, order, __fls(count));
+                    order > 0; order--) {
                        page = alloc_pages(gfp | __GFP_NORETRY, order);
                        if (!page)
                                continue;
@@ -453,7 +458,7 @@ int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg,
                size_t s_offset = iova_offset(iovad, s->offset);
                size_t s_length = s->length;
 
-               sg_dma_address(s) = s->offset;
+               sg_dma_address(s) = s_offset;
                sg_dma_len(s) = s_length;
                s->offset -= s_offset;
                s_length = iova_align(iovad, s_length + s_offset);
index 1fae1881648c5a87e9071d1dc9ade123baab0252..c12ba4516df25b7201731b44ef4a175c78f2d0e0 100644 (file)
@@ -753,7 +753,7 @@ static inline void set_irq_posting_cap(void)
                 * should have X86_FEATURE_CX16 support, this has been confirmed
                 * with Intel hardware guys.
                 */
-               if ( cpu_has_cx16 )
+               if (boot_cpu_has(X86_FEATURE_CX16))
                        intel_irq_remap_ops.capability |= 1 << IRQ_POSTING_CAP;
 
                for_each_iommu(iommu, drhd)
index 8cf605fa9946013642b2a88f500beb285cc55cfc..dfb868e2d129005d7a7401cea7c6109e7720559d 100644 (file)
@@ -295,7 +295,7 @@ static struct iommu_gather_ops ipmmu_gather_ops = {
 
 static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain)
 {
-       phys_addr_t ttbr;
+       u64 ttbr;
 
        /*
         * Allocate the page table operations.
index 4d7294e5d98271493e0ef6d2d90d10108178c83f..11fc2a27fa2ea90da2b65ef282a5db139c594c71 100644 (file)
@@ -8,6 +8,11 @@ config ARM_GIC
        select IRQ_DOMAIN_HIERARCHY
        select MULTI_IRQ_HANDLER
 
+config ARM_GIC_MAX_NR
+       int
+       default 2 if ARCH_REALVIEW
+       default 1
+
 config ARM_GIC_V2M
        bool
        depends on ARM_GIC
@@ -27,6 +32,14 @@ config ARM_GIC_V3_ITS
        bool
        select PCI_MSI_IRQ_DOMAIN
 
+config HISILICON_IRQ_MBIGEN
+       bool "Support mbigen interrupt controller"
+       default n
+       depends on ARM_GIC_V3 && ARM_GIC_V3_ITS && GENERIC_MSI_IRQ_DOMAIN
+       help
+        Enable the mbigen interrupt controller used on
+        Hisilicon platform.
+
 config ARM_NVIC
        bool
        select IRQ_DOMAIN
@@ -138,6 +151,12 @@ config TB10X_IRQC
        select IRQ_DOMAIN
        select GENERIC_IRQ_CHIP
 
+config TS4800_IRQ
+       tristate "TS-4800 IRQ controller"
+       select IRQ_DOMAIN
+       help
+         Support for the TS-4800 FPGA IRQ controller
+
 config VERSATILE_FPGA_IRQ
        bool
        select IRQ_DOMAIN
index 177f78f6e6d6313fd9fd16595fe36089296ce25f..d4c2e4ebc30809fcb21b9f705f416e9c8dbb7ee3 100644 (file)
@@ -21,9 +21,11 @@ obj-$(CONFIG_ARCH_SUNXI)             += irq-sun4i.o
 obj-$(CONFIG_ARCH_SUNXI)               += irq-sunxi-nmi.o
 obj-$(CONFIG_ARCH_SPEAR3XX)            += spear-shirq.o
 obj-$(CONFIG_ARM_GIC)                  += irq-gic.o irq-gic-common.o
+obj-$(CONFIG_REALVIEW_DT)              += irq-gic-realview.o
 obj-$(CONFIG_ARM_GIC_V2M)              += irq-gic-v2m.o
 obj-$(CONFIG_ARM_GIC_V3)               += irq-gic-v3.o irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V3_ITS)           += irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
+obj-$(CONFIG_HISILICON_IRQ_MBIGEN)     += irq-mbigen.o
 obj-$(CONFIG_ARM_NVIC)                 += irq-nvic.o
 obj-$(CONFIG_ARM_VIC)                  += irq-vic.o
 obj-$(CONFIG_ATMEL_AIC_IRQ)            += irq-atmel-aic-common.o irq-atmel-aic.o
@@ -39,6 +41,7 @@ obj-$(CONFIG_ARCH_NSPIRE)             += irq-zevio.o
 obj-$(CONFIG_ARCH_VT8500)              += irq-vt8500.o
 obj-$(CONFIG_ST_IRQCHIP)               += irq-st.o
 obj-$(CONFIG_TB10X_IRQC)               += irq-tb10x.o
+obj-$(CONFIG_TS4800_IRQ)               += irq-ts4800.o
 obj-$(CONFIG_XTENSA)                   += irq-xtensa-pic.o
 obj-$(CONFIG_XTENSA_MX)                        += irq-xtensa-mx.o
 obj-$(CONFIG_IRQ_CROSSBAR)             += irq-crossbar.o
index f68708281fcf4a821071f6d84246e34b016db4c5..963065a0d774149da62a5a1d5cac9152bfa9e696 100644 (file)
@@ -21,6 +21,9 @@
 #include <linux/irqdomain.h>
 #include <asm/exception.h>
 
+#define LOCAL_CONTROL                  0x000
+#define LOCAL_PRESCALER                        0x008
+
 /*
  * The low 2 bits identify the CPU that the GPU IRQ goes to, and the
  * next 2 bits identify the CPU that the GPU FIQ goes to.
 /* Same status bits as above, but for FIQ. */
 #define LOCAL_FIQ_PENDING0             0x070
 /*
- * Mailbox0 write-to-set bits.  There are 16 mailboxes, 4 per CPU, and
+ * Mailbox write-to-set bits.  There are 16 mailboxes, 4 per CPU, and
  * these bits are organized by mailbox number and then CPU number.  We
  * use mailbox 0 for IPIs.  The mailbox's interrupt is raised while
  * any bit is set.
  */
 #define LOCAL_MAILBOX0_SET0            0x080
-/* Mailbox0 write-to-clear bits. */
+#define LOCAL_MAILBOX3_SET0            0x08c
+/* Mailbox write-to-clear bits. */
 #define LOCAL_MAILBOX0_CLR0            0x0c0
+#define LOCAL_MAILBOX3_CLR0            0x0cc
 
 #define LOCAL_IRQ_CNTPSIRQ     0
 #define LOCAL_IRQ_CNTPNSIRQ    1
@@ -162,7 +167,7 @@ __exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs)
        u32 stat;
 
        stat = readl_relaxed(intc.base + LOCAL_IRQ_PENDING0 + 4 * cpu);
-       if (stat & 0x10) {
+       if (stat & BIT(LOCAL_IRQ_MAILBOX0)) {
 #ifdef CONFIG_SMP
                void __iomem *mailbox0 = (intc.base +
                                          LOCAL_MAILBOX0_CLR0 + 16 * cpu);
@@ -172,7 +177,7 @@ __exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs)
                writel(1 << ipi, mailbox0);
                handle_IPI(ipi, regs);
 #endif
-       } else {
+       } else if (stat) {
                u32 hwirq = ffs(stat) - 1;
 
                handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs);
@@ -217,6 +222,24 @@ static struct notifier_block bcm2836_arm_irqchip_cpu_notifier = {
        .notifier_call = bcm2836_arm_irqchip_cpu_notify,
        .priority = 100,
 };
+
+int __init bcm2836_smp_boot_secondary(unsigned int cpu,
+                                     struct task_struct *idle)
+{
+       unsigned long secondary_startup_phys =
+               (unsigned long)virt_to_phys((void *)secondary_startup);
+
+       dsb();
+       writel(secondary_startup_phys,
+              intc.base + LOCAL_MAILBOX3_SET0 + 16 * cpu);
+
+       return 0;
+}
+
+static const struct smp_operations bcm2836_smp_ops __initconst = {
+       .smp_boot_secondary     = bcm2836_smp_boot_secondary,
+};
+
 #endif
 
 static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = {
@@ -234,9 +257,31 @@ bcm2836_arm_irqchip_smp_init(void)
        register_cpu_notifier(&bcm2836_arm_irqchip_cpu_notifier);
 
        set_smp_cross_call(bcm2836_arm_irqchip_send_ipi);
+       smp_set_ops(&bcm2836_smp_ops);
 #endif
 }
 
+/*
+ * The LOCAL_IRQ_CNT* timer firings are based off of the external
+ * oscillator with some scaling.  The firmware sets up CNTFRQ to
+ * report 19.2Mhz, but doesn't set up the scaling registers.
+ */
+static void bcm2835_init_local_timer_frequency(void)
+{
+       /*
+        * Set the timer to source from the 19.2Mhz crystal clock (bit
+        * 8 unset), and only increment by 1 instead of 2 (bit 9
+        * unset).
+        */
+       writel(0, intc.base + LOCAL_CONTROL);
+
+       /*
+        * Set the timer prescaler to 1:1 (timer freq = input freq *
+        * 2**31 / prescaler)
+        */
+       writel(0x80000000, intc.base + LOCAL_PRESCALER);
+}
+
 static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node,
                                                      struct device_node *parent)
 {
@@ -246,6 +291,8 @@ static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node,
                        node->full_name);
        }
 
+       bcm2835_init_local_timer_frequency();
+
        intc.domain = irq_domain_add_linear(node, LAST_IRQ + 1,
                                            &bcm2836_arm_irqchip_intc_ops,
                                            NULL);
diff --git a/drivers/irqchip/irq-gic-realview.c b/drivers/irqchip/irq-gic-realview.c
new file mode 100644 (file)
index 0000000..aa46eb2
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Special GIC quirks for the ARM RealView
+ * Copyright (C) 2015 Linus Walleij
+ */
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/bitops.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/arm-gic.h>
+
+#define REALVIEW_SYS_LOCK_OFFSET       0x20
+#define REALVIEW_PB11MP_SYS_PLD_CTRL1  0x74
+#define VERSATILE_LOCK_VAL             0xA05F
+#define PLD_INTMODE_MASK               BIT(22)|BIT(23)|BIT(24)
+#define PLD_INTMODE_LEGACY             0x0
+#define PLD_INTMODE_NEW_DCC            BIT(22)
+#define PLD_INTMODE_NEW_NO_DCC         BIT(23)
+#define PLD_INTMODE_FIQ_ENABLE         BIT(24)
+
+static int __init
+realview_gic_of_init(struct device_node *node, struct device_node *parent)
+{
+       static struct regmap *map;
+
+       /* The PB11MPCore GIC needs to be configured in the syscon */
+       map = syscon_regmap_lookup_by_compatible("arm,realview-pb11mp-syscon");
+       if (!IS_ERR(map)) {
+               /* new irq mode with no DCC */
+               regmap_write(map, REALVIEW_SYS_LOCK_OFFSET,
+                            VERSATILE_LOCK_VAL);
+               regmap_update_bits(map, REALVIEW_PB11MP_SYS_PLD_CTRL1,
+                                  PLD_INTMODE_NEW_NO_DCC,
+                                  PLD_INTMODE_MASK);
+               regmap_write(map, REALVIEW_SYS_LOCK_OFFSET, 0x0000);
+               pr_info("TC11MP GIC: set up interrupt controller to NEW mode, no DCC\n");
+       } else {
+               pr_err("TC11MP GIC setup: could not find syscon\n");
+               return -ENXIO;
+       }
+       return gic_of_init(node, parent);
+}
+IRQCHIP_DECLARE(armtc11mp_gic, "arm,tc11mp-gic", realview_gic_of_init);
index 87f8d104acab37970b834ded3b74a93ba8b692f6..c779f83e511d4f6c889a88aa38ffa8086228738e 100644 (file)
 
 #define pr_fmt(fmt) "GICv2m: " fmt
 
+#include <linux/acpi.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
 #include <linux/kernel.h>
+#include <linux/msi.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
 #include <linux/slab.h>
@@ -55,7 +57,7 @@ static DEFINE_SPINLOCK(v2m_lock);
 
 struct v2m_data {
        struct list_head entry;
-       struct device_node *node;
+       struct fwnode_handle *fwnode;
        struct resource res;    /* GICv2m resource */
        void __iomem *base;     /* GICv2m virt address */
        u32 spi_start;          /* The SPI number that MSIs start */
@@ -138,6 +140,11 @@ static int gicv2m_irq_gic_domain_alloc(struct irq_domain *domain,
                fwspec.param[0] = 0;
                fwspec.param[1] = hwirq - 32;
                fwspec.param[2] = IRQ_TYPE_EDGE_RISING;
+       } else if (is_fwnode_irqchip(domain->parent->fwnode)) {
+               fwspec.fwnode = domain->parent->fwnode;
+               fwspec.param_count = 2;
+               fwspec.param[0] = hwirq;
+               fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
        } else {
                return -EINVAL;
        }
@@ -254,7 +261,9 @@ static void gicv2m_teardown(void)
                list_del(&v2m->entry);
                kfree(v2m->bm);
                iounmap(v2m->base);
-               of_node_put(v2m->node);
+               of_node_put(to_of_node(v2m->fwnode));
+               if (is_fwnode_irqchip(v2m->fwnode))
+                       irq_domain_free_fwnode(v2m->fwnode);
                kfree(v2m);
        }
 }
@@ -268,7 +277,7 @@ static int gicv2m_allocate_domains(struct irq_domain *parent)
        if (!v2m)
                return 0;
 
-       inner_domain = irq_domain_create_tree(of_node_to_fwnode(v2m->node),
+       inner_domain = irq_domain_create_tree(v2m->fwnode,
                                              &gicv2m_domain_ops, v2m);
        if (!inner_domain) {
                pr_err("Failed to create GICv2m domain\n");
@@ -277,10 +286,10 @@ static int gicv2m_allocate_domains(struct irq_domain *parent)
 
        inner_domain->bus_token = DOMAIN_BUS_NEXUS;
        inner_domain->parent = parent;
-       pci_domain = pci_msi_create_irq_domain(of_node_to_fwnode(v2m->node),
+       pci_domain = pci_msi_create_irq_domain(v2m->fwnode,
                                               &gicv2m_msi_domain_info,
                                               inner_domain);
-       plat_domain = platform_msi_create_irq_domain(of_node_to_fwnode(v2m->node),
+       plat_domain = platform_msi_create_irq_domain(v2m->fwnode,
                                                     &gicv2m_pmsi_domain_info,
                                                     inner_domain);
        if (!pci_domain || !plat_domain) {
@@ -296,8 +305,9 @@ static int gicv2m_allocate_domains(struct irq_domain *parent)
        return 0;
 }
 
-static int __init gicv2m_init_one(struct device_node *node,
-                                 struct irq_domain *parent)
+static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
+                                 u32 spi_start, u32 nr_spis,
+                                 struct resource *res)
 {
        int ret;
        struct v2m_data *v2m;
@@ -309,13 +319,9 @@ static int __init gicv2m_init_one(struct device_node *node,
        }
 
        INIT_LIST_HEAD(&v2m->entry);
-       v2m->node = node;
+       v2m->fwnode = fwnode;
 
-       ret = of_address_to_resource(node, 0, &v2m->res);
-       if (ret) {
-               pr_err("Failed to allocate v2m resource.\n");
-               goto err_free_v2m;
-       }
+       memcpy(&v2m->res, res, sizeof(struct resource));
 
        v2m->base = ioremap(v2m->res.start, resource_size(&v2m->res));
        if (!v2m->base) {
@@ -324,10 +330,9 @@ static int __init gicv2m_init_one(struct device_node *node,
                goto err_free_v2m;
        }
 
-       if (!of_property_read_u32(node, "arm,msi-base-spi", &v2m->spi_start) &&
-           !of_property_read_u32(node, "arm,msi-num-spis", &v2m->nr_spis)) {
-               pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n",
-                       v2m->spi_start, v2m->nr_spis);
+       if (spi_start && nr_spis) {
+               v2m->spi_start = spi_start;
+               v2m->nr_spis = nr_spis;
        } else {
                u32 typer = readl_relaxed(v2m->base + V2M_MSI_TYPER);
 
@@ -359,10 +364,9 @@ static int __init gicv2m_init_one(struct device_node *node,
        }
 
        list_add_tail(&v2m->entry, &v2m_nodes);
-       pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", node->name,
-               (unsigned long)v2m->res.start, (unsigned long)v2m->res.end,
-               v2m->spi_start, (v2m->spi_start + v2m->nr_spis));
 
+       pr_info("range%pR, SPI[%d:%d]\n", res,
+               v2m->spi_start, (v2m->spi_start + v2m->nr_spis - 1));
        return 0;
 
 err_iounmap:
@@ -377,19 +381,36 @@ static struct of_device_id gicv2m_device_id[] = {
        {},
 };
 
-int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent)
+static int __init gicv2m_of_init(struct fwnode_handle *parent_handle,
+                                struct irq_domain *parent)
 {
        int ret = 0;
+       struct device_node *node = to_of_node(parent_handle);
        struct device_node *child;
 
        for (child = of_find_matching_node(node, gicv2m_device_id); child;
             child = of_find_matching_node(child, gicv2m_device_id)) {
+               u32 spi_start = 0, nr_spis = 0;
+               struct resource res;
+
                if (!of_find_property(child, "msi-controller", NULL))
                        continue;
 
-               ret = gicv2m_init_one(child, parent);
+               ret = of_address_to_resource(child, 0, &res);
+               if (ret) {
+                       pr_err("Failed to allocate v2m resource.\n");
+                       break;
+               }
+
+               if (!of_property_read_u32(child, "arm,msi-base-spi",
+                                         &spi_start) &&
+                   !of_property_read_u32(child, "arm,msi-num-spis", &nr_spis))
+                       pr_info("DT overriding V2M MSI_TYPER (base:%u, num:%u)\n",
+                               spi_start, nr_spis);
+
+               ret = gicv2m_init_one(&child->fwnode, spi_start, nr_spis, &res);
                if (ret) {
-                       of_node_put(node);
+                       of_node_put(child);
                        break;
                }
        }
@@ -400,3 +421,101 @@ int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent)
                gicv2m_teardown();
        return ret;
 }
+
+#ifdef CONFIG_ACPI
+static int acpi_num_msi;
+
+static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev)
+{
+       struct v2m_data *data;
+
+       if (WARN_ON(acpi_num_msi <= 0))
+               return NULL;
+
+       /* We only return the fwnode of the first MSI frame. */
+       data = list_first_entry_or_null(&v2m_nodes, struct v2m_data, entry);
+       if (!data)
+               return NULL;
+
+       return data->fwnode;
+}
+
+static int __init
+acpi_parse_madt_msi(struct acpi_subtable_header *header,
+                   const unsigned long end)
+{
+       int ret;
+       struct resource res;
+       u32 spi_start = 0, nr_spis = 0;
+       struct acpi_madt_generic_msi_frame *m;
+       struct fwnode_handle *fwnode;
+
+       m = (struct acpi_madt_generic_msi_frame *)header;
+       if (BAD_MADT_ENTRY(m, end))
+               return -EINVAL;
+
+       res.start = m->base_address;
+       res.end = m->base_address + SZ_4K - 1;
+       res.flags = IORESOURCE_MEM;
+
+       if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {
+               spi_start = m->spi_base;
+               nr_spis = m->spi_count;
+
+               pr_info("ACPI overriding V2M MSI_TYPER (base:%u, num:%u)\n",
+                       spi_start, nr_spis);
+       }
+
+       fwnode = irq_domain_alloc_fwnode((void *)m->base_address);
+       if (!fwnode) {
+               pr_err("Unable to allocate GICv2m domain token\n");
+               return -EINVAL;
+       }
+
+       ret = gicv2m_init_one(fwnode, spi_start, nr_spis, &res);
+       if (ret)
+               irq_domain_free_fwnode(fwnode);
+
+       return ret;
+}
+
+static int __init gicv2m_acpi_init(struct irq_domain *parent)
+{
+       int ret;
+
+       if (acpi_num_msi > 0)
+               return 0;
+
+       acpi_num_msi = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_MSI_FRAME,
+                                     acpi_parse_madt_msi, 0);
+
+       if (acpi_num_msi <= 0)
+               goto err_out;
+
+       ret = gicv2m_allocate_domains(parent);
+       if (ret)
+               goto err_out;
+
+       pci_msi_register_fwnode_provider(&gicv2m_get_fwnode);
+
+       return 0;
+
+err_out:
+       gicv2m_teardown();
+       return -EINVAL;
+}
+#else /* CONFIG_ACPI */
+static int __init gicv2m_acpi_init(struct irq_domain *parent)
+{
+       return -EINVAL;
+}
+#endif /* CONFIG_ACPI */
+
+int __init gicv2m_init(struct fwnode_handle *parent_handle,
+                      struct irq_domain *parent)
+{
+       if (is_of_node(parent_handle))
+               return gicv2m_of_init(parent_handle, parent);
+
+       return gicv2m_acpi_init(parent);
+}
index abf2ffaed392270c97d14c7fdc2ab247e63a58e1..911758c056c14152d5a248110c14f35bd48e9b78 100644 (file)
@@ -69,6 +69,7 @@ union gic_base {
 };
 
 struct gic_chip_data {
+       struct irq_chip chip;
        union gic_base dist_base;
        union gic_base cpu_base;
 #ifdef CONFIG_CPU_PM
@@ -99,11 +100,7 @@ static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
 
 static struct static_key supports_deactivate = STATIC_KEY_INIT_TRUE;
 
-#ifndef MAX_GIC_NR
-#define MAX_GIC_NR     1
-#endif
-
-static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly;
+static struct gic_chip_data gic_data[CONFIG_ARM_GIC_MAX_NR] __read_mostly;
 
 #ifdef CONFIG_GIC_NON_BANKED
 static void __iomem *gic_get_percpu_base(union gic_base *base)
@@ -336,7 +333,7 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
                irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
                irqnr = irqstat & GICC_IAR_INT_ID_MASK;
 
-               if (likely(irqnr > 15 && irqnr < 1021)) {
+               if (likely(irqnr > 15 && irqnr < 1020)) {
                        if (static_key_true(&supports_deactivate))
                                writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
                        handle_domain_irq(gic->domain, irqnr, regs);
@@ -383,7 +380,6 @@ static void gic_handle_cascade_irq(struct irq_desc *desc)
 }
 
 static struct irq_chip gic_chip = {
-       .name                   = "GIC",
        .irq_mask               = gic_mask_irq,
        .irq_unmask             = gic_unmask_irq,
        .irq_eoi                = gic_eoi_irq,
@@ -417,8 +413,7 @@ static struct irq_chip gic_eoimode1_chip = {
 
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
-       if (gic_nr >= MAX_GIC_NR)
-               BUG();
+       BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
        irq_set_chained_handler_and_data(irq, gic_handle_cascade_irq,
                                         &gic_data[gic_nr]);
 }
@@ -524,7 +519,7 @@ int gic_cpu_if_down(unsigned int gic_nr)
        void __iomem *cpu_base;
        u32 val = 0;
 
-       if (gic_nr >= MAX_GIC_NR)
+       if (gic_nr >= CONFIG_ARM_GIC_MAX_NR)
                return -EINVAL;
 
        cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
@@ -548,8 +543,7 @@ static void gic_dist_save(unsigned int gic_nr)
        void __iomem *dist_base;
        int i;
 
-       if (gic_nr >= MAX_GIC_NR)
-               BUG();
+       BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
 
        gic_irqs = gic_data[gic_nr].gic_irqs;
        dist_base = gic_data_dist_base(&gic_data[gic_nr]);
@@ -587,8 +581,7 @@ static void gic_dist_restore(unsigned int gic_nr)
        unsigned int i;
        void __iomem *dist_base;
 
-       if (gic_nr >= MAX_GIC_NR)
-               BUG();
+       BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
 
        gic_irqs = gic_data[gic_nr].gic_irqs;
        dist_base = gic_data_dist_base(&gic_data[gic_nr]);
@@ -634,8 +627,7 @@ static void gic_cpu_save(unsigned int gic_nr)
        void __iomem *dist_base;
        void __iomem *cpu_base;
 
-       if (gic_nr >= MAX_GIC_NR)
-               BUG();
+       BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
 
        dist_base = gic_data_dist_base(&gic_data[gic_nr]);
        cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
@@ -664,8 +656,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
        void __iomem *dist_base;
        void __iomem *cpu_base;
 
-       if (gic_nr >= MAX_GIC_NR)
-               BUG();
+       BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
 
        dist_base = gic_data_dist_base(&gic_data[gic_nr]);
        cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
@@ -703,7 +694,7 @@ static int gic_notifier(struct notifier_block *self, unsigned long cmd,     void *v)
 {
        int i;
 
-       for (i = 0; i < MAX_GIC_NR; i++) {
+       for (i = 0; i < CONFIG_ARM_GIC_MAX_NR; i++) {
 #ifdef CONFIG_GIC_NON_BANKED
                /* Skip over unused GICs */
                if (!gic_data[i].get_base)
@@ -835,8 +826,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
        int i, ror_val, cpu = smp_processor_id();
        u32 val, cur_target_mask, active_mask;
 
-       if (gic_nr >= MAX_GIC_NR)
-               BUG();
+       BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
 
        dist_base = gic_data_dist_base(&gic_data[gic_nr]);
        if (!dist_base)
@@ -925,20 +915,15 @@ void __init gic_init_physaddr(struct device_node *node)
 static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
                                irq_hw_number_t hw)
 {
-       struct irq_chip *chip = &gic_chip;
-
-       if (static_key_true(&supports_deactivate)) {
-               if (d->host_data == (void *)&gic_data[0])
-                       chip = &gic_eoimode1_chip;
-       }
+       struct gic_chip_data *gic = d->host_data;
 
        if (hw < 32) {
                irq_set_percpu_devid(irq);
-               irq_domain_set_info(d, irq, hw, chip, d->host_data,
+               irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data,
                                    handle_percpu_devid_irq, NULL, NULL);
                irq_set_status_flags(irq, IRQ_NOAUTOEN);
        } else {
-               irq_domain_set_info(d, irq, hw, chip, d->host_data,
+               irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data,
                                    handle_fasteoi_irq, NULL, NULL);
                irq_set_probe(irq);
        }
@@ -972,7 +957,7 @@ static int gic_irq_domain_translate(struct irq_domain *d,
                return 0;
        }
 
-       if (fwspec->fwnode->type == FWNODE_IRQCHIP) {
+       if (is_fwnode_irqchip(fwspec->fwnode)) {
                if(fwspec->param_count != 2)
                        return -EINVAL;
 
@@ -1040,11 +1025,20 @@ static void __init __gic_init_bases(unsigned int gic_nr, int irq_start,
        struct gic_chip_data *gic;
        int gic_irqs, irq_base, i;
 
-       BUG_ON(gic_nr >= MAX_GIC_NR);
+       BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
 
        gic_check_cpu_features();
 
        gic = &gic_data[gic_nr];
+
+       /* Initialize irq_chip */
+       if (static_key_true(&supports_deactivate) && gic_nr == 0) {
+               gic->chip = gic_eoimode1_chip;
+       } else {
+               gic->chip = gic_chip;
+               gic->chip.name = kasprintf(GFP_KERNEL, "GIC-%d", gic_nr);
+       }
+
 #ifdef CONFIG_GIC_NON_BANKED
        if (percpu_offset) { /* Frankein-GIC without banked registers... */
                unsigned int cpu;
@@ -1196,7 +1190,7 @@ static bool gic_check_eoimode(struct device_node *node, void __iomem **base)
        return true;
 }
 
-static int __init
+int __init
 gic_of_init(struct device_node *node, struct device_node *parent)
 {
        void __iomem *cpu_base;
@@ -1234,7 +1228,7 @@ gic_of_init(struct device_node *node, struct device_node *parent)
        }
 
        if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
-               gicv2m_of_init(node, gic_data[gic_cnt].domain);
+               gicv2m_init(&node->fwnode, gic_data[gic_cnt].domain);
 
        gic_cnt++;
        return 0;
@@ -1359,6 +1353,10 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
        __gic_init_bases(0, -1, dist_base, cpu_base, 0, domain_handle);
 
        acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
+
+       if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
+               gicv2m_init(NULL, gic_data[0].domain);
+
        return 0;
 }
 IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
new file mode 100644 (file)
index 0000000..4dd3eb8
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2015 Hisilicon Limited, All Rights Reserved.
+ * Author: Jun Ma <majun258@huawei.com>
+ * Author: Yun Wu <wuyun.wu@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irqchip.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/* Interrupt numbers per mbigen node supported */
+#define IRQS_PER_MBIGEN_NODE           128
+
+/* 64 irqs (Pin0-pin63) are reserved for each mbigen chip */
+#define RESERVED_IRQ_PER_MBIGEN_CHIP   64
+
+/* The maximum IRQ pin number of mbigen chip(start from 0) */
+#define MAXIMUM_IRQ_PIN_NUM            1407
+
+/**
+ * In mbigen vector register
+ * bit[21:12]: event id value
+ * bit[11:0]:  device id
+ */
+#define IRQ_EVENT_ID_SHIFT             12
+#define IRQ_EVENT_ID_MASK              0x3ff
+
+/* register range of each mbigen node */
+#define MBIGEN_NODE_OFFSET             0x1000
+
+/* offset of vector register in mbigen node */
+#define REG_MBIGEN_VEC_OFFSET          0x200
+
+/**
+ * offset of clear register in mbigen node
+ * This register is used to clear the status
+ * of interrupt
+ */
+#define REG_MBIGEN_CLEAR_OFFSET                0xa000
+
+/**
+ * offset of interrupt type register
+ * This register is used to configure interrupt
+ * trigger type
+ */
+#define REG_MBIGEN_TYPE_OFFSET         0x0
+
+/**
+ * struct mbigen_device - holds the information of mbigen device.
+ *
+ * @pdev:              pointer to the platform device structure of mbigen chip.
+ * @base:              mapped address of this mbigen chip.
+ */
+struct mbigen_device {
+       struct platform_device  *pdev;
+       void __iomem            *base;
+};
+
+static inline unsigned int get_mbigen_vec_reg(irq_hw_number_t hwirq)
+{
+       unsigned int nid, pin;
+
+       hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP;
+       nid = hwirq / IRQS_PER_MBIGEN_NODE + 1;
+       pin = hwirq % IRQS_PER_MBIGEN_NODE;
+
+       return pin * 4 + nid * MBIGEN_NODE_OFFSET
+                       + REG_MBIGEN_VEC_OFFSET;
+}
+
+static inline void get_mbigen_type_reg(irq_hw_number_t hwirq,
+                                       u32 *mask, u32 *addr)
+{
+       unsigned int nid, irq_ofst, ofst;
+
+       hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP;
+       nid = hwirq / IRQS_PER_MBIGEN_NODE + 1;
+       irq_ofst = hwirq % IRQS_PER_MBIGEN_NODE;
+
+       *mask = 1 << (irq_ofst % 32);
+       ofst = irq_ofst / 32 * 4;
+
+       *addr = ofst + nid * MBIGEN_NODE_OFFSET
+               + REG_MBIGEN_TYPE_OFFSET;
+}
+
+static inline void get_mbigen_clear_reg(irq_hw_number_t hwirq,
+                                       u32 *mask, u32 *addr)
+{
+       unsigned int ofst;
+
+       hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP;
+       ofst = hwirq / 32 * 4;
+
+       *mask = 1 << (hwirq % 32);
+       *addr = ofst + REG_MBIGEN_CLEAR_OFFSET;
+}
+
+static void mbigen_eoi_irq(struct irq_data *data)
+{
+       void __iomem *base = data->chip_data;
+       u32 mask, addr;
+
+       get_mbigen_clear_reg(data->hwirq, &mask, &addr);
+
+       writel_relaxed(mask, base + addr);
+
+       irq_chip_eoi_parent(data);
+}
+
+static int mbigen_set_type(struct irq_data *data, unsigned int type)
+{
+       void __iomem *base = data->chip_data;
+       u32 mask, addr, val;
+
+       if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+               return -EINVAL;
+
+       get_mbigen_type_reg(data->hwirq, &mask, &addr);
+
+       val = readl_relaxed(base + addr);
+
+       if (type == IRQ_TYPE_LEVEL_HIGH)
+               val |= mask;
+       else
+               val &= ~mask;
+
+       writel_relaxed(val, base + addr);
+
+       return 0;
+}
+
+static struct irq_chip mbigen_irq_chip = {
+       .name =                 "mbigen-v2",
+       .irq_mask =             irq_chip_mask_parent,
+       .irq_unmask =           irq_chip_unmask_parent,
+       .irq_eoi =              mbigen_eoi_irq,
+       .irq_set_type =         mbigen_set_type,
+       .irq_set_affinity =     irq_chip_set_affinity_parent,
+};
+
+static void mbigen_write_msg(struct msi_desc *desc, struct msi_msg *msg)
+{
+       struct irq_data *d = irq_get_irq_data(desc->irq);
+       void __iomem *base = d->chip_data;
+       u32 val;
+
+       base += get_mbigen_vec_reg(d->hwirq);
+       val = readl_relaxed(base);
+
+       val &= ~(IRQ_EVENT_ID_MASK << IRQ_EVENT_ID_SHIFT);
+       val |= (msg->data << IRQ_EVENT_ID_SHIFT);
+
+       /* The address of doorbell is encoded in mbigen register by default
+        * So,we don't need to program the doorbell address at here
+        */
+       writel_relaxed(val, base);
+}
+
+static int mbigen_domain_translate(struct irq_domain *d,
+                                   struct irq_fwspec *fwspec,
+                                   unsigned long *hwirq,
+                                   unsigned int *type)
+{
+       if (is_of_node(fwspec->fwnode)) {
+               if (fwspec->param_count != 2)
+                       return -EINVAL;
+
+               if ((fwspec->param[0] > MAXIMUM_IRQ_PIN_NUM) ||
+                       (fwspec->param[0] < RESERVED_IRQ_PER_MBIGEN_CHIP))
+                       return -EINVAL;
+               else
+                       *hwirq = fwspec->param[0];
+
+               /* If there is no valid irq type, just use the default type */
+               if ((fwspec->param[1] == IRQ_TYPE_EDGE_RISING) ||
+                       (fwspec->param[1] == IRQ_TYPE_LEVEL_HIGH))
+                       *type = fwspec->param[1];
+               else
+                       return -EINVAL;
+
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int mbigen_irq_domain_alloc(struct irq_domain *domain,
+                                       unsigned int virq,
+                                       unsigned int nr_irqs,
+                                       void *args)
+{
+       struct irq_fwspec *fwspec = args;
+       irq_hw_number_t hwirq;
+       unsigned int type;
+       struct mbigen_device *mgn_chip;
+       int i, err;
+
+       err = mbigen_domain_translate(domain, fwspec, &hwirq, &type);
+       if (err)
+               return err;
+
+       err = platform_msi_domain_alloc(domain, virq, nr_irqs);
+       if (err)
+               return err;
+
+       mgn_chip = platform_msi_get_host_data(domain);
+
+       for (i = 0; i < nr_irqs; i++)
+               irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
+                                     &mbigen_irq_chip, mgn_chip->base);
+
+       return 0;
+}
+
+static struct irq_domain_ops mbigen_domain_ops = {
+       .translate      = mbigen_domain_translate,
+       .alloc          = mbigen_irq_domain_alloc,
+       .free           = irq_domain_free_irqs_common,
+};
+
+static int mbigen_device_probe(struct platform_device *pdev)
+{
+       struct mbigen_device *mgn_chip;
+       struct resource *res;
+       struct irq_domain *domain;
+       u32 num_pins;
+
+       mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
+       if (!mgn_chip)
+               return -ENOMEM;
+
+       mgn_chip->pdev = pdev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mgn_chip->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(mgn_chip->base))
+               return PTR_ERR(mgn_chip->base);
+
+       if (of_property_read_u32(pdev->dev.of_node, "num-pins", &num_pins) < 0) {
+               dev_err(&pdev->dev, "No num-pins property\n");
+               return -EINVAL;
+       }
+
+       domain = platform_msi_create_device_domain(&pdev->dev, num_pins,
+                                                       mbigen_write_msg,
+                                                       &mbigen_domain_ops,
+                                                       mgn_chip);
+
+       if (!domain)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, mgn_chip);
+
+       dev_info(&pdev->dev, "Allocated %d MSIs\n", num_pins);
+
+       return 0;
+}
+
+static const struct of_device_id mbigen_of_match[] = {
+       { .compatible = "hisilicon,mbigen-v2" },
+       { /* END */ }
+};
+MODULE_DEVICE_TABLE(of, mbigen_of_match);
+
+static struct platform_driver mbigen_platform_driver = {
+       .driver = {
+               .name           = "Hisilicon MBIGEN-V2",
+               .owner          = THIS_MODULE,
+               .of_match_table = mbigen_of_match,
+       },
+       .probe                  = mbigen_device_probe,
+};
+
+module_platform_driver(mbigen_platform_driver);
+
+MODULE_AUTHOR("Jun Ma <majun258@huawei.com>");
+MODULE_AUTHOR("Yun Wu <wuyun.wu@huawei.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Hisilicon MBI Generator driver");
index 8587d0f8d8c03300e6ece2da0f252b767d31f781..9d1bcfc33e4c973522ad818c18b65cde878bd56a 100644 (file)
@@ -47,6 +47,7 @@
 #define INTC_ILR0              0x0100
 
 #define ACTIVEIRQ_MASK         0x7f    /* omap2/3 active interrupt bits */
+#define SPURIOUSIRQ_MASK       (0x1ffffff << 7)
 #define INTCPS_NR_ILR_REGS     128
 #define INTCPS_NR_MIR_REGS     4
 
@@ -207,7 +208,6 @@ static int __init omap_alloc_gc_of(struct irq_domain *d, void __iomem *base)
                ct = gc->chip_types;
 
                ct->type = IRQ_TYPE_LEVEL_MASK;
-               ct->handler = handle_level_irq;
 
                ct->chip.irq_ack = omap_mask_ack_irq;
                ct->chip.irq_mask = irq_gc_mask_disable_reg;
@@ -330,11 +330,35 @@ static int __init omap_init_irq(u32 base, struct device_node *node)
 static asmlinkage void __exception_irq_entry
 omap_intc_handle_irq(struct pt_regs *regs)
 {
+       extern unsigned long irq_err_count;
        u32 irqnr;
 
        irqnr = intc_readl(INTC_SIR);
+
+       /*
+        * A spurious IRQ can result if interrupt that triggered the
+        * sorting is no longer active during the sorting (10 INTC
+        * functional clock cycles after interrupt assertion). Or a
+        * change in interrupt mask affected the result during sorting
+        * time. There is no special handling required except ignoring
+        * the SIR register value just read and retrying.
+        * See section 6.2.5 of AM335x TRM Literature Number: SPRUH73K
+        *
+        * Many a times, a spurious interrupt situation has been fixed
+        * by adding a flush for the posted write acking the IRQ in
+        * the device driver. Typically, this is going be the device
+        * driver whose interrupt was handled just before the spurious
+        * IRQ occurred. Pay attention to those device drivers if you
+        * run into hitting the spurious IRQ condition below.
+        */
+       if (unlikely((irqnr & SPURIOUSIRQ_MASK) == SPURIOUSIRQ_MASK)) {
+               pr_err_once("%s: spurious irq!\n", __func__);
+               irq_err_count++;
+               omap_ack_irq(NULL);
+               return;
+       }
+
        irqnr &= ACTIVEIRQ_MASK;
-       WARN_ONCE(!irqnr, "Spurious IRQ ?\n");
        handle_domain_irq(domain, irqnr, regs);
 }
 
index 6fd30d5ee14dddcd7a35169632a26d2156c2e34c..c378768d75b333866778f0d2e63567a1d249cc4a 100644 (file)
@@ -21,9 +21,9 @@ static const char ipr_bit[] = {
        10, 10, 10, 10,  9,  9,  9,  9,
 };
 
-static void *intc_baseaddr;
+static void __iomem *intc_baseaddr;
 
-#define IPR ((unsigned long)intc_baseaddr + 6)
+#define IPR (intc_baseaddr + 6)
 
 static void h8300h_disable_irq(struct irq_data *data)
 {
@@ -81,8 +81,8 @@ static int __init h8300h_intc_of_init(struct device_node *intc,
        BUG_ON(!intc_baseaddr);
 
        /* All interrupt priority low */
-       ctrl_outb(0x00, IPR + 0);
-       ctrl_outb(0x00, IPR + 1);
+       writeb(0x00, IPR + 0);
+       writeb(0x00, IPR + 1);
 
        domain = irq_domain_add_linear(intc, NR_IRQS, &irq_ops, NULL);
        BUG_ON(!domain);
index c325806561bedd932db973470d4bedfaf3950886..713177d97c7aa0b66210f5be611931d230f9421b 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
-#include <linux/platform_data/irq-renesas-intc-irqpin.h>
 #include <linux/pm_runtime.h>
 
 #define INTC_IRQPIN_MAX 8 /* maximum 8 interrupts per driver instance */
@@ -75,18 +74,20 @@ struct intc_irqpin_irq {
 struct intc_irqpin_priv {
        struct intc_irqpin_iomem iomem[INTC_IRQPIN_REG_NR];
        struct intc_irqpin_irq irq[INTC_IRQPIN_MAX];
-       struct renesas_intc_irqpin_config config;
-       unsigned int number_of_irqs;
+       unsigned int sense_bitfield_width;
        struct platform_device *pdev;
        struct irq_chip irq_chip;
        struct irq_domain *irq_domain;
        struct clk *clk;
-       bool shared_irqs;
+       unsigned shared_irqs:1;
+       unsigned needs_clk:1;
        u8 shared_irq_mask;
 };
 
-struct intc_irqpin_irlm_config {
+struct intc_irqpin_config {
        unsigned int irlm_bit;
+       unsigned needs_irlm:1;
+       unsigned needs_clk:1;
 };
 
 static unsigned long intc_irqpin_read32(void __iomem *iomem)
@@ -171,7 +172,7 @@ static void intc_irqpin_mask_unmask_prio(struct intc_irqpin_priv *p,
 static int intc_irqpin_set_sense(struct intc_irqpin_priv *p, int irq, int value)
 {
        /* The SENSE register is assumed to be 32-bit. */
-       int bitfield_width = p->config.sense_bitfield_width;
+       int bitfield_width = p->sense_bitfield_width;
        int shift = 32 - (irq + 1) * bitfield_width;
 
        dev_dbg(&p->pdev->dev, "sense irq = %d, mode = %d\n", irq, value);
@@ -361,8 +362,15 @@ static const struct irq_domain_ops intc_irqpin_irq_domain_ops = {
        .xlate  = irq_domain_xlate_twocell,
 };
 
-static const struct intc_irqpin_irlm_config intc_irqpin_irlm_r8a777x = {
+static const struct intc_irqpin_config intc_irqpin_irlm_r8a777x = {
        .irlm_bit = 23, /* ICR0.IRLM0 */
+       .needs_irlm = 1,
+       .needs_clk = 0,
+};
+
+static const struct intc_irqpin_config intc_irqpin_rmobile = {
+       .needs_irlm = 0,
+       .needs_clk = 1,
 };
 
 static const struct of_device_id intc_irqpin_dt_ids[] = {
@@ -371,14 +379,18 @@ static const struct of_device_id intc_irqpin_dt_ids[] = {
          .data = &intc_irqpin_irlm_r8a777x },
        { .compatible = "renesas,intc-irqpin-r8a7779",
          .data = &intc_irqpin_irlm_r8a777x },
+       { .compatible = "renesas,intc-irqpin-r8a7740",
+         .data = &intc_irqpin_rmobile },
+       { .compatible = "renesas,intc-irqpin-sh73a0",
+         .data = &intc_irqpin_rmobile },
        {},
 };
 MODULE_DEVICE_TABLE(of, intc_irqpin_dt_ids);
 
 static int intc_irqpin_probe(struct platform_device *pdev)
 {
+       const struct intc_irqpin_config *config = NULL;
        struct device *dev = &pdev->dev;
-       struct renesas_intc_irqpin_config *pdata = dev->platform_data;
        const struct of_device_id *of_id;
        struct intc_irqpin_priv *p;
        struct intc_irqpin_iomem *i;
@@ -388,6 +400,8 @@ static int intc_irqpin_probe(struct platform_device *pdev)
        void (*enable_fn)(struct irq_data *d);
        void (*disable_fn)(struct irq_data *d);
        const char *name = dev_name(dev);
+       bool control_parent;
+       unsigned int nirqs;
        int ref_irq;
        int ret;
        int k;
@@ -399,23 +413,28 @@ static int intc_irqpin_probe(struct platform_device *pdev)
        }
 
        /* deal with driver instance configuration */
-       if (pdata) {
-               memcpy(&p->config, pdata, sizeof(*pdata));
-       } else {
-               of_property_read_u32(dev->of_node, "sense-bitfield-width",
-                                    &p->config.sense_bitfield_width);
-               p->config.control_parent = of_property_read_bool(dev->of_node,
-                                                                "control-parent");
-       }
-       if (!p->config.sense_bitfield_width)
-               p->config.sense_bitfield_width = 4; /* default to 4 bits */
+       of_property_read_u32(dev->of_node, "sense-bitfield-width",
+                            &p->sense_bitfield_width);
+       control_parent = of_property_read_bool(dev->of_node, "control-parent");
+       if (!p->sense_bitfield_width)
+               p->sense_bitfield_width = 4; /* default to 4 bits */
 
        p->pdev = pdev;
        platform_set_drvdata(pdev, p);
 
+       of_id = of_match_device(intc_irqpin_dt_ids, dev);
+       if (of_id && of_id->data) {
+               config = of_id->data;
+               p->needs_clk = config->needs_clk;
+       }
+
        p->clk = devm_clk_get(dev, NULL);
        if (IS_ERR(p->clk)) {
-               dev_warn(dev, "unable to get clock\n");
+               if (p->needs_clk) {
+                       dev_err(dev, "unable to get clock\n");
+                       ret = PTR_ERR(p->clk);
+                       goto err0;
+               }
                p->clk = NULL;
        }
 
@@ -443,8 +462,8 @@ static int intc_irqpin_probe(struct platform_device *pdev)
                p->irq[k].requested_irq = irq->start;
        }
 
-       p->number_of_irqs = k;
-       if (p->number_of_irqs < 1) {
+       nirqs = k;
+       if (nirqs < 1) {
                dev_err(dev, "not enough IRQ resources\n");
                ret = -EINVAL;
                goto err0;
@@ -485,20 +504,16 @@ static int intc_irqpin_probe(struct platform_device *pdev)
        }
 
        /* configure "individual IRQ mode" where needed */
-       of_id = of_match_device(intc_irqpin_dt_ids, dev);
-       if (of_id && of_id->data) {
-               const struct intc_irqpin_irlm_config *irlm_config = of_id->data;
-
+       if (config && config->needs_irlm) {
                if (io[INTC_IRQPIN_REG_IRLM])
                        intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_IRLM,
-                                                     irlm_config->irlm_bit,
-                                                     1, 1);
+                                                     config->irlm_bit, 1, 1);
                else
                        dev_warn(dev, "unable to select IRLM mode\n");
        }
 
        /* mask all interrupts using priority */
-       for (k = 0; k < p->number_of_irqs; k++)
+       for (k = 0; k < nirqs; k++)
                intc_irqpin_mask_unmask_prio(p, k, 1);
 
        /* clear all pending interrupts */
@@ -506,16 +521,16 @@ static int intc_irqpin_probe(struct platform_device *pdev)
 
        /* scan for shared interrupt lines */
        ref_irq = p->irq[0].requested_irq;
-       p->shared_irqs = true;
-       for (k = 1; k < p->number_of_irqs; k++) {
+       p->shared_irqs = 1;
+       for (k = 1; k < nirqs; k++) {
                if (ref_irq != p->irq[k].requested_irq) {
-                       p->shared_irqs = false;
+                       p->shared_irqs = 0;
                        break;
                }
        }
 
        /* use more severe masking method if requested */
-       if (p->config.control_parent) {
+       if (control_parent) {
                enable_fn = intc_irqpin_irq_enable_force;
                disable_fn = intc_irqpin_irq_disable_force;
        } else if (!p->shared_irqs) {
@@ -534,9 +549,7 @@ static int intc_irqpin_probe(struct platform_device *pdev)
        irq_chip->irq_set_wake = intc_irqpin_irq_set_wake;
        irq_chip->flags = IRQCHIP_MASK_ON_SUSPEND;
 
-       p->irq_domain = irq_domain_add_simple(dev->of_node,
-                                             p->number_of_irqs,
-                                             p->config.irq_base,
+       p->irq_domain = irq_domain_add_simple(dev->of_node, nirqs, 0,
                                              &intc_irqpin_irq_domain_ops, p);
        if (!p->irq_domain) {
                ret = -ENXIO;
@@ -555,7 +568,7 @@ static int intc_irqpin_probe(struct platform_device *pdev)
                }
        } else {
                /* request interrupts one by one */
-               for (k = 0; k < p->number_of_irqs; k++) {
+               for (k = 0; k < nirqs; k++) {
                        if (devm_request_irq(dev, p->irq[k].requested_irq,
                                             intc_irqpin_irq_handler, 0, name,
                                             &p->irq[k])) {
@@ -567,17 +580,10 @@ static int intc_irqpin_probe(struct platform_device *pdev)
        }
 
        /* unmask all interrupts on prio level */
-       for (k = 0; k < p->number_of_irqs; k++)
+       for (k = 0; k < nirqs; k++)
                intc_irqpin_mask_unmask_prio(p, k, 0);
 
-       dev_info(dev, "driving %d irqs\n", p->number_of_irqs);
-
-       /* warn in case of mismatch if irq base is specified */
-       if (p->config.irq_base) {
-               if (p->config.irq_base != p->irq[0].domain_irq)
-                       dev_warn(dev, "irq base mismatch (%d/%d)\n",
-                                p->config.irq_base, p->irq[0].domain_irq);
-       }
+       dev_info(dev, "driving %d irqs\n", nirqs);
 
        return 0;
 
index 4ef178078e5bd7ddf388e215eddc1bde3151b0fb..0820f67cc9a76b42a8891501c9f04c574d6e27e8 100644 (file)
@@ -50,6 +50,12 @@ static struct sunxi_sc_nmi_reg_offs sun6i_reg_offs = {
        .enable = 0x34,
 };
 
+static struct sunxi_sc_nmi_reg_offs sun9i_reg_offs = {
+       .ctrl   = 0x00,
+       .pend   = 0x08,
+       .enable = 0x04,
+};
+
 static inline void sunxi_sc_nmi_write(struct irq_chip_generic *gc, u32 off,
                                      u32 val)
 {
@@ -207,3 +213,10 @@ static int __init sun7i_sc_nmi_irq_init(struct device_node *node,
        return sunxi_sc_nmi_irq_init(node, &sun7i_reg_offs);
 }
 IRQCHIP_DECLARE(sun7i_sc_nmi, "allwinner,sun7i-a20-sc-nmi", sun7i_sc_nmi_irq_init);
+
+static int __init sun9i_nmi_irq_init(struct device_node *node,
+                                    struct device_node *parent)
+{
+       return sunxi_sc_nmi_irq_init(node, &sun9i_reg_offs);
+}
+IRQCHIP_DECLARE(sun9i_nmi, "allwinner,sun9i-a80-nmi", sun9i_nmi_irq_init);
diff --git a/drivers/irqchip/irq-ts4800.c b/drivers/irqchip/irq-ts4800.c
new file mode 100644 (file)
index 0000000..4192bdc
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Multiplexed-IRQs driver for TS-4800's FPGA
+ *
+ * Copyright (c) 2015 - Savoir-faire Linux
+ *
+ * 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/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
+#define IRQ_MASK        0x4
+#define IRQ_STATUS      0x8
+
+struct ts4800_irq_data {
+       void __iomem            *base;
+       struct irq_domain       *domain;
+       struct irq_chip         irq_chip;
+};
+
+static void ts4800_irq_mask(struct irq_data *d)
+{
+       struct ts4800_irq_data *data = irq_data_get_irq_chip_data(d);
+       u16 reg = readw(data->base + IRQ_MASK);
+       u16 mask = 1 << d->hwirq;
+
+       writew(reg | mask, data->base + IRQ_MASK);
+}
+
+static void ts4800_irq_unmask(struct irq_data *d)
+{
+       struct ts4800_irq_data *data = irq_data_get_irq_chip_data(d);
+       u16 reg = readw(data->base + IRQ_MASK);
+       u16 mask = 1 << d->hwirq;
+
+       writew(reg & ~mask, data->base + IRQ_MASK);
+}
+
+static int ts4800_irqdomain_map(struct irq_domain *d, unsigned int irq,
+                               irq_hw_number_t hwirq)
+{
+       struct ts4800_irq_data *data = d->host_data;
+
+       irq_set_chip_and_handler(irq, &data->irq_chip, handle_simple_irq);
+       irq_set_chip_data(irq, data);
+       irq_set_noprobe(irq);
+
+       return 0;
+}
+
+struct irq_domain_ops ts4800_ic_ops = {
+       .map = ts4800_irqdomain_map,
+       .xlate = irq_domain_xlate_onecell,
+};
+
+static void ts4800_ic_chained_handle_irq(struct irq_desc *desc)
+{
+       struct ts4800_irq_data *data = irq_desc_get_handler_data(desc);
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       u16 status = readw(data->base + IRQ_STATUS);
+
+       chained_irq_enter(chip, desc);
+
+       if (unlikely(status == 0)) {
+               handle_bad_irq(desc);
+               goto out;
+       }
+
+       do {
+               unsigned int bit = __ffs(status);
+               int irq = irq_find_mapping(data->domain, bit);
+
+               status &= ~(1 << bit);
+               generic_handle_irq(irq);
+       } while (status);
+
+out:
+       chained_irq_exit(chip, desc);
+}
+
+static int ts4800_ic_probe(struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       struct ts4800_irq_data *data;
+       struct irq_chip *irq_chip;
+       struct resource *res;
+       int parent_irq;
+
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       data->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(data->base))
+               return PTR_ERR(data->base);
+
+       writew(0xFFFF, data->base + IRQ_MASK);
+
+       parent_irq = irq_of_parse_and_map(node, 0);
+       if (!parent_irq) {
+               dev_err(&pdev->dev, "failed to get parent IRQ\n");
+               return -EINVAL;
+       }
+
+       irq_chip = &data->irq_chip;
+       irq_chip->name = dev_name(&pdev->dev);
+       irq_chip->irq_mask = ts4800_irq_mask;
+       irq_chip->irq_unmask = ts4800_irq_unmask;
+
+       data->domain = irq_domain_add_linear(node, 8, &ts4800_ic_ops, data);
+       if (!data->domain) {
+               dev_err(&pdev->dev, "cannot add IRQ domain\n");
+               return -ENOMEM;
+       }
+
+       irq_set_chained_handler_and_data(parent_irq,
+                                        ts4800_ic_chained_handle_irq, data);
+
+       platform_set_drvdata(pdev, data);
+
+       return 0;
+}
+
+static int ts4800_ic_remove(struct platform_device *pdev)
+{
+       struct ts4800_irq_data *data = platform_get_drvdata(pdev);
+
+       irq_domain_remove(data->domain);
+
+       return 0;
+}
+
+static const struct of_device_id ts4800_ic_of_match[] = {
+       { .compatible = "technologic,ts4800-irqc", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ts4800_ic_of_match);
+
+static struct platform_driver ts4800_ic_driver = {
+       .probe  = ts4800_ic_probe,
+       .remove = ts4800_ic_remove,
+       .driver = {
+               .name = "ts4800-irqc",
+               .of_match_table = ts4800_ic_of_match,
+       },
+};
+module_platform_driver(ts4800_ic_driver);
+
+MODULE_AUTHOR("Damien Riegel <damien.riegel@savoirfairelinux.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ts4800_irqc");
index 4c48fa88a03d9b54651276cfe95a8fc2d5e287af..cb9d8ec375076ca5ddde0e708ba1a226c1e75d48 100644 (file)
@@ -43,8 +43,7 @@ static void __iomem *zevio_irq_io;
 static void zevio_irq_ack(struct irq_data *irqd)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(irqd);
-       struct irq_chip_regs *regs =
-               &container_of(irqd->chip, struct irq_chip_type, chip)->regs;
+       struct irq_chip_regs *regs = &irq_data_get_chip_type(irqd)->regs;
 
        readl(gc->reg_base + regs->ack);
 }
index b1ab8bdf82519b9da91c082198cf7acef6f61692..7f940c24a16b0d00163051acfda665b692733b5d 100644 (file)
@@ -52,6 +52,7 @@ config LEDS_AAT1290
 config LEDS_BCM6328
        tristate "LED Support for Broadcom BCM6328"
        depends on LEDS_CLASS
+       depends on HAS_IOMEM
        depends on OF
        help
          This option enables support for LEDs connected to the BCM6328
@@ -60,6 +61,7 @@ config LEDS_BCM6328
 config LEDS_BCM6358
        tristate "LED Support for Broadcom BCM6358"
        depends on LEDS_CLASS
+       depends on HAS_IOMEM
        depends on OF
        help
          This option enables support for LEDs connected to the BCM6358
index 3b2573411a379f8b26aa10bc968d3930dfa56e5f..cf398275a53cbc48ecbf3f49ec9017b26da27dbf 100644 (file)
@@ -108,7 +108,7 @@ static ssize_t flash_strobe_store(struct device *dev,
        if (ret)
                goto unlock;
 
-       if (state < 0 || state > 1) {
+       if (state > 1) {
                ret = -EINVAL;
                goto unlock;
        }
@@ -298,7 +298,7 @@ int led_classdev_flash_register(struct device *parent,
        led_cdev = &fled_cdev->led_cdev;
 
        if (led_cdev->flags & LED_DEV_CAP_FLASH) {
-               if (!led_cdev->brightness_set_sync)
+               if (!led_cdev->brightness_set_blocking)
                        return -EINVAL;
 
                ops = fled_cdev->ops;
@@ -316,10 +316,6 @@ int led_classdev_flash_register(struct device *parent,
        if (ret < 0)
                return ret;
 
-       /* Setting a torch brightness needs to have immediate effect */
-       led_cdev->flags &= ~SET_BRIGHTNESS_ASYNC;
-       led_cdev->flags |= SET_BRIGHTNESS_SYNC;
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(led_classdev_flash_register);
index 7385f98dd54b4b42cf7e430b94952150b979827b..14139c337312c574c82a98bee4c163834cad6bc5 100644 (file)
@@ -109,7 +109,7 @@ static const struct attribute_group *led_groups[] = {
 void led_classdev_suspend(struct led_classdev *led_cdev)
 {
        led_cdev->flags |= LED_SUSPENDED;
-       led_cdev->brightness_set(led_cdev, 0);
+       led_set_brightness_nopm(led_cdev, 0);
 }
 EXPORT_SYMBOL_GPL(led_classdev_suspend);
 
@@ -119,7 +119,7 @@ EXPORT_SYMBOL_GPL(led_classdev_suspend);
  */
 void led_classdev_resume(struct led_classdev *led_cdev)
 {
-       led_cdev->brightness_set(led_cdev, led_cdev->brightness);
+       led_set_brightness_nopm(led_cdev, led_cdev->brightness);
 
        if (led_cdev->flash_resume)
                led_cdev->flash_resume(led_cdev);
@@ -215,8 +215,6 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
        if (!led_cdev->max_brightness)
                led_cdev->max_brightness = LED_FULL;
 
-       led_cdev->flags |= SET_BRIGHTNESS_ASYNC;
-
        led_update_brightness(led_cdev);
 
        led_init_core(led_cdev);
@@ -247,12 +245,13 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
        up_write(&led_cdev->trigger_lock);
 #endif
 
-       cancel_work_sync(&led_cdev->set_brightness_work);
-
        /* Stop blinking */
        led_stop_software_blink(led_cdev);
+
        led_set_brightness(led_cdev, LED_OFF);
 
+       flush_work(&led_cdev->set_brightness_work);
+
        device_unregister(led_cdev->dev);
 
        down_write(&leds_list_lock);
index c1c3af089634cded4f27fd8e6397a9519025ad70..19e1e60dfaa354585ca01e2ffdc2a47f29c49c3b 100644 (file)
@@ -32,7 +32,7 @@ static void led_timer_function(unsigned long data)
        unsigned long delay;
 
        if (!led_cdev->blink_delay_on || !led_cdev->blink_delay_off) {
-               led_set_brightness_async(led_cdev, LED_OFF);
+               led_set_brightness_nosleep(led_cdev, LED_OFF);
                return;
        }
 
@@ -44,23 +44,23 @@ static void led_timer_function(unsigned long data)
        brightness = led_get_brightness(led_cdev);
        if (!brightness) {
                /* Time to switch the LED on. */
-               if (led_cdev->delayed_set_value) {
-                       led_cdev->blink_brightness =
-                                       led_cdev->delayed_set_value;
-                       led_cdev->delayed_set_value = 0;
-               }
                brightness = led_cdev->blink_brightness;
                delay = led_cdev->blink_delay_on;
        } else {
                /* Store the current brightness value to be able
                 * to restore it when the delay_off period is over.
+                * Do it only if there is no pending blink brightness
+                * change, to avoid overwriting the new value.
                 */
-               led_cdev->blink_brightness = brightness;
+               if (!(led_cdev->flags & LED_BLINK_BRIGHTNESS_CHANGE))
+                       led_cdev->blink_brightness = brightness;
+               else
+                       led_cdev->flags &= ~LED_BLINK_BRIGHTNESS_CHANGE;
                brightness = LED_OFF;
                delay = led_cdev->blink_delay_off;
        }
 
-       led_set_brightness_async(led_cdev, brightness);
+       led_set_brightness_nosleep(led_cdev, brightness);
 
        /* Return in next iteration if led is in one-shot mode and we are in
         * the final blink state so that the led is toggled each delay_on +
@@ -83,10 +83,24 @@ static void set_brightness_delayed(struct work_struct *ws)
 {
        struct led_classdev *led_cdev =
                container_of(ws, struct led_classdev, set_brightness_work);
+       int ret = 0;
 
-       led_stop_software_blink(led_cdev);
+       if (led_cdev->flags & LED_BLINK_DISABLE) {
+               led_cdev->delayed_set_value = LED_OFF;
+               led_stop_software_blink(led_cdev);
+               led_cdev->flags &= ~LED_BLINK_DISABLE;
+       }
 
-       led_set_brightness_async(led_cdev, led_cdev->delayed_set_value);
+       if (led_cdev->brightness_set)
+               led_cdev->brightness_set(led_cdev, led_cdev->delayed_set_value);
+       else if (led_cdev->brightness_set_blocking)
+               ret = led_cdev->brightness_set_blocking(led_cdev,
+                                               led_cdev->delayed_set_value);
+       else
+               ret = -ENOTSUPP;
+       if (ret < 0)
+               dev_err(led_cdev->dev,
+                       "Setting an LED's brightness failed (%d)\n", ret);
 }
 
 static void led_set_software_blink(struct led_classdev *led_cdev,
@@ -106,13 +120,14 @@ static void led_set_software_blink(struct led_classdev *led_cdev,
 
        /* never on - just set to off */
        if (!delay_on) {
-               led_set_brightness_async(led_cdev, LED_OFF);
+               led_set_brightness_nosleep(led_cdev, LED_OFF);
                return;
        }
 
        /* never off - just set to brightness */
        if (!delay_off) {
-               led_set_brightness_async(led_cdev, led_cdev->blink_brightness);
+               led_set_brightness_nosleep(led_cdev,
+                                          led_cdev->blink_brightness);
                return;
        }
 
@@ -156,7 +171,7 @@ void led_blink_set(struct led_classdev *led_cdev,
 
        led_blink_setup(led_cdev, delay_on, delay_off);
 }
-EXPORT_SYMBOL(led_blink_set);
+EXPORT_SYMBOL_GPL(led_blink_set);
 
 void led_blink_set_oneshot(struct led_classdev *led_cdev,
                           unsigned long *delay_on,
@@ -177,7 +192,7 @@ void led_blink_set_oneshot(struct led_classdev *led_cdev,
 
        led_blink_setup(led_cdev, delay_on, delay_off);
 }
-EXPORT_SYMBOL(led_blink_set_oneshot);
+EXPORT_SYMBOL_GPL(led_blink_set_oneshot);
 
 void led_stop_software_blink(struct led_classdev *led_cdev)
 {
@@ -190,29 +205,74 @@ EXPORT_SYMBOL_GPL(led_stop_software_blink);
 void led_set_brightness(struct led_classdev *led_cdev,
                        enum led_brightness brightness)
 {
-       int ret = 0;
-
-       /* delay brightness if soft-blink is active */
+       /*
+        * In case blinking is on delay brightness setting
+        * until the next timer tick.
+        */
        if (led_cdev->blink_delay_on || led_cdev->blink_delay_off) {
-               led_cdev->delayed_set_value = brightness;
-               if (brightness == LED_OFF)
+               /*
+                * If we need to disable soft blinking delegate this to the
+                * work queue task to avoid problems in case we are called
+                * from hard irq context.
+                */
+               if (brightness == LED_OFF) {
+                       led_cdev->flags |= LED_BLINK_DISABLE;
                        schedule_work(&led_cdev->set_brightness_work);
+               } else {
+                       led_cdev->flags |= LED_BLINK_BRIGHTNESS_CHANGE;
+                       led_cdev->blink_brightness = brightness;
+               }
                return;
        }
 
-       if (led_cdev->flags & SET_BRIGHTNESS_ASYNC) {
-               led_set_brightness_async(led_cdev, brightness);
+       led_set_brightness_nosleep(led_cdev, brightness);
+}
+EXPORT_SYMBOL_GPL(led_set_brightness);
+
+void led_set_brightness_nopm(struct led_classdev *led_cdev,
+                             enum led_brightness value)
+{
+       /* Use brightness_set op if available, it is guaranteed not to sleep */
+       if (led_cdev->brightness_set) {
+               led_cdev->brightness_set(led_cdev, value);
                return;
-       } else if (led_cdev->flags & SET_BRIGHTNESS_SYNC)
-               ret = led_set_brightness_sync(led_cdev, brightness);
-       else
-               ret = -EINVAL;
+       }
 
-       if (ret < 0)
-               dev_dbg(led_cdev->dev, "Setting LED brightness failed (%d)\n",
-                       ret);
+       /* If brightness setting can sleep, delegate it to a work queue task */
+       led_cdev->delayed_set_value = value;
+       schedule_work(&led_cdev->set_brightness_work);
+}
+EXPORT_SYMBOL_GPL(led_set_brightness_nopm);
+
+void led_set_brightness_nosleep(struct led_classdev *led_cdev,
+                               enum led_brightness value)
+{
+       led_cdev->brightness = min(value, led_cdev->max_brightness);
+
+       if (led_cdev->flags & LED_SUSPENDED)
+               return;
+
+       led_set_brightness_nopm(led_cdev, led_cdev->brightness);
+}
+EXPORT_SYMBOL_GPL(led_set_brightness_nosleep);
+
+int led_set_brightness_sync(struct led_classdev *led_cdev,
+                           enum led_brightness value)
+{
+       if (led_cdev->blink_delay_on || led_cdev->blink_delay_off)
+               return -EBUSY;
+
+       led_cdev->brightness = min(value, led_cdev->max_brightness);
+
+       if (led_cdev->flags & LED_SUSPENDED)
+               return 0;
+
+       if (led_cdev->brightness_set_blocking)
+               return led_cdev->brightness_set_blocking(led_cdev,
+                                                        led_cdev->brightness);
+       return -ENOTSUPP;
 }
-EXPORT_SYMBOL(led_set_brightness);
+EXPORT_SYMBOL_GPL(led_set_brightness_sync);
 
 int led_update_brightness(struct led_classdev *led_cdev)
 {
@@ -228,7 +288,7 @@ int led_update_brightness(struct led_classdev *led_cdev)
 
        return ret;
 }
-EXPORT_SYMBOL(led_update_brightness);
+EXPORT_SYMBOL_GPL(led_update_brightness);
 
 /* Caller must ensure led_cdev->led_access held */
 void led_sysfs_disable(struct led_classdev *led_cdev)
index e8b1120f486d6de7289f77e378b0e2ad14e3712d..e1e933424ac9a4366a223eeb7e8ca13d4d9290e3 100644 (file)
@@ -249,6 +249,34 @@ void led_trigger_unregister(struct led_trigger *trig)
 }
 EXPORT_SYMBOL_GPL(led_trigger_unregister);
 
+static void devm_led_trigger_release(struct device *dev, void *res)
+{
+       led_trigger_unregister(*(struct led_trigger **)res);
+}
+
+int devm_led_trigger_register(struct device *dev,
+                             struct led_trigger *trig)
+{
+       struct led_trigger **dr;
+       int rc;
+
+       dr = devres_alloc(devm_led_trigger_release, sizeof(*dr),
+                         GFP_KERNEL);
+       if (!dr)
+               return -ENOMEM;
+
+       *dr = trig;
+
+       rc = led_trigger_register(trig);
+       if (rc)
+               devres_free(dr);
+       else
+               devres_add(dev, dr);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(devm_led_trigger_register);
+
 /* Simple LED Tigger Interface */
 
 void led_trigger_event(struct led_trigger *trig,
index 7870840e7cc9a43543ab72262082bce05e150c11..1ad4d03a0a3ceca894ae1b1ffdc8212d1558165d 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/i2c.h>
 #include <linux/leds.h>
 #include <linux/slab.h>
-#include <linux/workqueue.h>
 #include <linux/mfd/88pm860x.h>
 #include <linux/module.h>
 
@@ -33,7 +32,6 @@
 struct pm860x_led {
        struct led_classdev cdev;
        struct i2c_client *i2c;
-       struct work_struct work;
        struct pm860x_chip *chip;
        struct mutex lock;
        char name[MFD_NAME_SIZE];
@@ -69,17 +67,18 @@ static int led_power_set(struct pm860x_chip *chip, int port, int on)
        return ret;
 }
 
-static void pm860x_led_work(struct work_struct *work)
+static int pm860x_led_set(struct led_classdev *cdev,
+                          enum led_brightness value)
 {
-
-       struct pm860x_led *led;
+       struct pm860x_led *led = container_of(cdev, struct pm860x_led, cdev);
        struct pm860x_chip *chip;
        unsigned char buf[3];
        int ret;
 
-       led = container_of(work, struct pm860x_led, work);
        chip = led->chip;
        mutex_lock(&led->lock);
+       led->brightness = value >> 3;
+
        if ((led->current_brightness == 0) && led->brightness) {
                led_power_set(chip, led->port, 1);
                if (led->iset) {
@@ -112,15 +111,8 @@ static void pm860x_led_work(struct work_struct *work)
        dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n",
                led->reg_control, led->brightness);
        mutex_unlock(&led->lock);
-}
 
-static void pm860x_led_set(struct led_classdev *cdev,
-                          enum led_brightness value)
-{
-       struct pm860x_led *data = container_of(cdev, struct pm860x_led, cdev);
-
-       data->brightness = value >> 3;
-       schedule_work(&data->work);
+       return 0;
 }
 
 #ifdef CONFIG_OF
@@ -213,9 +205,8 @@ static int pm860x_led_probe(struct platform_device *pdev)
 
        data->current_brightness = 0;
        data->cdev.name = data->name;
-       data->cdev.brightness_set = pm860x_led_set;
+       data->cdev.brightness_set_blocking = pm860x_led_set;
        mutex_init(&data->lock);
-       INIT_WORK(&data->work, pm860x_led_work);
 
        ret = led_classdev_register(chip->dev, &data->cdev);
        if (ret < 0) {
index ac77d36b630cda0b32dbcd312e97d461192b8ecc..def3cf9f7e9287d630ea5d9712a8323225b9b7a1 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
-#include <linux/workqueue.h>
 #include <media/v4l2-flash-led-class.h>
 
 #define AAT1290_MOVIE_MODE_CURRENT_ADDR        17
@@ -82,8 +81,6 @@ struct aat1290_led {
 
        /* brightness cache */
        unsigned int torch_brightness;
-       /* assures led-triggers compatibility */
-       struct work_struct work_brightness_set;
 };
 
 static struct aat1290_led *fled_cdev_to_led(
@@ -92,6 +89,12 @@ static struct aat1290_led *fled_cdev_to_led(
        return container_of(fled_cdev, struct aat1290_led, fled_cdev);
 }
 
+static struct led_classdev_flash *led_cdev_to_fled_cdev(
+                               struct led_classdev *led_cdev)
+{
+       return container_of(led_cdev, struct led_classdev_flash, led_cdev);
+}
+
 static void aat1290_as2cwire_write(struct aat1290_led *led, int addr, int value)
 {
        int i;
@@ -134,9 +137,14 @@ static void aat1290_set_flash_safety_timer(struct aat1290_led *led,
                                                        flash_tm_reg);
 }
 
-static void aat1290_brightness_set(struct aat1290_led *led,
+/* LED subsystem callbacks */
+
+static int aat1290_led_brightness_set(struct led_classdev *led_cdev,
                                        enum led_brightness brightness)
 {
+       struct led_classdev_flash *fled_cdev = led_cdev_to_fled_cdev(led_cdev);
+       struct aat1290_led *led = fled_cdev_to_led(fled_cdev);
+
        mutex_lock(&led->lock);
 
        if (brightness == 0) {
@@ -158,35 +166,6 @@ static void aat1290_brightness_set(struct aat1290_led *led,
        }
 
        mutex_unlock(&led->lock);
-}
-
-/* LED subsystem callbacks */
-
-static void aat1290_brightness_set_work(struct work_struct *work)
-{
-       struct aat1290_led *led =
-               container_of(work, struct aat1290_led, work_brightness_set);
-
-       aat1290_brightness_set(led, led->torch_brightness);
-}
-
-static void aat1290_led_brightness_set(struct led_classdev *led_cdev,
-                                       enum led_brightness brightness)
-{
-       struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
-       struct aat1290_led *led = fled_cdev_to_led(fled_cdev);
-
-       led->torch_brightness = brightness;
-       schedule_work(&led->work_brightness_set);
-}
-
-static int aat1290_led_brightness_set_sync(struct led_classdev *led_cdev,
-                                       enum led_brightness brightness)
-{
-       struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
-       struct aat1290_led *led = fled_cdev_to_led(fled_cdev);
-
-       aat1290_brightness_set(led, brightness);
 
        return 0;
 }
@@ -296,7 +275,7 @@ static int aat1290_led_parse_dt(struct aat1290_led *led,
        if (ret < 0) {
                dev_err(dev,
                        "flash-max-microamp DT property missing\n");
-               return ret;
+               goto err_parse_dt;
        }
 
        ret = of_property_read_u32(child_node, "flash-max-timeout-us",
@@ -304,13 +283,14 @@ static int aat1290_led_parse_dt(struct aat1290_led *led,
        if (ret < 0) {
                dev_err(dev,
                        "flash-max-timeout-us DT property missing\n");
-               return ret;
+               goto err_parse_dt;
        }
 
-       of_node_put(child_node);
-
        *sub_node = child_node;
 
+err_parse_dt:
+       of_node_put(child_node);
+
        return ret;
 }
 
@@ -509,11 +489,9 @@ static int aat1290_led_probe(struct platform_device *pdev)
        mutex_init(&led->lock);
 
        /* Initialize LED Flash class device */
-       led_cdev->brightness_set = aat1290_led_brightness_set;
-       led_cdev->brightness_set_sync = aat1290_led_brightness_set_sync;
+       led_cdev->brightness_set_blocking = aat1290_led_brightness_set;
        led_cdev->max_brightness = led_cfg.max_brightness;
        led_cdev->flags |= LED_DEV_CAP_FLASH;
-       INIT_WORK(&led->work_brightness_set, aat1290_brightness_set_work);
 
        aat1290_init_flash_timeout(led, &led_cfg);
 
@@ -548,7 +526,6 @@ static int aat1290_led_remove(struct platform_device *pdev)
 
        v4l2_flash_release(led->v4l2_flash);
        led_classdev_flash_unregister(&led->fled_cdev);
-       cancel_work_sync(&led->work_brightness_set);
 
        mutex_destroy(&led->lock);
 
index 07e66cae32d37f08f1911bc6751ef67caec6af7e..853b2d3bdb1731fbd903fe468ddf3f370ac4c156 100644 (file)
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
-#include <linux/workqueue.h>
 #include <linux/mfd/adp5520.h>
 #include <linux/slab.h>
 
 struct adp5520_led {
        struct led_classdev     cdev;
-       struct work_struct      work;
        struct device           *master;
-       enum led_brightness     new_brightness;
        int                     id;
        int                     flags;
 };
 
-static void adp5520_led_work(struct work_struct *work)
-{
-       struct adp5520_led *led = container_of(work, struct adp5520_led, work);
-       adp5520_write(led->master, ADP5520_LED1_CURRENT + led->id - 1,
-                        led->new_brightness >> 2);
-}
-
-static void adp5520_led_set(struct led_classdev *led_cdev,
+static int adp5520_led_set(struct led_classdev *led_cdev,
                           enum led_brightness value)
 {
        struct adp5520_led *led;
 
        led = container_of(led_cdev, struct adp5520_led, cdev);
-       led->new_brightness = value;
-       schedule_work(&led->work);
+       return adp5520_write(led->master, ADP5520_LED1_CURRENT + led->id - 1,
+                        value >> 2);
 }
 
 static int adp5520_led_setup(struct adp5520_led *led)
@@ -135,7 +125,7 @@ static int adp5520_led_probe(struct platform_device *pdev)
 
                led_dat->cdev.name = cur_led->name;
                led_dat->cdev.default_trigger = cur_led->default_trigger;
-               led_dat->cdev.brightness_set = adp5520_led_set;
+               led_dat->cdev.brightness_set_blocking = adp5520_led_set;
                led_dat->cdev.brightness = LED_OFF;
 
                if (cur_led->flags & ADP5520_FLAG_LED_MASK)
@@ -146,9 +136,6 @@ static int adp5520_led_probe(struct platform_device *pdev)
                led_dat->id = led_dat->flags & ADP5520_FLAG_LED_MASK;
 
                led_dat->master = pdev->dev.parent;
-               led_dat->new_brightness = LED_OFF;
-
-               INIT_WORK(&led_dat->work, adp5520_led_work);
 
                ret = led_classdev_register(led_dat->master, &led_dat->cdev);
                if (ret) {
@@ -170,10 +157,8 @@ static int adp5520_led_probe(struct platform_device *pdev)
 
 err:
        if (i > 0) {
-               for (i = i - 1; i >= 0; i--) {
+               for (i = i - 1; i >= 0; i--)
                        led_classdev_unregister(&led[i].cdev);
-                       cancel_work_sync(&led[i].work);
-               }
        }
 
        return ret;
@@ -192,7 +177,6 @@ static int adp5520_led_remove(struct platform_device *pdev)
 
        for (i = 0; i < pdata->num_leds; i++) {
                led_classdev_unregister(&led[i].cdev);
-               cancel_work_sync(&led[i].work);
        }
 
        return 0;
index c7ea5c62633186294eff8046dba51c8865d06eab..1548259297c185e8cfefb4f6df7127b97755da2b 100644 (file)
 #define BCM6328_LED_SHIFT_TEST         BIT(30)
 #define BCM6328_LED_TEST               BIT(31)
 #define BCM6328_INIT_MASK              (BCM6328_SERIAL_LED_EN | \
-                                        BCM6328_SERIAL_LED_MUX  | \
+                                        BCM6328_SERIAL_LED_MUX | \
                                         BCM6328_SERIAL_LED_CLK_NPOL | \
                                         BCM6328_SERIAL_LED_DATA_PPOL | \
                                         BCM6328_SERIAL_LED_SHIFT_DIR)
 
 #define BCM6328_LED_MODE_MASK          3
-#define BCM6328_LED_MODE_OFF           0
+#define BCM6328_LED_MODE_O           0
 #define BCM6328_LED_MODE_FAST          1
 #define BCM6328_LED_MODE_BLINK         2
-#define BCM6328_LED_MODE_O           3
+#define BCM6328_LED_MODE_OFF           3
 #define BCM6328_LED_SHIFT(X)           ((X) << 1)
 
 /**
@@ -76,12 +76,20 @@ struct bcm6328_led {
 
 static void bcm6328_led_write(void __iomem *reg, unsigned long data)
 {
+#ifdef CONFIG_CPU_BIG_ENDIAN
        iowrite32be(data, reg);
+#else
+       writel(data, reg);
+#endif
 }
 
 static unsigned long bcm6328_led_read(void __iomem *reg)
 {
+#ifdef CONFIG_CPU_BIG_ENDIAN
        return ioread32be(reg);
+#else
+       return readl(reg);
+#endif
 }
 
 /**
@@ -126,34 +134,45 @@ static void bcm6328_led_set(struct led_classdev *led_cdev,
        *(led->blink_leds) &= ~BIT(led->pin);
        if ((led->active_low && value == LED_OFF) ||
            (!led->active_low && value != LED_OFF))
-               bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
-       else
                bcm6328_led_mode(led, BCM6328_LED_MODE_ON);
+       else
+               bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
        spin_unlock_irqrestore(led->lock, flags);
 }
 
+static unsigned long bcm6328_blink_delay(unsigned long delay)
+{
+       unsigned long bcm6328_delay;
+
+       bcm6328_delay = delay + BCM6328_LED_INTERVAL_MS / 2;
+       bcm6328_delay = bcm6328_delay / BCM6328_LED_INTERVAL_MS;
+       if (bcm6328_delay == 0)
+               bcm6328_delay = 1;
+
+       return bcm6328_delay;
+}
+
 static int bcm6328_blink_set(struct led_classdev *led_cdev,
                             unsigned long *delay_on, unsigned long *delay_off)
 {
        struct bcm6328_led *led =
                container_of(led_cdev, struct bcm6328_led, cdev);
        unsigned long delay, flags;
+       int rc;
 
        if (!*delay_on)
                *delay_on = BCM6328_LED_DEF_DELAY;
        if (!*delay_off)
                *delay_off = BCM6328_LED_DEF_DELAY;
 
-       if (*delay_on != *delay_off) {
+       delay = bcm6328_blink_delay(*delay_on);
+       if (delay != bcm6328_blink_delay(*delay_off)) {
                dev_dbg(led_cdev->dev,
                        "fallback to soft blinking (delay_on != delay_off)\n");
                return -EINVAL;
        }
 
-       delay = *delay_on / BCM6328_LED_INTERVAL_MS;
-       if (delay == 0)
-               delay = 1;
-       else if (delay > BCM6328_LED_INTV_MASK) {
+       if (delay > BCM6328_LED_INTV_MASK) {
                dev_dbg(led_cdev->dev,
                        "fallback to soft blinking (delay > %ums)\n",
                        BCM6328_LED_INTV_MASK * BCM6328_LED_INTERVAL_MS);
@@ -175,16 +194,15 @@ static int bcm6328_blink_set(struct led_classdev *led_cdev,
                bcm6328_led_write(led->mem + BCM6328_REG_INIT, val);
 
                bcm6328_led_mode(led, BCM6328_LED_MODE_BLINK);
-
-               spin_unlock_irqrestore(led->lock, flags);
+               rc = 0;
        } else {
-               spin_unlock_irqrestore(led->lock, flags);
                dev_dbg(led_cdev->dev,
                        "fallback to soft blinking (delay already set)\n");
-               return -EINVAL;
+               rc = -EINVAL;
        }
+       spin_unlock_irqrestore(led->lock, flags);
 
-       return 0;
+       return rc;
 }
 
 static int bcm6328_hwled(struct device *dev, struct device_node *nc, u32 reg,
@@ -264,7 +282,6 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
                       unsigned long *blink_leds, unsigned long *blink_delay)
 {
        struct bcm6328_led *led;
-       unsigned long flags;
        const char *state;
        int rc;
 
@@ -286,7 +303,6 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
                                                    "linux,default-trigger",
                                                    NULL);
 
-       spin_lock_irqsave(lock, flags);
        if (!of_property_read_string(nc, "default-state", &state)) {
                if (!strcmp(state, "on")) {
                        led->cdev.brightness = LED_FULL;
@@ -303,8 +319,8 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
                        val = bcm6328_led_read(mode) >>
                              BCM6328_LED_SHIFT(shift % 16);
                        val &= BCM6328_LED_MODE_MASK;
-                       if ((led->active_low && val == BCM6328_LED_MODE_ON) ||
-                           (!led->active_low && val == BCM6328_LED_MODE_OFF))
+                       if ((led->active_low && val == BCM6328_LED_MODE_OFF) ||
+                           (!led->active_low && val == BCM6328_LED_MODE_ON))
                                led->cdev.brightness = LED_FULL;
                        else
                                led->cdev.brightness = LED_OFF;
@@ -315,12 +331,7 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
                led->cdev.brightness = LED_OFF;
        }
 
-       if ((led->active_low && led->cdev.brightness == LED_FULL) ||
-           (!led->active_low && led->cdev.brightness == LED_OFF))
-               bcm6328_led_mode(led, BCM6328_LED_MODE_ON);
-       else
-               bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
-       spin_unlock_irqrestore(lock, flags);
+       bcm6328_led_set(&led->cdev, led->cdev.brightness);
 
        led->cdev.brightness_set = bcm6328_led_set;
        led->cdev.blink_set = bcm6328_blink_set;
@@ -341,7 +352,7 @@ static int bcm6328_leds_probe(struct platform_device *pdev)
        struct device_node *child;
        struct resource *mem_r;
        void __iomem *mem;
-       spinlock_t *lock;
+       spinlock_t *lock; /* memory lock */
        unsigned long val, *blink_leds, *blink_delay;
 
        mem_r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
index 82b4ee1bc87e03e3df18fe5e044270c0996b18a5..b2cc06618abed309beaa7b0533cdb8b5b0762ff9 100644 (file)
@@ -49,12 +49,20 @@ struct bcm6358_led {
 
 static void bcm6358_led_write(void __iomem *reg, unsigned long data)
 {
+#ifdef CONFIG_CPU_BIG_ENDIAN
        iowrite32be(data, reg);
+#else
+       writel(data, reg);
+#endif
 }
 
 static unsigned long bcm6358_led_read(void __iomem *reg)
 {
+#ifdef CONFIG_CPU_BIG_ENDIAN
        return ioread32be(reg);
+#else
+       return readl(reg);
+#endif
 }
 
 static unsigned long bcm6358_led_busy(void __iomem *mem)
@@ -68,12 +76,15 @@ static unsigned long bcm6358_led_busy(void __iomem *mem)
        return val;
 }
 
-static void bcm6358_led_mode(struct bcm6358_led *led, unsigned long value)
+static void bcm6358_led_set(struct led_classdev *led_cdev,
+                           enum led_brightness value)
 {
-       unsigned long val;
+       struct bcm6358_led *led =
+               container_of(led_cdev, struct bcm6358_led, cdev);
+       unsigned long flags, val;
 
+       spin_lock_irqsave(led->lock, flags);
        bcm6358_led_busy(led->mem);
-
        val = bcm6358_led_read(led->mem + BCM6358_REG_MODE);
        if ((led->active_low && value == LED_OFF) ||
            (!led->active_low && value != LED_OFF))
@@ -81,17 +92,6 @@ static void bcm6358_led_mode(struct bcm6358_led *led, unsigned long value)
        else
                val &= ~(BIT(led->pin));
        bcm6358_led_write(led->mem + BCM6358_REG_MODE, val);
-}
-
-static void bcm6358_led_set(struct led_classdev *led_cdev,
-                           enum led_brightness value)
-{
-       struct bcm6358_led *led =
-               container_of(led_cdev, struct bcm6358_led, cdev);
-       unsigned long flags;
-
-       spin_lock_irqsave(led->lock, flags);
-       bcm6358_led_mode(led, value);
        spin_unlock_irqrestore(led->lock, flags);
 }
 
@@ -99,7 +99,6 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
                       void __iomem *mem, spinlock_t *lock)
 {
        struct bcm6358_led *led;
-       unsigned long flags;
        const char *state;
        int rc;
 
@@ -119,15 +118,11 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
                                                    "linux,default-trigger",
                                                    NULL);
 
-       spin_lock_irqsave(lock, flags);
        if (!of_property_read_string(nc, "default-state", &state)) {
                if (!strcmp(state, "on")) {
                        led->cdev.brightness = LED_FULL;
                } else if (!strcmp(state, "keep")) {
                        unsigned long val;
-
-                       bcm6358_led_busy(led->mem);
-
                        val = bcm6358_led_read(led->mem + BCM6358_REG_MODE);
                        val &= BIT(led->pin);
                        if ((led->active_low && !val) ||
@@ -141,8 +136,8 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
        } else {
                led->cdev.brightness = LED_OFF;
        }
-       bcm6358_led_mode(led, led->cdev.brightness);
-       spin_unlock_irqrestore(lock, flags);
+
+       bcm6358_led_set(&led->cdev, led->cdev.brightness);
 
        led->cdev.brightness_set = bcm6358_led_set;
 
index 6078c15d3452df77da066ec2f3d00bc805c02fa0..6b4de762a760857da3b22ba5feeaf9a49dee5c56 100644 (file)
@@ -72,7 +72,6 @@ struct bd2802_led {
        struct bd2802_led_platform_data *pdata;
        struct i2c_client               *client;
        struct rw_semaphore             rwsem;
-       struct work_struct              work;
 
        struct led_state                led[2];
 
@@ -518,29 +517,22 @@ static struct device_attribute *bd2802_attributes[] = {
        &bd2802_rgb_current_attr,
 };
 
-static void bd2802_led_work(struct work_struct *work)
-{
-       struct bd2802_led *led = container_of(work, struct bd2802_led, work);
-
-       if (led->state)
-               bd2802_turn_on(led, led->led_id, led->color, led->state);
-       else
-               bd2802_turn_off(led, led->led_id, led->color);
-}
-
 #define BD2802_CONTROL_RGBS(name, id, clr)                             \
-static void bd2802_set_##name##_brightness(struct led_classdev *led_cdev,\
+static int bd2802_set_##name##_brightness(struct led_classdev *led_cdev,\
                                        enum led_brightness value)      \
 {                                                                      \
        struct bd2802_led *led =                                        \
                container_of(led_cdev, struct bd2802_led, cdev_##name); \
        led->led_id = id;                                               \
        led->color = clr;                                               \
-       if (value == LED_OFF)                                           \
+       if (value == LED_OFF) {                                         \
                led->state = BD2802_OFF;                                \
-       else                                                            \
+               bd2802_turn_off(led, led->led_id, led->color);          \
+       } else {                                                        \
                led->state = BD2802_ON;                                 \
-       schedule_work(&led->work);                                      \
+               bd2802_turn_on(led, led->led_id, led->color, BD2802_ON);\
+       }                                                               \
+       return 0;                                                       \
 }                                                                      \
 static int bd2802_set_##name##_blink(struct led_classdev *led_cdev,    \
                unsigned long *delay_on, unsigned long *delay_off)      \
@@ -552,7 +544,7 @@ static int bd2802_set_##name##_blink(struct led_classdev *led_cdev, \
        led->led_id = id;                                               \
        led->color = clr;                                               \
        led->state = BD2802_BLINK;                                      \
-       schedule_work(&led->work);                                      \
+       bd2802_turn_on(led, led->led_id, led->color, BD2802_BLINK);     \
        return 0;                                                       \
 }
 
@@ -567,11 +559,9 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
 {
        int ret;
 
-       INIT_WORK(&led->work, bd2802_led_work);
-
        led->cdev_led1r.name = "led1_R";
        led->cdev_led1r.brightness = LED_OFF;
-       led->cdev_led1r.brightness_set = bd2802_set_led1r_brightness;
+       led->cdev_led1r.brightness_set_blocking = bd2802_set_led1r_brightness;
        led->cdev_led1r.blink_set = bd2802_set_led1r_blink;
 
        ret = led_classdev_register(&led->client->dev, &led->cdev_led1r);
@@ -583,7 +573,7 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
 
        led->cdev_led1g.name = "led1_G";
        led->cdev_led1g.brightness = LED_OFF;
-       led->cdev_led1g.brightness_set = bd2802_set_led1g_brightness;
+       led->cdev_led1g.brightness_set_blocking = bd2802_set_led1g_brightness;
        led->cdev_led1g.blink_set = bd2802_set_led1g_blink;
 
        ret = led_classdev_register(&led->client->dev, &led->cdev_led1g);
@@ -595,7 +585,7 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
 
        led->cdev_led1b.name = "led1_B";
        led->cdev_led1b.brightness = LED_OFF;
-       led->cdev_led1b.brightness_set = bd2802_set_led1b_brightness;
+       led->cdev_led1b.brightness_set_blocking = bd2802_set_led1b_brightness;
        led->cdev_led1b.blink_set = bd2802_set_led1b_blink;
 
        ret = led_classdev_register(&led->client->dev, &led->cdev_led1b);
@@ -607,7 +597,7 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
 
        led->cdev_led2r.name = "led2_R";
        led->cdev_led2r.brightness = LED_OFF;
-       led->cdev_led2r.brightness_set = bd2802_set_led2r_brightness;
+       led->cdev_led2r.brightness_set_blocking = bd2802_set_led2r_brightness;
        led->cdev_led2r.blink_set = bd2802_set_led2r_blink;
 
        ret = led_classdev_register(&led->client->dev, &led->cdev_led2r);
@@ -619,7 +609,7 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
 
        led->cdev_led2g.name = "led2_G";
        led->cdev_led2g.brightness = LED_OFF;
-       led->cdev_led2g.brightness_set = bd2802_set_led2g_brightness;
+       led->cdev_led2g.brightness_set_blocking = bd2802_set_led2g_brightness;
        led->cdev_led2g.blink_set = bd2802_set_led2g_blink;
 
        ret = led_classdev_register(&led->client->dev, &led->cdev_led2g);
@@ -631,7 +621,7 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
 
        led->cdev_led2b.name = "led2_B";
        led->cdev_led2b.brightness = LED_OFF;
-       led->cdev_led2b.brightness_set = bd2802_set_led2b_brightness;
+       led->cdev_led2b.brightness_set_blocking = bd2802_set_led2b_brightness;
        led->cdev_led2b.blink_set = bd2802_set_led2b_blink;
        led->cdev_led2b.flags |= LED_CORE_SUSPENDRESUME;
 
@@ -661,7 +651,6 @@ failed_unregister_led1_R:
 
 static void bd2802_unregister_led_classdev(struct bd2802_led *led)
 {
-       cancel_work_sync(&led->work);
        led_classdev_unregister(&led->cdev_led2b);
        led_classdev_unregister(&led->cdev_led2g);
        led_classdev_unregister(&led->cdev_led2r);
index d0452b099aee1512bd70ed152de1085227ad9c8e..617fe975bf6ecfb1d8dd473ef98d19ef6e6abaaa 100644 (file)
@@ -39,16 +39,9 @@ struct blinkm_led {
        struct i2c_client *i2c_client;
        struct led_classdev led_cdev;
        int id;
-       atomic_t active;
-};
-
-struct blinkm_work {
-       struct blinkm_led *blinkm_led;
-       struct work_struct work;
 };
 
 #define cdev_to_blmled(c)          container_of(c, struct blinkm_led, led_cdev)
-#define work_to_blmwork(c)         container_of(c, struct blinkm_work, work)
 
 struct blinkm_data {
        struct i2c_client *i2c_client;
@@ -439,65 +432,30 @@ static int blinkm_transfer_hw(struct i2c_client *client, int cmd)
        return 0;
 }
 
-static void led_work(struct work_struct *work)
-{
-       int ret;
-       struct blinkm_led *led;
-       struct blinkm_data *data;
-       struct blinkm_work *blm_work = work_to_blmwork(work);
-
-       led = blm_work->blinkm_led;
-       data = i2c_get_clientdata(led->i2c_client);
-       ret = blinkm_transfer_hw(led->i2c_client, BLM_GO_RGB);
-       atomic_dec(&led->active);
-       dev_dbg(&led->i2c_client->dev,
-                       "# DONE # next_red = %d, next_green = %d,"
-                       " next_blue = %d, active = %d\n",
-                       data->next_red, data->next_green,
-                       data->next_blue, atomic_read(&led->active));
-       kfree(blm_work);
-}
-
 static int blinkm_led_common_set(struct led_classdev *led_cdev,
                                 enum led_brightness value, int color)
 {
        /* led_brightness is 0, 127 or 255 - we just use it here as-is */
        struct blinkm_led *led = cdev_to_blmled(led_cdev);
        struct blinkm_data *data = i2c_get_clientdata(led->i2c_client);
-       struct blinkm_work *bl_work;
 
        switch (color) {
        case RED:
                /* bail out if there's no change */
                if (data->next_red == (u8) value)
                        return 0;
-               /* we assume a quite fast sequence here ([off]->on->off)
-                * think of network led trigger - we cannot blink that fast, so
-                * in case we already have a off->on->off transition queued up,
-                * we refuse to queue up more.
-                * Revisit: fast-changing brightness. */
-               if (atomic_read(&led->active) > 1)
-                       return 0;
                data->next_red = (u8) value;
                break;
        case GREEN:
                /* bail out if there's no change */
                if (data->next_green == (u8) value)
                        return 0;
-               /* we assume a quite fast sequence here ([off]->on->off)
-                * Revisit: fast-changing brightness. */
-               if (atomic_read(&led->active) > 1)
-                       return 0;
                data->next_green = (u8) value;
                break;
        case BLUE:
                /* bail out if there's no change */
                if (data->next_blue == (u8) value)
                        return 0;
-               /* we assume a quite fast sequence here ([off]->on->off)
-                * Revisit: fast-changing brightness. */
-               if (atomic_read(&led->active) > 1)
-                       return 0;
                data->next_blue = (u8) value;
                break;
 
@@ -506,42 +464,31 @@ static int blinkm_led_common_set(struct led_classdev *led_cdev,
                return -EINVAL;
        }
 
-       bl_work = kzalloc(sizeof(*bl_work), GFP_ATOMIC);
-       if (!bl_work)
-               return -ENOMEM;
-
-       atomic_inc(&led->active);
+       blinkm_transfer_hw(led->i2c_client, BLM_GO_RGB);
        dev_dbg(&led->i2c_client->dev,
-                       "#TO_SCHED# next_red = %d, next_green = %d,"
-                       " next_blue = %d, active = %d\n",
+                       "# DONE # next_red = %d, next_green = %d,"
+                       " next_blue = %d\n",
                        data->next_red, data->next_green,
-                       data->next_blue, atomic_read(&led->active));
-
-       /* a fresh work _item_ for each change */
-       bl_work->blinkm_led = led;
-       INIT_WORK(&bl_work->work, led_work);
-       /* queue work in own queue for easy sync on exit*/
-       schedule_work(&bl_work->work);
-
+                       data->next_blue);
        return 0;
 }
 
-static void blinkm_led_red_set(struct led_classdev *led_cdev,
+static int blinkm_led_red_set(struct led_classdev *led_cdev,
                               enum led_brightness value)
 {
-       blinkm_led_common_set(led_cdev, value, RED);
+       return blinkm_led_common_set(led_cdev, value, RED);
 }
 
-static void blinkm_led_green_set(struct led_classdev *led_cdev,
+static int blinkm_led_green_set(struct led_classdev *led_cdev,
                                 enum led_brightness value)
 {
-       blinkm_led_common_set(led_cdev, value, GREEN);
+       return blinkm_led_common_set(led_cdev, value, GREEN);
 }
 
-static void blinkm_led_blue_set(struct led_classdev *led_cdev,
+static int blinkm_led_blue_set(struct led_classdev *led_cdev,
                                enum led_brightness value)
 {
-       blinkm_led_common_set(led_cdev, value, BLUE);
+       return blinkm_led_common_set(led_cdev, value, BLUE);
 }
 
 static void blinkm_init_hw(struct i2c_client *client)
@@ -669,7 +616,6 @@ static int blinkm_probe(struct i2c_client *client,
                led[i]->id = i;
                led[i]->led_cdev.max_brightness = 255;
                led[i]->led_cdev.flags = LED_CORE_SUSPENDRESUME;
-               atomic_set(&led[i]->active, 0);
                switch (i) {
                case RED:
                        snprintf(blinkm_led_name, sizeof(blinkm_led_name),
@@ -677,7 +623,8 @@ static int blinkm_probe(struct i2c_client *client,
                                         client->adapter->nr,
                                         client->addr);
                        led[i]->led_cdev.name = blinkm_led_name;
-                       led[i]->led_cdev.brightness_set = blinkm_led_red_set;
+                       led[i]->led_cdev.brightness_set_blocking =
+                                                       blinkm_led_red_set;
                        err = led_classdev_register(&client->dev,
                                                    &led[i]->led_cdev);
                        if (err < 0) {
@@ -693,7 +640,8 @@ static int blinkm_probe(struct i2c_client *client,
                                         client->adapter->nr,
                                         client->addr);
                        led[i]->led_cdev.name = blinkm_led_name;
-                       led[i]->led_cdev.brightness_set = blinkm_led_green_set;
+                       led[i]->led_cdev.brightness_set_blocking =
+                                                       blinkm_led_green_set;
                        err = led_classdev_register(&client->dev,
                                                    &led[i]->led_cdev);
                        if (err < 0) {
@@ -709,7 +657,8 @@ static int blinkm_probe(struct i2c_client *client,
                                         client->adapter->nr,
                                         client->addr);
                        led[i]->led_cdev.name = blinkm_led_name;
-                       led[i]->led_cdev.brightness_set = blinkm_led_blue_set;
+                       led[i]->led_cdev.brightness_set_blocking =
+                                                       blinkm_led_blue_set;
                        err = led_classdev_register(&client->dev,
                                                    &led[i]->led_cdev);
                        if (err < 0) {
@@ -746,10 +695,8 @@ static int blinkm_remove(struct i2c_client *client)
        int i;
 
        /* make sure no workqueue entries are pending */
-       for (i = 0; i < 3; i++) {
-               flush_scheduled_work();
+       for (i = 0; i < 3; i++)
                led_classdev_unregister(&data->blinkm_leds[i].led_cdev);
-       }
 
        /* reset rgb */
        data->next_red = 0x00;
index 952ba96e5b38c85e5988efea1cd2dd7f07c43347..4752a2b6ba2bc8d0ea9478b7692664ab2020eafa 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
-#include <linux/workqueue.h>
 #include <linux/mfd/da903x.h>
 #include <linux/slab.h>
 
@@ -33,9 +32,7 @@
 
 struct da903x_led {
        struct led_classdev     cdev;
-       struct work_struct      work;
        struct device           *master;
-       enum led_brightness     new_brightness;
        int                     id;
        int                     flags;
 };
@@ -43,11 +40,13 @@ struct da903x_led {
 #define DA9030_LED_OFFSET(id)  ((id) - DA9030_ID_LED_1)
 #define DA9034_LED_OFFSET(id)  ((id) - DA9034_ID_LED_1)
 
-static void da903x_led_work(struct work_struct *work)
+static int da903x_led_set(struct led_classdev *led_cdev,
+                          enum led_brightness value)
 {
-       struct da903x_led *led = container_of(work, struct da903x_led, work);
+       struct da903x_led *led =
+                       container_of(led_cdev, struct da903x_led, cdev);
        uint8_t val;
-       int offset;
+       int offset, ret = -EINVAL;
 
        switch (led->id) {
        case DA9030_ID_LED_1:
@@ -57,37 +56,31 @@ static void da903x_led_work(struct work_struct *work)
        case DA9030_ID_LED_PC:
                offset = DA9030_LED_OFFSET(led->id);
                val = led->flags & ~0x87;
-               val |= (led->new_brightness) ? 0x80 : 0; /* EN bit */
-               val |= (0x7 - (led->new_brightness >> 5)) & 0x7; /* PWM<2:0> */
-               da903x_write(led->master, DA9030_LED1_CONTROL + offset, val);
+               val |= value ? 0x80 : 0; /* EN bit */
+               val |= (0x7 - (value >> 5)) & 0x7; /* PWM<2:0> */
+               ret = da903x_write(led->master, DA9030_LED1_CONTROL + offset,
+                                  val);
                break;
        case DA9030_ID_VIBRA:
                val = led->flags & ~0x80;
-               val |= (led->new_brightness) ? 0x80 : 0; /* EN bit */
-               da903x_write(led->master, DA9030_MISC_CONTROL_A, val);
+               val |= value ? 0x80 : 0; /* EN bit */
+               ret = da903x_write(led->master, DA9030_MISC_CONTROL_A, val);
                break;
        case DA9034_ID_LED_1:
        case DA9034_ID_LED_2:
                offset = DA9034_LED_OFFSET(led->id);
-               val = (led->new_brightness * 0x5f / LED_FULL) & 0x7f;
+               val = (value * 0x5f / LED_FULL) & 0x7f;
                val |= (led->flags & DA9034_LED_RAMP) ? 0x80 : 0;
-               da903x_write(led->master, DA9034_LED1_CONTROL + offset, val);
+               ret = da903x_write(led->master, DA9034_LED1_CONTROL + offset,
+                                  val);
                break;
        case DA9034_ID_VIBRA:
-               val = led->new_brightness & 0xfe;
-               da903x_write(led->master, DA9034_VIBRA, val);
+               val = value & 0xfe;
+               ret = da903x_write(led->master, DA9034_VIBRA, val);
                break;
        }
-}
 
-static void da903x_led_set(struct led_classdev *led_cdev,
-                          enum led_brightness value)
-{
-       struct da903x_led *led;
-
-       led = container_of(led_cdev, struct da903x_led, cdev);
-       led->new_brightness = value;
-       schedule_work(&led->work);
+       return ret;
 }
 
 static int da903x_led_probe(struct platform_device *pdev)
@@ -113,15 +106,12 @@ static int da903x_led_probe(struct platform_device *pdev)
 
        led->cdev.name = pdata->name;
        led->cdev.default_trigger = pdata->default_trigger;
-       led->cdev.brightness_set = da903x_led_set;
+       led->cdev.brightness_set_blocking = da903x_led_set;
        led->cdev.brightness = LED_OFF;
 
        led->id = id;
        led->flags = pdata->flags;
        led->master = pdev->dev.parent;
-       led->new_brightness = LED_OFF;
-
-       INIT_WORK(&led->work, da903x_led_work);
 
        ret = led_classdev_register(led->master, &led->cdev);
        if (ret) {
index 28291b6acc8e988dedcff54108998badce7c156f..f8c7d82c26529aea6e80b5b88d95e232a2cad706 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
-#include <linux/workqueue.h>
 #include <linux/slab.h>
 
 #include <linux/mfd/da9052/reg.h>
 
 struct da9052_led {
        struct led_classdev cdev;
-       struct work_struct work;
        struct da9052 *da9052;
        unsigned char led_index;
        unsigned char id;
-       int brightness;
 };
 
 static unsigned char led_reg[] = {
@@ -44,12 +41,13 @@ static unsigned char led_reg[] = {
        DA9052_LED_CONT_5_REG,
 };
 
-static int da9052_set_led_brightness(struct da9052_led *led)
+static int da9052_set_led_brightness(struct da9052_led *led,
+                                    enum led_brightness brightness)
 {
        u8 val;
        int error;
 
-       val = (led->brightness & 0x7f) | DA9052_LED_CONT_DIM;
+       val = (brightness & 0x7f) | DA9052_LED_CONT_DIM;
 
        error = da9052_reg_write(led->da9052, led_reg[led->led_index], val);
        if (error < 0)
@@ -58,21 +56,13 @@ static int da9052_set_led_brightness(struct da9052_led *led)
        return error;
 }
 
-static void da9052_led_work(struct work_struct *work)
-{
-       struct da9052_led *led = container_of(work, struct da9052_led, work);
-
-       da9052_set_led_brightness(led);
-}
-
-static void da9052_led_set(struct led_classdev *led_cdev,
+static int da9052_led_set(struct led_classdev *led_cdev,
                           enum led_brightness value)
 {
-       struct da9052_led *led;
+       struct da9052_led *led =
+                       container_of(led_cdev, struct da9052_led, cdev);
 
-       led = container_of(led_cdev, struct da9052_led, cdev);
-       led->brightness = value;
-       schedule_work(&led->work);
+       return da9052_set_led_brightness(led, value);
 }
 
 static int da9052_configure_leds(struct da9052 *da9052)
@@ -133,13 +123,11 @@ static int da9052_led_probe(struct platform_device *pdev)
 
        for (i = 0; i < pled->num_leds; i++) {
                led[i].cdev.name = pled->leds[i].name;
-               led[i].cdev.brightness_set = da9052_led_set;
+               led[i].cdev.brightness_set_blocking = da9052_led_set;
                led[i].cdev.brightness = LED_OFF;
                led[i].cdev.max_brightness = DA9052_MAX_BRIGHTNESS;
-               led[i].brightness = LED_OFF;
                led[i].led_index = pled->leds[i].flags;
                led[i].da9052 = dev_get_drvdata(pdev->dev.parent);
-               INIT_WORK(&led[i].work, da9052_led_work);
 
                error = led_classdev_register(pdev->dev.parent, &led[i].cdev);
                if (error) {
@@ -148,7 +136,8 @@ static int da9052_led_probe(struct platform_device *pdev)
                        goto err_register;
                }
 
-               error = da9052_set_led_brightness(&led[i]);
+               error = da9052_set_led_brightness(&led[i],
+                                                 led[i].cdev.brightness);
                if (error) {
                        dev_err(&pdev->dev, "Unable to init led %d\n",
                                led[i].led_index);
@@ -166,10 +155,8 @@ static int da9052_led_probe(struct platform_device *pdev)
        return 0;
 
 err_register:
-       for (i = i - 1; i >= 0; i--) {
+       for (i = i - 1; i >= 0; i--)
                led_classdev_unregister(&led[i].cdev);
-               cancel_work_sync(&led[i].work);
-       }
 err:
        return error;
 }
@@ -187,10 +174,8 @@ static int da9052_led_remove(struct platform_device *pdev)
        pled = pdata->pled;
 
        for (i = 0; i < pled->num_leds; i++) {
-               led[i].brightness = 0;
-               da9052_set_led_brightness(&led[i]);
+               da9052_set_led_brightness(&led[i], LED_OFF);
                led_classdev_unregister(&led[i].cdev);
-               cancel_work_sync(&led[i].work);
        }
 
        return 0;
index 314159610d240a1e063befb88e499a6eccc3b3ee..5a5a86d5f1f58c2642459d7e6587ba9cb3a5c14a 100644 (file)
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/workqueue.h>
 #include <linux/spi/spi.h>
 
 struct dac124s085_led {
        struct led_classdev     ldev;
        struct spi_device       *spi;
        int                     id;
-       int                     brightness;
        char                    name[sizeof("dac124s085-3")];
 
        struct mutex            mutex;
-       struct work_struct      work;
-       spinlock_t              lock;
 };
 
 struct dac124s085 {
@@ -38,29 +33,21 @@ struct dac124s085 {
 #define ALL_WRITE_UPDATE       (2 << 12)
 #define POWER_DOWN_OUTPUT      (3 << 12)
 
-static void dac124s085_led_work(struct work_struct *work)
+static int dac124s085_set_brightness(struct led_classdev *ldev,
+                                     enum led_brightness brightness)
 {
-       struct dac124s085_led *led = container_of(work, struct dac124s085_led,
-                                                 work);
+       struct dac124s085_led *led = container_of(ldev, struct dac124s085_led,
+                                                 ldev);
        u16 word;
+       int ret;
 
        mutex_lock(&led->mutex);
        word = cpu_to_le16(((led->id) << 14) | REG_WRITE_UPDATE |
-                          (led->brightness & 0xfff));
-       spi_write(led->spi, (const u8 *)&word, sizeof(word));
+                          (brightness & 0xfff));
+       ret = spi_write(led->spi, (const u8 *)&word, sizeof(word));
        mutex_unlock(&led->mutex);
-}
-
-static void dac124s085_set_brightness(struct led_classdev *ldev,
-                                     enum led_brightness brightness)
-{
-       struct dac124s085_led *led = container_of(ldev, struct dac124s085_led,
-                                                 ldev);
 
-       spin_lock(&led->lock);
-       led->brightness = brightness;
-       schedule_work(&led->work);
-       spin_unlock(&led->lock);
+       return ret;
 }
 
 static int dac124s085_probe(struct spi_device *spi)
@@ -78,16 +65,13 @@ static int dac124s085_probe(struct spi_device *spi)
        for (i = 0; i < ARRAY_SIZE(dac->leds); i++) {
                led             = dac->leds + i;
                led->id         = i;
-               led->brightness = LED_OFF;
                led->spi        = spi;
                snprintf(led->name, sizeof(led->name), "dac124s085-%d", i);
-               spin_lock_init(&led->lock);
-               INIT_WORK(&led->work, dac124s085_led_work);
                mutex_init(&led->mutex);
                led->ldev.name = led->name;
                led->ldev.brightness = LED_OFF;
                led->ldev.max_brightness = 0xfff;
-               led->ldev.brightness_set = dac124s085_set_brightness;
+               led->ldev.brightness_set_blocking = dac124s085_set_brightness;
                ret = led_classdev_register(&spi->dev, &led->ldev);
                if (ret < 0)
                        goto eledcr;
@@ -109,10 +93,8 @@ static int dac124s085_remove(struct spi_device *spi)
        struct dac124s085       *dac = spi_get_drvdata(spi);
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(dac->leds); i++) {
+       for (i = 0; i < ARRAY_SIZE(dac->leds); i++)
                led_classdev_unregister(&dac->leds[i].ldev);
-               cancel_work_sync(&dac->leds[i].work);
-       }
 
        return 0;
 }
index 5db4515a4fd7aaf292958a5a7fa982bcccceb999..7bc53280dbfdd91d0d2efa51bb63986a6bbf336b 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/property.h>
 #include <linux/slab.h>
-#include <linux/workqueue.h>
 
 struct gpio_led_data {
        struct led_classdev cdev;
        struct gpio_desc *gpiod;
-       struct work_struct work;
-       u8 new_level;
        u8 can_sleep;
        u8 blinking;
        int (*platform_gpio_blink_set)(struct gpio_desc *desc, int state,
                        unsigned long *delay_on, unsigned long *delay_off);
 };
 
-static void gpio_led_work(struct work_struct *work)
-{
-       struct gpio_led_data *led_dat =
-               container_of(work, struct gpio_led_data, work);
-
-       if (led_dat->blinking) {
-               led_dat->platform_gpio_blink_set(led_dat->gpiod,
-                                       led_dat->new_level, NULL, NULL);
-               led_dat->blinking = 0;
-       } else
-               gpiod_set_value_cansleep(led_dat->gpiod, led_dat->new_level);
-}
-
 static void gpio_led_set(struct led_classdev *led_cdev,
        enum led_brightness value)
 {
@@ -58,23 +42,25 @@ static void gpio_led_set(struct led_classdev *led_cdev,
        else
                level = 1;
 
-       /* Setting GPIOs with I2C/etc requires a task context, and we don't
-        * seem to have a reliable way to know if we're already in one; so
-        * let's just assume the worst.
-        */
-       if (led_dat->can_sleep) {
-               led_dat->new_level = level;
-               schedule_work(&led_dat->work);
+       if (led_dat->blinking) {
+               led_dat->platform_gpio_blink_set(led_dat->gpiod, level,
+                                                NULL, NULL);
+               led_dat->blinking = 0;
        } else {
-               if (led_dat->blinking) {
-                       led_dat->platform_gpio_blink_set(led_dat->gpiod, level,
-                                                        NULL, NULL);
-                       led_dat->blinking = 0;
-               } else
+               if (led_dat->can_sleep)
+                       gpiod_set_value_cansleep(led_dat->gpiod, level);
+               else
                        gpiod_set_value(led_dat->gpiod, level);
        }
 }
 
+static int gpio_led_set_blocking(struct led_classdev *led_cdev,
+       enum led_brightness value)
+{
+       gpio_led_set(led_cdev, value);
+       return 0;
+}
+
 static int gpio_blink_set(struct led_classdev *led_cdev,
        unsigned long *delay_on, unsigned long *delay_off)
 {
@@ -125,12 +111,15 @@ static int create_gpio_led(const struct gpio_led *template,
        led_dat->cdev.name = template->name;
        led_dat->cdev.default_trigger = template->default_trigger;
        led_dat->can_sleep = gpiod_cansleep(led_dat->gpiod);
+       if (!led_dat->can_sleep)
+               led_dat->cdev.brightness_set = gpio_led_set;
+       else
+               led_dat->cdev.brightness_set_blocking = gpio_led_set_blocking;
        led_dat->blinking = 0;
        if (blink_set) {
                led_dat->platform_gpio_blink_set = blink_set;
                led_dat->cdev.blink_set = gpio_blink_set;
        }
-       led_dat->cdev.brightness_set = gpio_led_set;
        if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
                state = !!gpiod_get_value_cansleep(led_dat->gpiod);
        else
@@ -143,17 +132,9 @@ static int create_gpio_led(const struct gpio_led *template,
        if (ret < 0)
                return ret;
 
-       INIT_WORK(&led_dat->work, gpio_led_work);
-
        return led_classdev_register(parent, &led_dat->cdev);
 }
 
-static void delete_gpio_led(struct gpio_led_data *led)
-{
-       led_classdev_unregister(&led->cdev);
-       cancel_work_sync(&led->work);
-}
-
 struct gpio_leds_priv {
        int num_leds;
        struct gpio_led_data leds[];
@@ -233,7 +214,7 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
 
 err:
        for (count = priv->num_leds - 1; count >= 0; count--)
-               delete_gpio_led(&priv->leds[count]);
+               led_classdev_unregister(&priv->leds[count].cdev);
        return ERR_PTR(ret);
 }
 
@@ -265,7 +246,8 @@ static int gpio_led_probe(struct platform_device *pdev)
                        if (ret < 0) {
                                /* On failure: unwind the led creations */
                                for (i = i - 1; i >= 0; i--)
-                                       delete_gpio_led(&priv->leds[i]);
+                                       led_classdev_unregister(
+                                                       &priv->leds[i].cdev);
                                return ret;
                        }
                }
@@ -286,7 +268,7 @@ static int gpio_led_remove(struct platform_device *pdev)
        int i;
 
        for (i = 0; i < priv->num_leds; i++)
-               delete_gpio_led(&priv->leds[i]);
+               led_classdev_unregister(&priv->leds[i].cdev);
 
        return 0;
 }
index fa262b6b25eb26dfab24fa784200ae6175996f06..02f17331379dd65b875136b1c78ab689fef83478 100644 (file)
@@ -20,7 +20,7 @@
 #define LED_AUTOSTOP (1 << 5) /* LED ON/OFF auto stop set 0:disable, 1:enable */
 #define LED_ALWAYS   (1 << 6) /* LED Interrupt Mask 0:No mask, 1:mask         */
 
-static void micro_leds_brightness_set(struct led_classdev *led_cdev,
+static int micro_leds_brightness_set(struct led_classdev *led_cdev,
                                      enum led_brightness value)
 {
        struct ipaq_micro *micro = dev_get_drvdata(led_cdev->dev->parent->parent);
@@ -50,7 +50,7 @@ static void micro_leds_brightness_set(struct led_classdev *led_cdev,
                msg.tx_data[2] = 1;
                msg.tx_data[3] = 0; /* Duty cycle 256 */
        }
-       ipaq_micro_tx_msg_sync(micro, &msg);
+       return ipaq_micro_tx_msg_sync(micro, &msg);
 }
 
 /* Maximum duty cycle in ms 256/10 sec = 25600 ms */
@@ -102,7 +102,7 @@ static int micro_leds_blink_set(struct led_classdev *led_cdev,
 
 static struct led_classdev micro_led = {
        .name                   = "led-ipaq-micro",
-       .brightness_set         = micro_leds_brightness_set,
+       .brightness_set_blocking = micro_leds_brightness_set,
        .blink_set              = micro_leds_blink_set,
        .flags                  = LED_CORE_SUSPENDRESUME,
 };
index feca07be85f590c09f4b12a69835e59e44ecff9b..bf23ba191ad06857a3a3e1a7ab8e2725d910262f 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
-#include <linux/workqueue.h>
 
 /* Value related the movie mode */
 #define KTD2692_MOVIE_MODE_CURRENT_LEVELS      16
@@ -82,7 +81,6 @@ struct ktd2692_context {
        /* secures access to the device */
        struct mutex lock;
        struct regulator *regulator;
-       struct work_struct work_brightness_set;
 
        struct gpio_desc *aux_gpio;
        struct gpio_desc *ctrl_gpio;
@@ -158,9 +156,12 @@ static void ktd2692_expresswire_write(struct ktd2692_context *led, u8 value)
        ktd2692_expresswire_end(led);
 }
 
-static void ktd2692_brightness_set(struct ktd2692_context *led,
-                                  enum led_brightness brightness)
+static int ktd2692_led_brightness_set(struct led_classdev *led_cdev,
+                                      enum led_brightness brightness)
 {
+       struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+       struct ktd2692_context *led = fled_cdev_to_led(fled_cdev);
+
        mutex_lock(&led->lock);
 
        if (brightness == LED_OFF) {
@@ -174,33 +175,6 @@ static void ktd2692_brightness_set(struct ktd2692_context *led,
 
        ktd2692_expresswire_write(led, led->mode | KTD2692_REG_MODE_BASE);
        mutex_unlock(&led->lock);
-}
-
-static void ktd2692_brightness_set_work(struct work_struct *work)
-{
-       struct ktd2692_context *led =
-               container_of(work, struct ktd2692_context, work_brightness_set);
-
-       ktd2692_brightness_set(led, led->torch_brightness);
-}
-
-static void ktd2692_led_brightness_set(struct led_classdev *led_cdev,
-                                      enum led_brightness brightness)
-{
-       struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
-       struct ktd2692_context *led = fled_cdev_to_led(fled_cdev);
-
-       led->torch_brightness = brightness;
-       schedule_work(&led->work_brightness_set);
-}
-
-static int ktd2692_led_brightness_set_sync(struct led_classdev *led_cdev,
-                                          enum led_brightness brightness)
-{
-       struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
-       struct ktd2692_context *led = fled_cdev_to_led(fled_cdev);
-
-       ktd2692_brightness_set(led, brightness);
 
        return 0;
 }
@@ -332,21 +306,24 @@ static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev,
                                   &cfg->movie_max_microamp);
        if (ret) {
                dev_err(dev, "failed to parse led-max-microamp\n");
-               return ret;
+               goto err_parse_dt;
        }
 
        ret = of_property_read_u32(child_node, "flash-max-microamp",
                                   &cfg->flash_max_microamp);
        if (ret) {
                dev_err(dev, "failed to parse flash-max-microamp\n");
-               return ret;
+               goto err_parse_dt;
        }
 
        ret = of_property_read_u32(child_node, "flash-max-timeout-us",
                                   &cfg->flash_max_timeout);
-       if (ret)
+       if (ret) {
                dev_err(dev, "failed to parse flash-max-timeout-us\n");
+               goto err_parse_dt;
+       }
 
+err_parse_dt:
        of_node_put(child_node);
        return ret;
 }
@@ -381,12 +358,10 @@ static int ktd2692_probe(struct platform_device *pdev)
        fled_cdev->ops = &flash_ops;
 
        led_cdev->max_brightness = led_cfg.max_brightness;
-       led_cdev->brightness_set = ktd2692_led_brightness_set;
-       led_cdev->brightness_set_sync = ktd2692_led_brightness_set_sync;
+       led_cdev->brightness_set_blocking = ktd2692_led_brightness_set;
        led_cdev->flags |= LED_CORE_SUSPENDRESUME | LED_DEV_CAP_FLASH;
 
        mutex_init(&led->lock);
-       INIT_WORK(&led->work_brightness_set, ktd2692_brightness_set_work);
 
        platform_set_drvdata(pdev, led);
 
@@ -408,7 +383,6 @@ static int ktd2692_remove(struct platform_device *pdev)
        int ret;
 
        led_classdev_flash_unregister(&led->fled_cdev);
-       cancel_work_sync(&led->work_brightness_set);
 
        if (led->regulator) {
                ret = regulator_disable(led->regulator);
index 6e2e02035dd7b9c43c00e4bf19145152efdacc0c..196dcb5e6004a0a93972685b504ae281ed822d0e 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
-#include <linux/workqueue.h>
 
 #include <linux/mfd/lm3533.h>
 
@@ -53,9 +52,6 @@ struct lm3533_led {
 
        struct mutex mutex;
        unsigned long flags;
-
-       struct work_struct work;
-       u8 new_brightness;
 };
 
 
@@ -123,27 +119,17 @@ out:
        return ret;
 }
 
-static void lm3533_led_work(struct work_struct *work)
-{
-       struct lm3533_led *led = container_of(work, struct lm3533_led, work);
-
-       dev_dbg(led->cdev.dev, "%s - %u\n", __func__, led->new_brightness);
-
-       if (led->new_brightness == 0)
-               lm3533_led_pattern_enable(led, 0);      /* disable blink */
-
-       lm3533_ctrlbank_set_brightness(&led->cb, led->new_brightness);
-}
-
-static void lm3533_led_set(struct led_classdev *cdev,
+static int lm3533_led_set(struct led_classdev *cdev,
                                                enum led_brightness value)
 {
        struct lm3533_led *led = to_lm3533_led(cdev);
 
        dev_dbg(led->cdev.dev, "%s - %d\n", __func__, value);
 
-       led->new_brightness = value;
-       schedule_work(&led->work);
+       if (value == 0)
+               lm3533_led_pattern_enable(led, 0);      /* disable blink */
+
+       return lm3533_ctrlbank_set_brightness(&led->cb, value);
 }
 
 static enum led_brightness lm3533_led_get(struct led_classdev *cdev)
@@ -693,7 +679,7 @@ static int lm3533_led_probe(struct platform_device *pdev)
        led->lm3533 = lm3533;
        led->cdev.name = pdata->name;
        led->cdev.default_trigger = pdata->default_trigger;
-       led->cdev.brightness_set = lm3533_led_set;
+       led->cdev.brightness_set_blocking = lm3533_led_set;
        led->cdev.brightness_get = lm3533_led_get;
        led->cdev.blink_set = lm3533_led_blink_set;
        led->cdev.brightness = LED_OFF;
@@ -701,7 +687,6 @@ static int lm3533_led_probe(struct platform_device *pdev)
        led->id = pdev->id;
 
        mutex_init(&led->mutex);
-       INIT_WORK(&led->work, lm3533_led_work);
 
        /* The class framework makes a callback to get brightness during
         * registration so use parent device (for error reporting) until
@@ -733,7 +718,6 @@ static int lm3533_led_probe(struct platform_device *pdev)
 
 err_unregister:
        led_classdev_unregister(&led->cdev);
-       flush_work(&led->work);
 
        return ret;
 }
@@ -746,7 +730,6 @@ static int lm3533_led_remove(struct platform_device *pdev)
 
        lm3533_ctrlbank_disable(&led->cb);
        led_classdev_unregister(&led->cdev);
-       flush_work(&led->work);
 
        return 0;
 }
@@ -760,7 +743,6 @@ static void lm3533_led_shutdown(struct platform_device *pdev)
 
        lm3533_ctrlbank_disable(&led->cb);
        lm3533_led_set(&led->cdev, LED_OFF);            /* disable blink */
-       flush_work(&led->work);
 }
 
 static struct platform_driver lm3533_led_driver = {
index 48872997d6b4b35391affa52d07496082fb261f7..6cb94f9a2f3f3fb382d98f29f780d1cb58c76339 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/platform_device.h>
 #include <linux/fs.h>
 #include <linux/regmap.h>
-#include <linux/workqueue.h>
 #include <linux/platform_data/leds-lm355x.h>
 
 enum lm355x_type {
@@ -59,14 +58,6 @@ struct lm355x_chip_data {
        struct led_classdev cdev_torch;
        struct led_classdev cdev_indicator;
 
-       struct work_struct work_flash;
-       struct work_struct work_torch;
-       struct work_struct work_indicator;
-
-       u8 br_flash;
-       u8 br_torch;
-       u8 br_indicator;
-
        struct lm355x_platform_data *pdata;
        struct regmap *regmap;
        struct mutex lock;
@@ -204,7 +195,7 @@ out:
 }
 
 /* chip control */
-static void lm355x_control(struct lm355x_chip_data *chip,
+static int lm355x_control(struct lm355x_chip_data *chip,
                           u8 brightness, enum lm355x_mode opmode)
 {
        int ret;
@@ -301,7 +292,7 @@ static void lm355x_control(struct lm355x_chip_data *chip,
        case MODE_SHDN:
                break;
        default:
-               return;
+               return -EINVAL;
        }
        /* operation mode control */
        ret = regmap_update_bits(chip->regmap, preg[REG_OPMODE].regno,
@@ -309,73 +300,55 @@ static void lm355x_control(struct lm355x_chip_data *chip,
                                 opmode << preg[REG_OPMODE].shift);
        if (ret < 0)
                goto out;
-       return;
+       return ret;
 out:
        dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
-       return;
+       return ret;
 }
 
 /* torch */
-static void lm355x_deferred_torch_brightness_set(struct work_struct *work)
-{
-       struct lm355x_chip_data *chip =
-           container_of(work, struct lm355x_chip_data, work_torch);
 
-       mutex_lock(&chip->lock);
-       lm355x_control(chip, chip->br_torch, MODE_TORCH);
-       mutex_unlock(&chip->lock);
-}
-
-static void lm355x_torch_brightness_set(struct led_classdev *cdev,
+static int lm355x_torch_brightness_set(struct led_classdev *cdev,
                                        enum led_brightness brightness)
 {
        struct lm355x_chip_data *chip =
            container_of(cdev, struct lm355x_chip_data, cdev_torch);
-
-       chip->br_torch = brightness;
-       schedule_work(&chip->work_torch);
-}
-
-/* flash */
-static void lm355x_deferred_strobe_brightness_set(struct work_struct *work)
-{
-       struct lm355x_chip_data *chip =
-           container_of(work, struct lm355x_chip_data, work_flash);
+       int ret;
 
        mutex_lock(&chip->lock);
-       lm355x_control(chip, chip->br_flash, MODE_FLASH);
+       ret = lm355x_control(chip, brightness, MODE_TORCH);
        mutex_unlock(&chip->lock);
+       return ret;
 }
 
-static void lm355x_strobe_brightness_set(struct led_classdev *cdev,
+/* flash */
+
+static int lm355x_strobe_brightness_set(struct led_classdev *cdev,
                                         enum led_brightness brightness)
 {
        struct lm355x_chip_data *chip =
            container_of(cdev, struct lm355x_chip_data, cdev_flash);
-
-       chip->br_flash = brightness;
-       schedule_work(&chip->work_flash);
-}
-
-/* indicator */
-static void lm355x_deferred_indicator_brightness_set(struct work_struct *work)
-{
-       struct lm355x_chip_data *chip =
-           container_of(work, struct lm355x_chip_data, work_indicator);
+       int ret;
 
        mutex_lock(&chip->lock);
-       lm355x_control(chip, chip->br_indicator, MODE_INDIC);
+       ret = lm355x_control(chip, brightness, MODE_FLASH);
        mutex_unlock(&chip->lock);
+       return ret;
 }
 
-static void lm355x_indicator_brightness_set(struct led_classdev *cdev,
+/* indicator */
+
+static int lm355x_indicator_brightness_set(struct led_classdev *cdev,
                                            enum led_brightness brightness)
 {
        struct lm355x_chip_data *chip =
            container_of(cdev, struct lm355x_chip_data, cdev_indicator);
+       int ret;
 
-       chip->br_indicator = brightness;
-       schedule_work(&chip->work_indicator);
+       mutex_lock(&chip->lock);
+       ret = lm355x_control(chip, brightness, MODE_INDIC);
+       mutex_unlock(&chip->lock);
+       return ret;
 }
 
 /* indicator pattern only for lm3556*/
@@ -479,34 +452,31 @@ static int lm355x_probe(struct i2c_client *client,
                goto err_out;
 
        /* flash */
-       INIT_WORK(&chip->work_flash, lm355x_deferred_strobe_brightness_set);
        chip->cdev_flash.name = "flash";
        chip->cdev_flash.max_brightness = 16;
-       chip->cdev_flash.brightness_set = lm355x_strobe_brightness_set;
+       chip->cdev_flash.brightness_set_blocking = lm355x_strobe_brightness_set;
        chip->cdev_flash.default_trigger = "flash";
        err = led_classdev_register((struct device *)
                                    &client->dev, &chip->cdev_flash);
        if (err < 0)
                goto err_out;
        /* torch */
-       INIT_WORK(&chip->work_torch, lm355x_deferred_torch_brightness_set);
        chip->cdev_torch.name = "torch";
        chip->cdev_torch.max_brightness = 8;
-       chip->cdev_torch.brightness_set = lm355x_torch_brightness_set;
+       chip->cdev_torch.brightness_set_blocking = lm355x_torch_brightness_set;
        chip->cdev_torch.default_trigger = "torch";
        err = led_classdev_register((struct device *)
                                    &client->dev, &chip->cdev_torch);
        if (err < 0)
                goto err_create_torch_file;
        /* indicator */
-       INIT_WORK(&chip->work_indicator,
-                 lm355x_deferred_indicator_brightness_set);
        chip->cdev_indicator.name = "indicator";
        if (id->driver_data == CHIP_LM3554)
                chip->cdev_indicator.max_brightness = 4;
        else
                chip->cdev_indicator.max_brightness = 8;
-       chip->cdev_indicator.brightness_set = lm355x_indicator_brightness_set;
+       chip->cdev_indicator.brightness_set_blocking =
+                                       lm355x_indicator_brightness_set;
        /* indicator pattern control only for LM3556 */
        if (id->driver_data == CHIP_LM3556)
                chip->cdev_indicator.groups = lm355x_indicator_groups;
@@ -534,11 +504,8 @@ static int lm355x_remove(struct i2c_client *client)
 
        regmap_write(chip->regmap, preg[REG_OPMODE].regno, 0);
        led_classdev_unregister(&chip->cdev_indicator);
-       flush_work(&chip->work_indicator);
        led_classdev_unregister(&chip->cdev_torch);
-       flush_work(&chip->work_torch);
        led_classdev_unregister(&chip->cdev_flash);
-       flush_work(&chip->work_flash);
        dev_info(&client->dev, "%s is removed\n", lm355x_name[chip->type]);
 
        return 0;
index 02ebe342f5af219ae4bd576a78794adc5d6fc88f..cada0848db7b2623f511541b679cfaa74ae3a538 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/platform_device.h>
 #include <linux/fs.h>
 #include <linux/regmap.h>
-#include <linux/workqueue.h>
 #include <linux/platform_data/leds-lm3642.h>
 
 #define        REG_FILT_TIME                   (0x0)
@@ -73,10 +72,6 @@ struct lm3642_chip_data {
        struct led_classdev cdev_torch;
        struct led_classdev cdev_indicator;
 
-       struct work_struct work_flash;
-       struct work_struct work_torch;
-       struct work_struct work_indicator;
-
        u8 br_flash;
        u8 br_torch;
        u8 br_indicator;
@@ -209,24 +204,18 @@ out_strtoint:
 
 static DEVICE_ATTR(torch_pin, S_IWUSR, NULL, lm3642_torch_pin_store);
 
-static void lm3642_deferred_torch_brightness_set(struct work_struct *work)
-{
-       struct lm3642_chip_data *chip =
-           container_of(work, struct lm3642_chip_data, work_torch);
-
-       mutex_lock(&chip->lock);
-       lm3642_control(chip, chip->br_torch, MODES_TORCH);
-       mutex_unlock(&chip->lock);
-}
-
-static void lm3642_torch_brightness_set(struct led_classdev *cdev,
+static int lm3642_torch_brightness_set(struct led_classdev *cdev,
                                        enum led_brightness brightness)
 {
        struct lm3642_chip_data *chip =
            container_of(cdev, struct lm3642_chip_data, cdev_torch);
+       int ret;
 
+       mutex_lock(&chip->lock);
        chip->br_torch = brightness;
-       schedule_work(&chip->work_torch);
+       ret = lm3642_control(chip, chip->br_torch, MODES_TORCH);
+       mutex_unlock(&chip->lock);
+       return ret;
 }
 
 /* flash */
@@ -266,45 +255,33 @@ out_strtoint:
 
 static DEVICE_ATTR(strobe_pin, S_IWUSR, NULL, lm3642_strobe_pin_store);
 
-static void lm3642_deferred_strobe_brightness_set(struct work_struct *work)
-{
-       struct lm3642_chip_data *chip =
-           container_of(work, struct lm3642_chip_data, work_flash);
-
-       mutex_lock(&chip->lock);
-       lm3642_control(chip, chip->br_flash, MODES_FLASH);
-       mutex_unlock(&chip->lock);
-}
-
-static void lm3642_strobe_brightness_set(struct led_classdev *cdev,
+static int lm3642_strobe_brightness_set(struct led_classdev *cdev,
                                         enum led_brightness brightness)
 {
        struct lm3642_chip_data *chip =
            container_of(cdev, struct lm3642_chip_data, cdev_flash);
-
-       chip->br_flash = brightness;
-       schedule_work(&chip->work_flash);
-}
-
-/* indicator */
-static void lm3642_deferred_indicator_brightness_set(struct work_struct *work)
-{
-       struct lm3642_chip_data *chip =
-           container_of(work, struct lm3642_chip_data, work_indicator);
+       int ret;
 
        mutex_lock(&chip->lock);
-       lm3642_control(chip, chip->br_indicator, MODES_INDIC);
+       chip->br_flash = brightness;
+       ret = lm3642_control(chip, chip->br_flash, MODES_FLASH);
        mutex_unlock(&chip->lock);
+       return ret;
 }
 
-static void lm3642_indicator_brightness_set(struct led_classdev *cdev,
+/* indicator */
+static int lm3642_indicator_brightness_set(struct led_classdev *cdev,
                                            enum led_brightness brightness)
 {
        struct lm3642_chip_data *chip =
            container_of(cdev, struct lm3642_chip_data, cdev_indicator);
+       int ret;
 
+       mutex_lock(&chip->lock);
        chip->br_indicator = brightness;
-       schedule_work(&chip->work_indicator);
+       ret = lm3642_control(chip, chip->br_indicator, MODES_INDIC);
+       mutex_unlock(&chip->lock);
+       return ret;
 }
 
 static const struct regmap_config lm3642_regmap = {
@@ -371,10 +348,9 @@ static int lm3642_probe(struct i2c_client *client,
                goto err_out;
 
        /* flash */
-       INIT_WORK(&chip->work_flash, lm3642_deferred_strobe_brightness_set);
        chip->cdev_flash.name = "flash";
        chip->cdev_flash.max_brightness = 16;
-       chip->cdev_flash.brightness_set = lm3642_strobe_brightness_set;
+       chip->cdev_flash.brightness_set_blocking = lm3642_strobe_brightness_set;
        chip->cdev_flash.default_trigger = "flash";
        chip->cdev_flash.groups = lm3642_flash_groups,
        err = led_classdev_register((struct device *)
@@ -385,10 +361,9 @@ static int lm3642_probe(struct i2c_client *client,
        }
 
        /* torch */
-       INIT_WORK(&chip->work_torch, lm3642_deferred_torch_brightness_set);
        chip->cdev_torch.name = "torch";
        chip->cdev_torch.max_brightness = 8;
-       chip->cdev_torch.brightness_set = lm3642_torch_brightness_set;
+       chip->cdev_torch.brightness_set_blocking = lm3642_torch_brightness_set;
        chip->cdev_torch.default_trigger = "torch";
        chip->cdev_torch.groups = lm3642_torch_groups,
        err = led_classdev_register((struct device *)
@@ -399,11 +374,10 @@ static int lm3642_probe(struct i2c_client *client,
        }
 
        /* indicator */
-       INIT_WORK(&chip->work_indicator,
-                 lm3642_deferred_indicator_brightness_set);
        chip->cdev_indicator.name = "indicator";
        chip->cdev_indicator.max_brightness = 8;
-       chip->cdev_indicator.brightness_set = lm3642_indicator_brightness_set;
+       chip->cdev_indicator.brightness_set_blocking =
+                                               lm3642_indicator_brightness_set;
        err = led_classdev_register((struct device *)
                                    &client->dev, &chip->cdev_indicator);
        if (err < 0) {
@@ -427,11 +401,8 @@ static int lm3642_remove(struct i2c_client *client)
        struct lm3642_chip_data *chip = i2c_get_clientdata(client);
 
        led_classdev_unregister(&chip->cdev_indicator);
-       flush_work(&chip->work_indicator);
        led_classdev_unregister(&chip->cdev_torch);
-       flush_work(&chip->work_torch);
        led_classdev_unregister(&chip->cdev_flash);
-       flush_work(&chip->work_flash);
        regmap_write(chip->regmap, REG_ENABLE, 0);
        return 0;
 }
index 53144fb9616702d3024bb505c1278b613bb02221..6c758aea1bbdaa1fb77edf71e9c611e4e131ee0e 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/slab.h>
 #include <linux/leds.h>
 #include <linux/mutex.h>
-#include <linux/workqueue.h>
 #include <linux/leds-lp3944.h>
 
 /* Read Only Registers */
 struct lp3944_led_data {
        u8 id;
        enum lp3944_type type;
-       enum lp3944_status status;
        struct led_classdev ldev;
        struct i2c_client *client;
-       struct work_struct work;
 };
 
 struct lp3944_data {
@@ -275,13 +272,12 @@ static int lp3944_led_set_blink(struct led_classdev *led_cdev,
        dev_dbg(&led->client->dev, "%s: OK hardware accelerated blink!\n",
                __func__);
 
-       led->status = LP3944_LED_STATUS_DIM0;
-       schedule_work(&led->work);
+       lp3944_led_set(led, LP3944_LED_STATUS_DIM0);
 
        return 0;
 }
 
-static void lp3944_led_set_brightness(struct led_classdev *led_cdev,
+static int lp3944_led_set_brightness(struct led_classdev *led_cdev,
                                      enum led_brightness brightness)
 {
        struct lp3944_led_data *led = ldev_to_led(led_cdev);
@@ -289,16 +285,7 @@ static void lp3944_led_set_brightness(struct led_classdev *led_cdev,
        dev_dbg(&led->client->dev, "%s: %s, %d\n",
                __func__, led_cdev->name, brightness);
 
-       led->status = !!brightness;
-       schedule_work(&led->work);
-}
-
-static void lp3944_led_work(struct work_struct *work)
-{
-       struct lp3944_led_data *led;
-
-       led = container_of(work, struct lp3944_led_data, work);
-       lp3944_led_set(led, led->status);
+       return lp3944_led_set(led, !!brightness);
 }
 
 static int lp3944_configure(struct i2c_client *client,
@@ -318,14 +305,13 @@ static int lp3944_configure(struct i2c_client *client,
                case LP3944_LED_TYPE_LED:
                case LP3944_LED_TYPE_LED_INVERTED:
                        led->type = pled->type;
-                       led->status = pled->status;
                        led->ldev.name = pled->name;
                        led->ldev.max_brightness = 1;
-                       led->ldev.brightness_set = lp3944_led_set_brightness;
+                       led->ldev.brightness_set_blocking =
+                                               lp3944_led_set_brightness;
                        led->ldev.blink_set = lp3944_led_set_blink;
                        led->ldev.flags = LED_CORE_SUSPENDRESUME;
 
-                       INIT_WORK(&led->work, lp3944_led_work);
                        err = led_classdev_register(&client->dev, &led->ldev);
                        if (err < 0) {
                                dev_err(&client->dev,
@@ -336,14 +322,14 @@ static int lp3944_configure(struct i2c_client *client,
 
                        /* to expose the default value to userspace */
                        led->ldev.brightness =
-                                       (enum led_brightness) led->status;
+                                       (enum led_brightness) pled->status;
 
                        /* Set the default led status */
-                       err = lp3944_led_set(led, led->status);
+                       err = lp3944_led_set(led, pled->status);
                        if (err < 0) {
                                dev_err(&client->dev,
                                        "%s couldn't set STATUS %d\n",
-                                       led->ldev.name, led->status);
+                                       led->ldev.name, pled->status);
                                goto exit;
                        }
                        break;
@@ -364,7 +350,6 @@ exit:
                        case LP3944_LED_TYPE_LED:
                        case LP3944_LED_TYPE_LED_INVERTED:
                                led_classdev_unregister(&data->leds[i].ldev);
-                               cancel_work_sync(&data->leds[i].work);
                                break;
 
                        case LP3944_LED_TYPE_NONE:
@@ -424,7 +409,6 @@ static int lp3944_remove(struct i2c_client *client)
                case LP3944_LED_TYPE_LED:
                case LP3944_LED_TYPE_LED_INVERTED:
                        led_classdev_unregister(&data->leds[i].ldev);
-                       cancel_work_sync(&data->leds[i].work);
                        break;
 
                case LP3944_LED_TYPE_NONE:
index 63a92542c8cb0953d17d5dcd8502075348dad9cf..549b315ca8fe820932816d6c84e3d705bd876c99 100644 (file)
@@ -362,16 +362,17 @@ static int lp5521_run_selftest(struct lp55xx_chip *chip, char *buf)
        return 0;
 }
 
-static void lp5521_led_brightness_work(struct work_struct *work)
+static int lp5521_led_brightness(struct lp55xx_led *led)
 {
-       struct lp55xx_led *led = container_of(work, struct lp55xx_led,
-                                             brightness_work);
        struct lp55xx_chip *chip = led->chip;
+       int ret;
 
        mutex_lock(&chip->lock);
-       lp55xx_write(chip, LP5521_REG_LED_PWM_BASE + led->chan_nr,
+       ret = lp55xx_write(chip, LP5521_REG_LED_PWM_BASE + led->chan_nr,
                led->brightness);
        mutex_unlock(&chip->lock);
+
+       return ret;
 }
 
 static ssize_t show_engine_mode(struct device *dev,
@@ -501,7 +502,7 @@ static struct lp55xx_device_config lp5521_cfg = {
        },
        .max_channel  = LP5521_MAX_LEDS,
        .post_init_device   = lp5521_post_init_device,
-       .brightness_work_fn = lp5521_led_brightness_work,
+       .brightness_fn      = lp5521_led_brightness,
        .set_led_current    = lp5521_set_led_current,
        .firmware_cb        = lp5521_firmware_loaded,
        .run_engine         = lp5521_run_engine,
index 1d0187f42941aadfd91eb7b17d36b876484fff51..c5b30f06218a3af833c3dd9724f8871f19048d17 100644 (file)
@@ -802,16 +802,16 @@ leave:
        return ret;
 }
 
-static void lp5523_led_brightness_work(struct work_struct *work)
+static int lp5523_led_brightness(struct lp55xx_led *led)
 {
-       struct lp55xx_led *led = container_of(work, struct lp55xx_led,
-                                             brightness_work);
        struct lp55xx_chip *chip = led->chip;
+       int ret;
 
        mutex_lock(&chip->lock);
-       lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + led->chan_nr,
+       ret = lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + led->chan_nr,
                     led->brightness);
        mutex_unlock(&chip->lock);
+       return ret;
 }
 
 static LP55XX_DEV_ATTR_RW(engine1_mode, show_engine1_mode, store_engine1_mode);
@@ -867,7 +867,7 @@ static struct lp55xx_device_config lp5523_cfg = {
        },
        .max_channel  = LP5523_MAX_LEDS,
        .post_init_device   = lp5523_post_init_device,
-       .brightness_work_fn = lp5523_led_brightness_work,
+       .brightness_fn      = lp5523_led_brightness,
        .set_led_current    = lp5523_set_led_current,
        .firmware_cb        = lp5523_firmware_loaded,
        .run_engine         = lp5523_run_engine,
index 0360c59dbdc91b122d0d08273c48203e6755ca6b..b75333803a63776608acf7e5810c118123c6e166 100644 (file)
@@ -311,10 +311,8 @@ static int lp5562_post_init_device(struct lp55xx_chip *chip)
        return 0;
 }
 
-static void lp5562_led_brightness_work(struct work_struct *work)
+static int lp5562_led_brightness(struct lp55xx_led *led)
 {
-       struct lp55xx_led *led = container_of(work, struct lp55xx_led,
-                                             brightness_work);
        struct lp55xx_chip *chip = led->chip;
        u8 addr[] = {
                LP5562_REG_R_PWM,
@@ -322,10 +320,13 @@ static void lp5562_led_brightness_work(struct work_struct *work)
                LP5562_REG_B_PWM,
                LP5562_REG_W_PWM,
        };
+       int ret;
 
        mutex_lock(&chip->lock);
-       lp55xx_write(chip, addr[led->chan_nr], led->brightness);
+       ret = lp55xx_write(chip, addr[led->chan_nr], led->brightness);
        mutex_unlock(&chip->lock);
+
+       return ret;
 }
 
 static void lp5562_write_program_memory(struct lp55xx_chip *chip,
@@ -503,7 +504,7 @@ static struct lp55xx_device_config lp5562_cfg = {
        },
        .post_init_device   = lp5562_post_init_device,
        .set_led_current    = lp5562_set_led_current,
-       .brightness_work_fn = lp5562_led_brightness_work,
+       .brightness_fn      = lp5562_led_brightness,
        .run_engine         = lp5562_run_engine,
        .firmware_cb        = lp5562_firmware_loaded,
        .dev_attr_group     = &lp5562_group,
index 59b76833f0d32d1d114421ed17b160fd60d2a9c2..5377f22ff994769eba699f93f5cff31cea16bfaf 100644 (file)
@@ -134,13 +134,14 @@ static struct attribute *lp55xx_led_attrs[] = {
 };
 ATTRIBUTE_GROUPS(lp55xx_led);
 
-static void lp55xx_set_brightness(struct led_classdev *cdev,
+static int lp55xx_set_brightness(struct led_classdev *cdev,
                             enum led_brightness brightness)
 {
        struct lp55xx_led *led = cdev_to_lp55xx_led(cdev);
+       struct lp55xx_device_config *cfg = led->chip->cfg;
 
        led->brightness = (u8)brightness;
-       schedule_work(&led->brightness_work);
+       return cfg->brightness_fn(led);
 }
 
 static int lp55xx_init_led(struct lp55xx_led *led,
@@ -172,7 +173,7 @@ static int lp55xx_init_led(struct lp55xx_led *led,
                return -EINVAL;
        }
 
-       led->cdev.brightness_set = lp55xx_set_brightness;
+       led->cdev.brightness_set_blocking = lp55xx_set_brightness;
        led->cdev.groups = lp55xx_led_groups;
 
        if (pdata->led_config[chan].name) {
@@ -464,7 +465,7 @@ int lp55xx_register_leds(struct lp55xx_led *led, struct lp55xx_chip *chip)
        int ret;
        int i;
 
-       if (!cfg->brightness_work_fn) {
+       if (!cfg->brightness_fn) {
                dev_err(&chip->cl->dev, "empty brightness configuration\n");
                return -EINVAL;
        }
@@ -481,8 +482,6 @@ int lp55xx_register_leds(struct lp55xx_led *led, struct lp55xx_chip *chip)
                if (ret)
                        goto err_init_led;
 
-               INIT_WORK(&each->brightness_work, cfg->brightness_work_fn);
-
                chip->num_leds++;
                each->chip = chip;
 
@@ -507,7 +506,6 @@ void lp55xx_unregister_leds(struct lp55xx_led *led, struct lp55xx_chip *chip)
        for (i = 0; i < chip->num_leds; i++) {
                each = led + i;
                led_classdev_unregister(&each->cdev);
-               flush_work(&each->brightness_work);
        }
 }
 EXPORT_SYMBOL_GPL(lp55xx_unregister_leds);
index c7f1e6155001f6eeb76818f6a4dcf3904624c7e8..abf1fb5da37d5d34db57f8f5d82a347257b26f3a 100644 (file)
@@ -95,7 +95,7 @@ struct lp55xx_reg {
  * @enable             : Chip specific enable command
  * @max_channel        : Maximum number of channels
  * @post_init_device   : Chip specific initialization code
- * @brightness_work_fn : Brightness work function
+ * @brightness_fn      : Brightness function
  * @set_led_current    : LED current set function
  * @firmware_cb        : Call function when the firmware is loaded
  * @run_engine         : Run internal engine for pattern
@@ -110,7 +110,7 @@ struct lp55xx_device_config {
        int (*post_init_device) (struct lp55xx_chip *chip);
 
        /* access brightness register */
-       void (*brightness_work_fn)(struct work_struct *work);
+       int (*brightness_fn)(struct lp55xx_led *led);
 
        /* current setting function */
        void (*set_led_current) (struct lp55xx_led *led, u8 led_current);
@@ -164,7 +164,6 @@ struct lp55xx_chip {
  * @cdev            : LED class device
  * @led_current     : Current setting at each led channel
  * @max_current     : Maximun current at each led channel
- * @brightness_work : Workqueue for brightness control
  * @brightness      : Brightness value
  * @chip            : The lp55xx chip data
  */
@@ -173,7 +172,6 @@ struct lp55xx_led {
        struct led_classdev cdev;
        u8 led_current;
        u8 max_current;
-       struct work_struct brightness_work;
        u8 brightness;
        struct lp55xx_chip *chip;
 };
index 3f54f6f2b821d2684f326cda03ac1957ac1015ef..3f9675bd214a404fcd5e771ed87bf4079dacf938 100644 (file)
@@ -272,16 +272,17 @@ static void lp8501_firmware_loaded(struct lp55xx_chip *chip)
        lp8501_update_program_memory(chip, fw->data, fw->size);
 }
 
-static void lp8501_led_brightness_work(struct work_struct *work)
+static int lp8501_led_brightness(struct lp55xx_led *led)
 {
-       struct lp55xx_led *led = container_of(work, struct lp55xx_led,
-                                             brightness_work);
        struct lp55xx_chip *chip = led->chip;
+       int ret;
 
        mutex_lock(&chip->lock);
-       lp55xx_write(chip, LP8501_REG_LED_PWM_BASE + led->chan_nr,
+       ret = lp55xx_write(chip, LP8501_REG_LED_PWM_BASE + led->chan_nr,
                     led->brightness);
        mutex_unlock(&chip->lock);
+
+       return ret;
 }
 
 /* Chip specific configurations */
@@ -296,7 +297,7 @@ static struct lp55xx_device_config lp8501_cfg = {
        },
        .max_channel  = LP8501_MAX_LEDS,
        .post_init_device   = lp8501_post_init_device,
-       .brightness_work_fn = lp8501_led_brightness_work,
+       .brightness_fn      = lp8501_led_brightness,
        .set_led_current    = lp8501_set_led_current,
        .firmware_cb        = lp8501_firmware_loaded,
        .run_engine         = lp8501_run_engine,
index 3409f03c1fa8a5095ad37b8ff3b08b220cb58179..0eee38fc05651294cf63f433d331e74942746441 100644 (file)
 struct lp8788_led {
        struct lp8788 *lp;
        struct mutex lock;
-       struct work_struct work;
        struct led_classdev led_dev;
        enum lp8788_isink_number isink_num;
-       enum led_brightness brightness;
        int on;
 };
 
@@ -76,24 +74,29 @@ static int lp8788_led_init_device(struct lp8788_led *led,
        return lp8788_update_bits(led->lp, addr, mask, val);
 }
 
-static void lp8788_led_enable(struct lp8788_led *led,
+static int lp8788_led_enable(struct lp8788_led *led,
                        enum lp8788_isink_number num, int on)
 {
+       int ret;
+
        u8 mask = 1 << num;
        u8 val = on << num;
 
-       if (lp8788_update_bits(led->lp, LP8788_ISINK_CTRL, mask, val))
-               return;
+       ret = lp8788_update_bits(led->lp, LP8788_ISINK_CTRL, mask, val);
+       if (ret == 0)
+               led->on = on;
 
-       led->on = on;
+       return ret;
 }
 
-static void lp8788_led_work(struct work_struct *work)
+static int lp8788_brightness_set(struct led_classdev *led_cdev,
+                               enum led_brightness val)
 {
-       struct lp8788_led *led = container_of(work, struct lp8788_led, work);
+       struct lp8788_led *led =
+                       container_of(led_cdev, struct lp8788_led, led_dev);
+
        enum lp8788_isink_number num = led->isink_num;
-       int enable;
-       u8 val = led->brightness;
+       int enable, ret;
 
        mutex_lock(&led->lock);
 
@@ -101,28 +104,21 @@ static void lp8788_led_work(struct work_struct *work)
        case LP8788_ISINK_1:
        case LP8788_ISINK_2:
        case LP8788_ISINK_3:
-               lp8788_write_byte(led->lp, lp8788_pwm_addr[num], val);
+               ret = lp8788_write_byte(led->lp, lp8788_pwm_addr[num], val);
+               if (ret < 0)
+                       goto unlock;
                break;
        default:
                mutex_unlock(&led->lock);
-               return;
+               return -EINVAL;
        }
 
        enable = (val > 0) ? 1 : 0;
        if (enable != led->on)
-               lp8788_led_enable(led, num, enable);
-
+               ret = lp8788_led_enable(led, num, enable);
+unlock:
        mutex_unlock(&led->lock);
-}
-
-static void lp8788_brightness_set(struct led_classdev *led_cdev,
-                               enum led_brightness brt_val)
-{
-       struct lp8788_led *led =
-                       container_of(led_cdev, struct lp8788_led, led_dev);
-
-       led->brightness = brt_val;
-       schedule_work(&led->work);
+       return ret;
 }
 
 static int lp8788_led_probe(struct platform_device *pdev)
@@ -139,7 +135,7 @@ static int lp8788_led_probe(struct platform_device *pdev)
 
        led->lp = lp;
        led->led_dev.max_brightness = MAX_BRIGHTNESS;
-       led->led_dev.brightness_set = lp8788_brightness_set;
+       led->led_dev.brightness_set_blocking = lp8788_brightness_set;
 
        led_pdata = lp->pdata ? lp->pdata->led_pdata : NULL;
 
@@ -149,7 +145,6 @@ static int lp8788_led_probe(struct platform_device *pdev)
                led->led_dev.name = led_pdata->name;
 
        mutex_init(&led->lock);
-       INIT_WORK(&led->work, lp8788_led_work);
 
        platform_set_drvdata(pdev, led);
 
@@ -173,7 +168,6 @@ static int lp8788_led_remove(struct platform_device *pdev)
        struct lp8788_led *led = platform_get_drvdata(pdev);
 
        led_classdev_unregister(&led->led_dev);
-       flush_work(&led->work);
 
        return 0;
 }
index 79f084354e679930f1efa36f30745e867ed72b27..3e70775a2d54eaab717f5e61a4f3580bd28a492d 100644 (file)
 /**
  * struct lp8860_led -
  * @lock - Lock for reading/writing the device
- * @work - Work item used to off load the brightness register writes
  * @client - Pointer to the I2C client
  * @led_dev - led class device pointer
  * @regmap - Devices register map
  * @eeprom_regmap - EEPROM register map
  * @enable_gpio - VDDIO/EN gpio to enable communication interface
  * @regulator - LED supply regulator pointer
- * @brightness - Current brightness value requested
  * @label - LED label
 **/
 struct lp8860_led {
        struct mutex lock;
-       struct work_struct work;
        struct i2c_client *client;
        struct led_classdev led_dev;
        struct regmap *regmap;
        struct regmap *eeprom_regmap;
        struct gpio_desc *enable_gpio;
        struct regulator *regulator;
-       enum led_brightness brightness;
        const char *label;
 };
 
@@ -212,11 +208,13 @@ out:
        return ret;
 }
 
-static void lp8860_led_brightness_work(struct work_struct *work)
+static int lp8860_brightness_set(struct led_classdev *led_cdev,
+                               enum led_brightness brt_val)
 {
-       struct lp8860_led *led = container_of(work, struct lp8860_led, work);
+       struct lp8860_led *led =
+                       container_of(led_cdev, struct lp8860_led, led_dev);
+       int disp_brightness = brt_val * 255;
        int ret;
-       int disp_brightness = led->brightness * 255;
 
        mutex_lock(&led->lock);
 
@@ -241,16 +239,7 @@ static void lp8860_led_brightness_work(struct work_struct *work)
        }
 out:
        mutex_unlock(&led->lock);
-}
-
-static void lp8860_brightness_set(struct led_classdev *led_cdev,
-                               enum led_brightness brt_val)
-{
-       struct lp8860_led *led =
-                       container_of(led_cdev, struct lp8860_led, led_dev);
-
-       led->brightness = brt_val;
-       schedule_work(&led->work);
+       return ret;
 }
 
 static int lp8860_init(struct lp8860_led *led)
@@ -406,10 +395,9 @@ static int lp8860_probe(struct i2c_client *client,
        led->client = client;
        led->led_dev.name = led->label;
        led->led_dev.max_brightness = LED_FULL;
-       led->led_dev.brightness_set = lp8860_brightness_set;
+       led->led_dev.brightness_set_blocking = lp8860_brightness_set;
 
        mutex_init(&led->lock);
-       INIT_WORK(&led->work, lp8860_led_brightness_work);
 
        i2c_set_clientdata(client, led);
 
@@ -448,7 +436,6 @@ static int lp8860_remove(struct i2c_client *client)
        int ret;
 
        led_classdev_unregister(&led->led_dev);
-       cancel_work_sync(&led->work);
 
        if (led->enable_gpio)
                gpiod_direction_output(led->enable_gpio, 0);
index 9f41124765cc5503044fc1af4fd5cba4a992d73c..a7ff510cbdd06e113ee5e744ea0c1c9eb8c4618e 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
-#include <linux/workqueue.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
 struct lt3593_led_data {
        struct led_classdev cdev;
        unsigned gpio;
-       struct work_struct work;
-       u8 new_level;
 };
 
-static void lt3593_led_work(struct work_struct *work)
+static int lt3593_led_set(struct led_classdev *led_cdev,
+                          enum led_brightness value)
 {
-       int pulses;
        struct lt3593_led_data *led_dat =
-               container_of(work, struct lt3593_led_data, work);
+               container_of(led_cdev, struct lt3593_led_data, cdev);
+       int pulses;
 
        /*
         * The LT3593 resets its internal current level register to the maximum
@@ -47,18 +45,18 @@ static void lt3593_led_work(struct work_struct *work)
         * applied is to the output driver.
         */
 
-       if (led_dat->new_level == 0) {
+       if (value == 0) {
                gpio_set_value_cansleep(led_dat->gpio, 0);
-               return;
+               return 0;
        }
 
-       pulses = 32 - (led_dat->new_level * 32) / 255;
+       pulses = 32 - (value * 32) / 255;
 
        if (pulses == 0) {
                gpio_set_value_cansleep(led_dat->gpio, 0);
                mdelay(1);
                gpio_set_value_cansleep(led_dat->gpio, 1);
-               return;
+               return 0;
        }
 
        gpio_set_value_cansleep(led_dat->gpio, 1);
@@ -69,16 +67,8 @@ static void lt3593_led_work(struct work_struct *work)
                gpio_set_value_cansleep(led_dat->gpio, 1);
                udelay(1);
        }
-}
 
-static void lt3593_led_set(struct led_classdev *led_cdev,
-       enum led_brightness value)
-{
-       struct lt3593_led_data *led_dat =
-               container_of(led_cdev, struct lt3593_led_data, cdev);
-
-       led_dat->new_level = value;
-       schedule_work(&led_dat->work);
+       return 0;
 }
 
 static int create_lt3593_led(const struct gpio_led *template,
@@ -97,7 +87,7 @@ static int create_lt3593_led(const struct gpio_led *template,
        led_dat->cdev.default_trigger = template->default_trigger;
        led_dat->gpio = template->gpio;
 
-       led_dat->cdev.brightness_set = lt3593_led_set;
+       led_dat->cdev.brightness_set_blocking = lt3593_led_set;
 
        state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
        led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
@@ -111,8 +101,6 @@ static int create_lt3593_led(const struct gpio_led *template,
        if (ret < 0)
                return ret;
 
-       INIT_WORK(&led_dat->work, lt3593_led_work);
-
        ret = led_classdev_register(parent, &led_dat->cdev);
        if (ret < 0)
                return ret;
@@ -129,7 +117,6 @@ static void delete_lt3593_led(struct lt3593_led_data *led)
                return;
 
        led_classdev_unregister(&led->cdev);
-       cancel_work_sync(&led->work);
 }
 
 static int lt3593_led_probe(struct platform_device *pdev)
index afbb1409b2e24a1a5c6636409e9cf874f84955e4..1eb58ef6aefe44c888dd52a7ddb10631231d92f0 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
-#include <linux/workqueue.h>
 #include <media/v4l2-flash-led-class.h>
 
 #define MODE_OFF               0
@@ -62,8 +61,6 @@ struct max77693_sub_led {
        int fled_id;
        /* corresponding LED Flash class device */
        struct led_classdev_flash fled_cdev;
-       /* assures led-triggers compatibility */
-       struct work_struct work_brightness_set;
        /* V4L2 Flash device */
        struct v4l2_flash *v4l2_flash;
 
@@ -463,10 +460,14 @@ static int max77693_setup(struct max77693_led_device *led,
        return max77693_set_mode_reg(led, MODE_OFF);
 }
 
-static int __max77693_led_brightness_set(struct max77693_led_device *led,
-                                       int fled_id, enum led_brightness value)
+/* LED subsystem callbacks */
+static int max77693_led_brightness_set(struct led_classdev *led_cdev,
+                                       enum led_brightness value)
 {
-       int ret;
+       struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+       struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
+       struct max77693_led_device *led = sub_led_to_led(sub_led);
+       int fled_id = sub_led->fled_id, ret;
 
        mutex_lock(&led->lock);
 
@@ -494,43 +495,8 @@ static int __max77693_led_brightness_set(struct max77693_led_device *led,
                        ret);
 unlock:
        mutex_unlock(&led->lock);
-       return ret;
-}
-
-static void max77693_led_brightness_set_work(
-                                       struct work_struct *work)
-{
-       struct max77693_sub_led *sub_led =
-                       container_of(work, struct max77693_sub_led,
-                                       work_brightness_set);
-       struct max77693_led_device *led = sub_led_to_led(sub_led);
-
-       __max77693_led_brightness_set(led, sub_led->fled_id,
-                               sub_led->torch_brightness);
-}
-
-/* LED subsystem callbacks */
-
-static int max77693_led_brightness_set_sync(
-                               struct led_classdev *led_cdev,
-                               enum led_brightness value)
-{
-       struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
-       struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
-       struct max77693_led_device *led = sub_led_to_led(sub_led);
-
-       return __max77693_led_brightness_set(led, sub_led->fled_id, value);
-}
 
-static void max77693_led_brightness_set(
-                               struct led_classdev *led_cdev,
-                               enum led_brightness value)
-{
-       struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
-       struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
-
-       sub_led->torch_brightness = value;
-       schedule_work(&sub_led->work_brightness_set);
+       return ret;
 }
 
 static int max77693_led_flash_brightness_set(
@@ -682,6 +648,7 @@ static int max77693_led_parse_dt(struct max77693_led_device *led,
                if (sub_nodes[fled_id]) {
                        dev_err(dev,
                                "Conflicting \"led-sources\" DT properties\n");
+                       of_node_put(child_node);
                        return -EINVAL;
                }
 
@@ -931,16 +898,13 @@ static void max77693_init_fled_cdev(struct max77693_sub_led *sub_led,
 
        led_cdev->name = led_cfg->label[fled_id];
 
-       led_cdev->brightness_set = max77693_led_brightness_set;
-       led_cdev->brightness_set_sync = max77693_led_brightness_set_sync;
+       led_cdev->brightness_set_blocking = max77693_led_brightness_set;
        led_cdev->max_brightness = (led->iout_joint ?
                                        led_cfg->iout_torch_max[FLED1] +
                                        led_cfg->iout_torch_max[FLED2] :
                                        led_cfg->iout_torch_max[fled_id]) /
                                   TORCH_IOUT_STEP;
        led_cdev->flags |= LED_DEV_CAP_FLASH;
-       INIT_WORK(&sub_led->work_brightness_set,
-                       max77693_led_brightness_set_work);
 
        max77693_init_flash_settings(sub_led, led_cfg);
 
@@ -1062,13 +1026,11 @@ static int max77693_led_remove(struct platform_device *pdev)
        if (led->iout_joint || max77693_fled_used(led, FLED1)) {
                v4l2_flash_release(sub_leds[FLED1].v4l2_flash);
                led_classdev_flash_unregister(&sub_leds[FLED1].fled_cdev);
-               cancel_work_sync(&sub_leds[FLED1].work_brightness_set);
        }
 
        if (!led->iout_joint && max77693_fled_used(led, FLED2)) {
                v4l2_flash_release(sub_leds[FLED2].v4l2_flash);
                led_classdev_flash_unregister(&sub_leds[FLED2].fled_cdev);
-               cancel_work_sync(&sub_leds[FLED2].work_brightness_set);
        }
 
        mutex_destroy(&led->lock);
index c592aa5662bb466f728d6c6ce5f204850fc3ec80..01b4590693582c8a0eeaa34bf955535342017c52 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/module.h>
 #include <linux/err.h>
 #include <linux/slab.h>
-#include <linux/workqueue.h>
 #include <linux/leds.h>
 #include <linux/mfd/max8997.h>
 #include <linux/mfd/max8997-private.h>
index e2b847fe22a1c9343d1bb37020000b470ccd7ff7..a2e4c1792e17cb2f4d5ce8f9faf30e30da289f66 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/platform_device.h>
 #include <linux/leds.h>
 #include <linux/of.h>
-#include <linux/workqueue.h>
 #include <linux/mfd/mc13xxx.h>
 
 struct mc13xxx_led_devtype {
@@ -32,8 +31,6 @@ struct mc13xxx_led_devtype {
 
 struct mc13xxx_led {
        struct led_classdev     cdev;
-       struct work_struct      work;
-       enum led_brightness     new_brightness;
        int                     id;
        struct mc13xxx_leds     *leds;
 };
@@ -55,9 +52,11 @@ static unsigned int mc13xxx_max_brightness(int id)
        return 0x3f;
 }
 
-static void mc13xxx_led_work(struct work_struct *work)
+static int mc13xxx_led_set(struct led_classdev *led_cdev,
+                           enum led_brightness value)
 {
-       struct mc13xxx_led *led = container_of(work, struct mc13xxx_led, work);
+       struct mc13xxx_led *led =
+               container_of(led_cdev, struct mc13xxx_led, cdev);
        struct mc13xxx_leds *leds = led->leds;
        unsigned int reg, bank, off, shift;
 
@@ -105,19 +104,9 @@ static void mc13xxx_led_work(struct work_struct *work)
                BUG();
        }
 
-       mc13xxx_reg_rmw(leds->master, leds->devtype->ledctrl_base + reg,
+       return mc13xxx_reg_rmw(leds->master, leds->devtype->ledctrl_base + reg,
                        mc13xxx_max_brightness(led->id) << shift,
-                       led->new_brightness << shift);
-}
-
-static void mc13xxx_led_set(struct led_classdev *led_cdev,
-                           enum led_brightness value)
-{
-       struct mc13xxx_led *led =
-               container_of(led_cdev, struct mc13xxx_led, cdev);
-
-       led->new_brightness = value;
-       schedule_work(&led->work);
+                       value << shift);
 }
 
 #ifdef CONFIG_OF
@@ -257,11 +246,9 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev)
                leds->led[i].cdev.name = name;
                leds->led[i].cdev.default_trigger = trig;
                leds->led[i].cdev.flags = LED_CORE_SUSPENDRESUME;
-               leds->led[i].cdev.brightness_set = mc13xxx_led_set;
+               leds->led[i].cdev.brightness_set_blocking = mc13xxx_led_set;
                leds->led[i].cdev.max_brightness = mc13xxx_max_brightness(id);
 
-               INIT_WORK(&leds->led[i].work, mc13xxx_led_work);
-
                ret = led_classdev_register(dev->parent, &leds->led[i].cdev);
                if (ret) {
                        dev_err(dev, "Failed to register LED %i\n", id);
@@ -270,10 +257,8 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev)
        }
 
        if (ret)
-               while (--i >= 0) {
+               while (--i >= 0)
                        led_classdev_unregister(&leds->led[i].cdev);
-                       cancel_work_sync(&leds->led[i].work);
-               }
 
        return ret;
 }
@@ -283,10 +268,8 @@ static int mc13xxx_led_remove(struct platform_device *pdev)
        struct mc13xxx_leds *leds = platform_get_drvdata(pdev);
        int i;
 
-       for (i = 0; i < leds->num_leds; i++) {
+       for (i = 0; i < leds->num_leds; i++)
                led_classdev_unregister(&leds->led[i].cdev);
-               cancel_work_sync(&leds->led[i].work);
-       }
 
        return 0;
 }
index a95a61220169ddc8099ba127d01cdb0db3a5adcb..506b75b190e7325a46ac8517dcdcf651c50d7050 100644 (file)
@@ -45,24 +45,12 @@ struct ns2_led_data {
        unsigned                cmd;
        unsigned                slow;
        bool                    can_sleep;
-       int                     mode_index;
        unsigned char           sata; /* True when SATA mode active. */
        rwlock_t                rw_lock; /* Lock GPIOs. */
-       struct work_struct      work;
        int                     num_modes;
        struct ns2_led_modval   *modval;
 };
 
-static void ns2_led_work(struct work_struct *work)
-{
-       struct ns2_led_data *led_dat =
-               container_of(work, struct ns2_led_data, work);
-       int i = led_dat->mode_index;
-
-       gpio_set_value_cansleep(led_dat->cmd, led_dat->modval[i].cmd_level);
-       gpio_set_value_cansleep(led_dat->slow, led_dat->modval[i].slow_level);
-}
-
 static int ns2_led_get_mode(struct ns2_led_data *led_dat,
                            enum ns2_led_modes *mode)
 {
@@ -112,8 +100,8 @@ static void ns2_led_set_mode(struct ns2_led_data *led_dat,
                goto exit_unlock;
        }
 
-       led_dat->mode_index = i;
-       schedule_work(&led_dat->work);
+       gpio_set_value_cansleep(led_dat->cmd, led_dat->modval[i].cmd_level);
+       gpio_set_value_cansleep(led_dat->slow, led_dat->modval[i].slow_level);
 
 exit_unlock:
        write_unlock_irqrestore(&led_dat->rw_lock, flags);
@@ -136,6 +124,13 @@ static void ns2_led_set(struct led_classdev *led_cdev,
        ns2_led_set_mode(led_dat, mode);
 }
 
+static int ns2_led_set_blocking(struct led_classdev *led_cdev,
+                       enum led_brightness value)
+{
+       ns2_led_set(led_cdev, value);
+       return 0;
+}
+
 static ssize_t ns2_led_sata_store(struct device *dev,
                                  struct device_attribute *attr,
                                  const char *buff, size_t count)
@@ -219,13 +214,16 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
        led_dat->cdev.name = template->name;
        led_dat->cdev.default_trigger = template->default_trigger;
        led_dat->cdev.blink_set = NULL;
-       led_dat->cdev.brightness_set = ns2_led_set;
        led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
        led_dat->cdev.groups = ns2_led_groups;
        led_dat->cmd = template->cmd;
        led_dat->slow = template->slow;
        led_dat->can_sleep = gpio_cansleep(led_dat->cmd) |
                                gpio_cansleep(led_dat->slow);
+       if (led_dat->can_sleep)
+               led_dat->cdev.brightness_set_blocking = ns2_led_set_blocking;
+       else
+               led_dat->cdev.brightness_set = ns2_led_set;
        led_dat->modval = template->modval;
        led_dat->num_modes = template->num_modes;
 
@@ -238,8 +236,6 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
        led_dat->cdev.brightness =
                (mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL;
 
-       INIT_WORK(&led_dat->work, ns2_led_work);
-
        ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
        if (ret < 0)
                return ret;
@@ -250,7 +246,6 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
 static void delete_ns2_led(struct ns2_led_data *led_dat)
 {
        led_classdev_unregister(&led_dat->cdev);
-       cancel_work_sync(&led_dat->work);
 }
 
 #ifdef CONFIG_OF_GPIO
index 5a6363d161a2f91e203a58923a3b09cc26a980b9..17c63ec9fb9e45fecda26e4b3e447653ece91f57 100644 (file)
@@ -158,7 +158,7 @@ static void pca9532_setled(struct pca9532_led *led)
        mutex_unlock(&data->update_lock);
 }
 
-static void pca9532_set_brightness(struct led_classdev *led_cdev,
+static int pca9532_set_brightness(struct led_classdev *led_cdev,
        enum led_brightness value)
 {
        int err = 0;
@@ -172,9 +172,12 @@ static void pca9532_set_brightness(struct led_classdev *led_cdev,
                led->state = PCA9532_PWM0; /* Thecus: hardcode one pwm */
                err = pca9532_calcpwm(led->client, 0, 0, value);
                if (err)
-                       return; /* XXX: led api doesn't allow error code? */
+                       return err;
        }
-       schedule_work(&led->work);
+       if (led->state == PCA9532_PWM0)
+               pca9532_setpwm(led->client, 0);
+       pca9532_setled(led);
+       return err;
 }
 
 static int pca9532_set_blink(struct led_classdev *led_cdev,
@@ -198,7 +201,10 @@ static int pca9532_set_blink(struct led_classdev *led_cdev,
        err = pca9532_calcpwm(client, 0, psc, led_cdev->brightness);
        if (err)
                return err;
-       schedule_work(&led->work);
+       if (led->state == PCA9532_PWM0)
+               pca9532_setpwm(led->client, 0);
+       pca9532_setled(led);
+
        return 0;
 }
 
@@ -233,15 +239,6 @@ static void pca9532_input_work(struct work_struct *work)
        mutex_unlock(&data->update_lock);
 }
 
-static void pca9532_led_work(struct work_struct *work)
-{
-       struct pca9532_led *led;
-       led = container_of(work, struct pca9532_led, work);
-       if (led->state == PCA9532_PWM0)
-               pca9532_setpwm(led->client, 0);
-       pca9532_setled(led);
-}
-
 #ifdef CONFIG_LEDS_PCA9532_GPIO
 static int pca9532_gpio_request_pin(struct gpio_chip *gc, unsigned offset)
 {
@@ -307,7 +304,6 @@ static int pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
                        break;
                case PCA9532_TYPE_LED:
                        led_classdev_unregister(&data->leds[i].ldev);
-                       cancel_work_sync(&data->leds[i].work);
                        break;
                case PCA9532_TYPE_N2100_BEEP:
                        if (data->idev != NULL) {
@@ -359,9 +355,9 @@ static int pca9532_configure(struct i2c_client *client,
                        led->name = pled->name;
                        led->ldev.name = led->name;
                        led->ldev.brightness = LED_OFF;
-                       led->ldev.brightness_set = pca9532_set_brightness;
+                       led->ldev.brightness_set_blocking =
+                                               pca9532_set_brightness;
                        led->ldev.blink_set = pca9532_set_blink;
-                       INIT_WORK(&led->work, pca9532_led_work);
                        err = led_classdev_register(&client->dev, &led->ldev);
                        if (err < 0) {
                                dev_err(&client->dev,
index b775e1efecd3b6711acd61847652caf2352f194c..840401ae9a4ea210d02d02b2efa7bbdfc015b000 100644 (file)
@@ -47,7 +47,6 @@
 #include <linux/leds.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
-#include <linux/workqueue.h>
 #include <linux/slab.h>
 
 /* LED select registers determine the source that drives LED outputs */
@@ -110,8 +109,6 @@ struct pca955x {
 
 struct pca955x_led {
        struct pca955x  *pca955x;
-       struct work_struct      work;
-       enum led_brightness     brightness;
        struct led_classdev     led_cdev;
        int                     led_num;        /* 0 .. 15 potentially */
        char                    name[32];
@@ -193,7 +190,8 @@ static u8 pca955x_read_ls(struct i2c_client *client, int n)
                pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n);
 }
 
-static void pca955x_led_work(struct work_struct *work)
+static int pca955x_led_set(struct led_classdev *led_cdev,
+                           enum led_brightness value)
 {
        struct pca955x_led *pca955x_led;
        struct pca955x *pca955x;
@@ -201,7 +199,7 @@ static void pca955x_led_work(struct work_struct *work)
        int chip_ls;    /* which LSx to use (0-3 potentially) */
        int ls_led;     /* which set of bits within LSx to use (0-3) */
 
-       pca955x_led = container_of(work, struct pca955x_led, work);
+       pca955x_led = container_of(led_cdev, struct pca955x_led, led_cdev);
        pca955x = pca955x_led->pca955x;
 
        chip_ls = pca955x_led->led_num / 4;
@@ -211,7 +209,7 @@ static void pca955x_led_work(struct work_struct *work)
 
        ls = pca955x_read_ls(pca955x->client, chip_ls);
 
-       switch (pca955x_led->brightness) {
+       switch (value) {
        case LED_FULL:
                ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_LED_ON);
                break;
@@ -230,7 +228,7 @@ static void pca955x_led_work(struct work_struct *work)
                 * just turning off for all other values.
                 */
                pca955x_write_pwm(pca955x->client, 1,
-                               255 - pca955x_led->brightness);
+                               255 - value);
                ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_BLINK1);
                break;
        }
@@ -238,21 +236,8 @@ static void pca955x_led_work(struct work_struct *work)
        pca955x_write_ls(pca955x->client, chip_ls, ls);
 
        mutex_unlock(&pca955x->lock);
-}
-
-static void pca955x_led_set(struct led_classdev *led_cdev, enum led_brightness value)
-{
-       struct pca955x_led *pca955x;
-
-       pca955x = container_of(led_cdev, struct pca955x_led, led_cdev);
-
-       pca955x->brightness = value;
 
-       /*
-        * Must use workqueue for the actual I/O since I2C operations
-        * can sleep.
-        */
-       schedule_work(&pca955x->work);
+       return 0;
 }
 
 static int pca955x_probe(struct i2c_client *client,
@@ -328,9 +313,7 @@ static int pca955x_probe(struct i2c_client *client,
                }
 
                pca955x_led->led_cdev.name = pca955x_led->name;
-               pca955x_led->led_cdev.brightness_set = pca955x_led_set;
-
-               INIT_WORK(&pca955x_led->work, pca955x_led_work);
+               pca955x_led->led_cdev.brightness_set_blocking = pca955x_led_set;
 
                err = led_classdev_register(&client->dev,
                                        &pca955x_led->led_cdev);
@@ -355,10 +338,8 @@ static int pca955x_probe(struct i2c_client *client,
        return 0;
 
 exit:
-       while (i--) {
+       while (i--)
                led_classdev_unregister(&pca955x->leds[i].led_cdev);
-               cancel_work_sync(&pca955x->leds[i].work);
-       }
 
        return err;
 }
@@ -368,10 +349,8 @@ static int pca955x_remove(struct i2c_client *client)
        struct pca955x *pca955x = i2c_get_clientdata(client);
        int i;
 
-       for (i = 0; i < pca955x->chipdef->bits; i++) {
+       for (i = 0; i < pca955x->chipdef->bits; i++)
                led_classdev_unregister(&pca955x->leds[i].led_cdev);
-               cancel_work_sync(&pca955x->leds[i].work);
-       }
 
        return 0;
 }
index 41f269fe09205f48c3216179d30da652a4574bb3..407eba11e187906e8d84d3aa4998d4020f11e522 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/leds.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
-#include <linux/workqueue.h>
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/platform_data/leds-pca963x.h>
@@ -96,11 +95,6 @@ static const struct i2c_device_id pca963x_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, pca963x_id);
 
-enum pca963x_cmd {
-       BRIGHTNESS_SET,
-       BLINK_SET,
-};
-
 struct pca963x_led;
 
 struct pca963x {
@@ -112,47 +106,52 @@ struct pca963x {
 
 struct pca963x_led {
        struct pca963x *chip;
-       struct work_struct work;
-       enum led_brightness brightness;
        struct led_classdev led_cdev;
        int led_num; /* 0 .. 15 potentially */
-       enum pca963x_cmd cmd;
        char name[32];
        u8 gdc;
        u8 gfrq;
 };
 
-static void pca963x_brightness_work(struct pca963x_led *pca963x)
+static int pca963x_brightness(struct pca963x_led *pca963x,
+                              enum led_brightness brightness)
 {
        u8 ledout_addr = pca963x->chip->chipdef->ledout_base
                + (pca963x->led_num / 4);
        u8 ledout;
        int shift = 2 * (pca963x->led_num % 4);
        u8 mask = 0x3 << shift;
+       int ret;
 
        mutex_lock(&pca963x->chip->mutex);
        ledout = i2c_smbus_read_byte_data(pca963x->chip->client, ledout_addr);
-       switch (pca963x->brightness) {
+       switch (brightness) {
        case LED_FULL:
-               i2c_smbus_write_byte_data(pca963x->chip->client, ledout_addr,
+               ret = i2c_smbus_write_byte_data(pca963x->chip->client,
+                       ledout_addr,
                        (ledout & ~mask) | (PCA963X_LED_ON << shift));
                break;
        case LED_OFF:
-               i2c_smbus_write_byte_data(pca963x->chip->client, ledout_addr,
-                       ledout & ~mask);
+               ret = i2c_smbus_write_byte_data(pca963x->chip->client,
+                       ledout_addr, ledout & ~mask);
                break;
        default:
-               i2c_smbus_write_byte_data(pca963x->chip->client,
+               ret = i2c_smbus_write_byte_data(pca963x->chip->client,
                        PCA963X_PWM_BASE + pca963x->led_num,
-                       pca963x->brightness);
-               i2c_smbus_write_byte_data(pca963x->chip->client, ledout_addr,
+                       brightness);
+               if (ret < 0)
+                       goto unlock;
+               ret = i2c_smbus_write_byte_data(pca963x->chip->client,
+                       ledout_addr,
                        (ledout & ~mask) | (PCA963X_LED_PWM << shift));
                break;
        }
+unlock:
        mutex_unlock(&pca963x->chip->mutex);
+       return ret;
 }
 
-static void pca963x_blink_work(struct pca963x_led *pca963x)
+static void pca963x_blink(struct pca963x_led *pca963x)
 {
        u8 ledout_addr = pca963x->chip->chipdef->ledout_base +
                (pca963x->led_num / 4);
@@ -180,36 +179,14 @@ static void pca963x_blink_work(struct pca963x_led *pca963x)
        mutex_unlock(&pca963x->chip->mutex);
 }
 
-static void pca963x_work(struct work_struct *work)
-{
-       struct pca963x_led *pca963x = container_of(work,
-               struct pca963x_led, work);
-
-       switch (pca963x->cmd) {
-       case BRIGHTNESS_SET:
-               pca963x_brightness_work(pca963x);
-               break;
-       case BLINK_SET:
-               pca963x_blink_work(pca963x);
-               break;
-       }
-}
-
-static void pca963x_led_set(struct led_classdev *led_cdev,
+static int pca963x_led_set(struct led_classdev *led_cdev,
        enum led_brightness value)
 {
        struct pca963x_led *pca963x;
 
        pca963x = container_of(led_cdev, struct pca963x_led, led_cdev);
 
-       pca963x->cmd = BRIGHTNESS_SET;
-       pca963x->brightness = value;
-
-       /*
-        * Must use workqueue for the actual I/O since I2C operations
-        * can sleep.
-        */
-       schedule_work(&pca963x->work);
+       return pca963x_brightness(pca963x, value);
 }
 
 static int pca963x_blink_set(struct led_classdev *led_cdev,
@@ -254,15 +231,10 @@ static int pca963x_blink_set(struct led_classdev *led_cdev,
         */
        gfrq = (period * 24 / 1000) - 1;
 
-       pca963x->cmd = BLINK_SET;
        pca963x->gdc = gdc;
        pca963x->gfrq = gfrq;
 
-       /*
-        * Must use workqueue for the actual I/O since I2C operations
-        * can sleep.
-        */
-       schedule_work(&pca963x->work);
+       pca963x_blink(pca963x);
 
        *delay_on = time_on;
        *delay_off = time_off;
@@ -409,13 +381,11 @@ static int pca963x_probe(struct i2c_client *client,
                                 client->addr, i);
 
                pca963x[i].led_cdev.name = pca963x[i].name;
-               pca963x[i].led_cdev.brightness_set = pca963x_led_set;
+               pca963x[i].led_cdev.brightness_set_blocking = pca963x_led_set;
 
                if (pdata && pdata->blink_type == PCA963X_HW_BLINK)
                        pca963x[i].led_cdev.blink_set = pca963x_blink_set;
 
-               INIT_WORK(&pca963x[i].work, pca963x_work);
-
                err = led_classdev_register(&client->dev, &pca963x[i].led_cdev);
                if (err < 0)
                        goto exit;
@@ -435,10 +405,8 @@ static int pca963x_probe(struct i2c_client *client,
        return 0;
 
 exit:
-       while (i--) {
+       while (i--)
                led_classdev_unregister(&pca963x[i].led_cdev);
-               cancel_work_sync(&pca963x[i].work);
-       }
 
        return err;
 }
@@ -448,10 +416,8 @@ static int pca963x_remove(struct i2c_client *client)
        struct pca963x *pca963x = i2c_get_clientdata(client);
        int i;
 
-       for (i = 0; i < pca963x->chipdef->n_leds; i++) {
+       for (i = 0; i < pca963x->chipdef->n_leds; i++)
                led_classdev_unregister(&pca963x->leds[i].led_cdev);
-               cancel_work_sync(&pca963x->leds[i].work);
-       }
 
        return 0;
 }
index 1e75e1fe9b726d83b7cd8a317fce7c4c727bf82c..dfb8bd390125357fd6e1660d4257ba564a5ab72c 100644 (file)
@@ -77,7 +77,7 @@ static int powernv_get_led_type(const char *led_type_desc)
  * This function is called from work queue task context when ever it gets
  * scheduled. This function can sleep at opal_async_wait_response call.
  */
-static void powernv_led_set(struct powernv_led_data *powernv_led,
+static int powernv_led_set(struct powernv_led_data *powernv_led,
                            enum led_brightness value)
 {
        int rc, token;
@@ -99,7 +99,7 @@ static void powernv_led_set(struct powernv_led_data *powernv_led,
                if (token != -ERESTARTSYS)
                        dev_err(dev, "%s: Couldn't get OPAL async token\n",
                                __func__);
-               return;
+               return token;
        }
 
        rc = opal_leds_set_ind(token, powernv_led->loc_code,
@@ -125,6 +125,7 @@ static void powernv_led_set(struct powernv_led_data *powernv_led,
 
 out_token:
        opal_async_release_token(token);
+       return rc;
 }
 
 /*
@@ -173,20 +174,23 @@ static enum led_brightness powernv_led_get(struct powernv_led_data *powernv_led)
  * LED classdev 'brightness_get' function. This schedules work
  * to update LED state.
  */
-static void powernv_brightness_set(struct led_classdev *led_cdev,
+static int powernv_brightness_set(struct led_classdev *led_cdev,
                                   enum led_brightness value)
 {
        struct powernv_led_data *powernv_led =
                container_of(led_cdev, struct powernv_led_data, cdev);
        struct powernv_led_common *powernv_led_common = powernv_led->common;
+       int rc;
 
        /* Do not modify LED in unload path */
        if (powernv_led_common->led_disabled)
-               return;
+               return 0;
 
        mutex_lock(&powernv_led_common->lock);
-       powernv_led_set(powernv_led, value);
+       rc = powernv_led_set(powernv_led, value);
        mutex_unlock(&powernv_led_common->lock);
+
+       return rc;
 }
 
 /* LED classdev 'brightness_get' function */
@@ -227,7 +231,7 @@ static int powernv_led_create(struct device *dev,
                return -ENOMEM;
        }
 
-       powernv_led->cdev.brightness_set = powernv_brightness_set;
+       powernv_led->cdev.brightness_set_blocking = powernv_brightness_set;
        powernv_led->cdev.brightness_get = powernv_brightness_get;
        powernv_led->cdev.brightness = LED_OFF;
        powernv_led->cdev.max_brightness = LED_FULL;
@@ -256,8 +260,6 @@ static int powernv_led_classdev(struct platform_device *pdev,
 
        for_each_child_of_node(led_node, np) {
                p = of_find_property(np, "led-types", NULL);
-               if (!p)
-                       continue;
 
                while ((cur = of_prop_next_string(p, cur)) != NULL) {
                        powernv_led = devm_kzalloc(dev, sizeof(*powernv_led),
index 1d07e3e83d29ef8110824d905bcee09e411bc681..4783bacb2e9d8e48c043223fd89643069d93f4b9 100644 (file)
 #include <linux/pwm.h>
 #include <linux/leds_pwm.h>
 #include <linux/slab.h>
-#include <linux/workqueue.h>
 
 struct led_pwm_data {
        struct led_classdev     cdev;
        struct pwm_device       *pwm;
-       struct work_struct      work;
        unsigned int            active_low;
        unsigned int            period;
        int                     duty;
@@ -51,14 +49,6 @@ static void __led_pwm_set(struct led_pwm_data *led_dat)
                pwm_enable(led_dat->pwm);
 }
 
-static void led_pwm_work(struct work_struct *work)
-{
-       struct led_pwm_data *led_dat =
-               container_of(work, struct led_pwm_data, work);
-
-       __led_pwm_set(led_dat);
-}
-
 static void led_pwm_set(struct led_classdev *led_cdev,
        enum led_brightness brightness)
 {
@@ -75,10 +65,14 @@ static void led_pwm_set(struct led_classdev *led_cdev,
 
        led_dat->duty = duty;
 
-       if (led_dat->can_sleep)
-               schedule_work(&led_dat->work);
-       else
-               __led_pwm_set(led_dat);
+       __led_pwm_set(led_dat);
+}
+
+static int led_pwm_set_blocking(struct led_classdev *led_cdev,
+       enum led_brightness brightness)
+{
+       led_pwm_set(led_cdev, brightness);
+       return 0;
 }
 
 static inline size_t sizeof_pwm_leds_priv(int num_leds)
@@ -89,11 +83,8 @@ static inline size_t sizeof_pwm_leds_priv(int num_leds)
 
 static void led_pwm_cleanup(struct led_pwm_priv *priv)
 {
-       while (priv->num_leds--) {
+       while (priv->num_leds--)
                led_classdev_unregister(&priv->leds[priv->num_leds].cdev);
-               if (priv->leds[priv->num_leds].can_sleep)
-                       cancel_work_sync(&priv->leds[priv->num_leds].work);
-       }
 }
 
 static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
@@ -105,7 +96,6 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
        led_data->active_low = led->active_low;
        led_data->cdev.name = led->name;
        led_data->cdev.default_trigger = led->default_trigger;
-       led_data->cdev.brightness_set = led_pwm_set;
        led_data->cdev.brightness = LED_OFF;
        led_data->cdev.max_brightness = led->max_brightness;
        led_data->cdev.flags = LED_CORE_SUSPENDRESUME;
@@ -122,8 +112,10 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
        }
 
        led_data->can_sleep = pwm_can_sleep(led_data->pwm);
-       if (led_data->can_sleep)
-               INIT_WORK(&led_data->work, led_pwm_work);
+       if (!led_data->can_sleep)
+               led_data->cdev.brightness_set = led_pwm_set;
+       else
+               led_data->cdev.brightness_set_blocking = led_pwm_set_blocking;
 
        led_data->period = pwm_get_period(led_data->pwm);
        if (!led_data->period && (led->pwm_period_ns > 0))
@@ -132,6 +124,7 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
        ret = led_classdev_register(dev, &led_data->cdev);
        if (ret == 0) {
                priv->num_leds++;
+               led_pwm_set(&led_data->cdev, led_data->cdev.brightness);
        } else {
                dev_err(dev, "failed to register PWM led for %s: %d\n",
                        led->name, ret);
@@ -236,6 +229,6 @@ static struct platform_driver led_pwm_driver = {
 module_platform_driver(led_pwm_driver);
 
 MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
-MODULE_DESCRIPTION("PWM LED driver for PXA");
-MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("generic PWM LED driver");
+MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:leds-pwm");
index ffc21397a6753e8ca959f0e15f390079ee024326..acf77ca47558a48145ad0801b26959c3fd829329 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/module.h>
 #include <linux/err.h>
 #include <linux/slab.h>
-#include <linux/workqueue.h>
 #include <linux/leds.h>
 #include <linux/leds-regulator.h>
 #include <linux/platform_device.h>
 
 struct regulator_led {
        struct led_classdev cdev;
-       enum led_brightness value;
        int enabled;
        struct mutex mutex;
-       struct work_struct work;
 
        struct regulator *vcc;
 };
@@ -94,22 +91,24 @@ static void regulator_led_disable(struct regulator_led *led)
        led->enabled = 0;
 }
 
-static void regulator_led_set_value(struct regulator_led *led)
+static int regulator_led_brightness_set(struct led_classdev *led_cdev,
+                                        enum led_brightness value)
 {
+       struct regulator_led *led = to_regulator_led(led_cdev);
        int voltage;
-       int ret;
+       int ret = 0;
 
        mutex_lock(&led->mutex);
 
-       if (led->value == LED_OFF) {
+       if (value == LED_OFF) {
                regulator_led_disable(led);
                goto out;
        }
 
        if (led->cdev.max_brightness > 1) {
-               voltage = led_regulator_get_voltage(led->vcc, led->value);
+               voltage = led_regulator_get_voltage(led->vcc, value);
                dev_dbg(led->cdev.dev, "brightness: %d voltage: %d\n",
-                               led->value, voltage);
+                               value, voltage);
 
                ret = regulator_set_voltage(led->vcc, voltage, voltage);
                if (ret != 0)
@@ -121,23 +120,7 @@ static void regulator_led_set_value(struct regulator_led *led)
 
 out:
        mutex_unlock(&led->mutex);
-}
-
-static void led_work(struct work_struct *work)
-{
-       struct regulator_led *led;
-
-       led = container_of(work, struct regulator_led, work);
-       regulator_led_set_value(led);
-}
-
-static void regulator_led_brightness_set(struct led_classdev *led_cdev,
-                          enum led_brightness value)
-{
-       struct regulator_led *led = to_regulator_led(led_cdev);
-
-       led->value = value;
-       schedule_work(&led->work);
+       return ret;
 }
 
 static int regulator_led_probe(struct platform_device *pdev)
@@ -169,9 +152,8 @@ static int regulator_led_probe(struct platform_device *pdev)
                                pdata->brightness);
                return -EINVAL;
        }
-       led->value = pdata->brightness;
 
-       led->cdev.brightness_set = regulator_led_brightness_set;
+       led->cdev.brightness_set_blocking = regulator_led_brightness_set;
        led->cdev.name = pdata->name;
        led->cdev.flags |= LED_CORE_SUSPENDRESUME;
        led->vcc = vcc;
@@ -181,21 +163,18 @@ static int regulator_led_probe(struct platform_device *pdev)
                led->enabled = 1;
 
        mutex_init(&led->mutex);
-       INIT_WORK(&led->work, led_work);
 
        platform_set_drvdata(pdev, led);
 
        ret = led_classdev_register(&pdev->dev, &led->cdev);
-       if (ret < 0) {
-               cancel_work_sync(&led->work);
+       if (ret < 0)
                return ret;
-       }
 
        /* to expose the default value to userspace */
-       led->cdev.brightness = led->value;
+       led->cdev.brightness = pdata->brightness;
 
        /* Set the default led status */
-       regulator_led_set_value(led);
+       regulator_led_brightness_set(&led->cdev, led->cdev.brightness);
 
        return 0;
 }
@@ -205,7 +184,6 @@ static int regulator_led_remove(struct platform_device *pdev)
        struct regulator_led *led = platform_get_drvdata(pdev);
 
        led_classdev_unregister(&led->cdev);
-       cancel_work_sync(&led->work);
        regulator_led_disable(led);
        return 0;
 }
index c2553c54f2cf4794145c29b3e5ee83b365c1a494..7c09db8bd4e8724a9a8b86bc07050c0c73cbfe31 100644 (file)
@@ -234,28 +234,19 @@ static struct platform_driver sunfire_fhc_led_driver = {
        },
 };
 
+static struct platform_driver * const drivers[] = {
+       &sunfire_clockboard_led_driver,
+       &sunfire_fhc_led_driver,
+};
+
 static int __init sunfire_leds_init(void)
 {
-       int err = platform_driver_register(&sunfire_clockboard_led_driver);
-
-       if (err) {
-               pr_err("Could not register clock board LED driver\n");
-               return err;
-       }
-
-       err = platform_driver_register(&sunfire_fhc_led_driver);
-       if (err) {
-               pr_err("Could not register FHC LED driver\n");
-               platform_driver_unregister(&sunfire_clockboard_led_driver);
-       }
-
-       return err;
+       return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
 }
 
 static void __exit sunfire_leds_exit(void)
 {
-       platform_driver_unregister(&sunfire_clockboard_led_driver);
-       platform_driver_unregister(&sunfire_fhc_led_driver);
+       platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
 }
 
 module_init(sunfire_leds_init);
index b88900d721e4494e9e05c494e7d9977501cda97b..3be40f74f12a70a279274bc3bc5a506cd3d4a995 100644 (file)
@@ -20,7 +20,7 @@
  * MA 02111-1307 USA
  */
 #include <linux/io.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of_device.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
@@ -139,29 +139,17 @@ static int syscon_led_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int syscon_led_remove(struct platform_device *pdev)
-{
-       struct syscon_led *sled = platform_get_drvdata(pdev);
-
-       led_classdev_unregister(&sled->cdev);
-       /* Turn it off */
-       regmap_update_bits(sled->map, sled->offset, sled->mask, 0);
-       return 0;
-}
-
 static const struct of_device_id of_syscon_leds_match[] = {
        { .compatible = "register-bit-led", },
        {},
 };
 
-MODULE_DEVICE_TABLE(of, of_syscon_leds_match);
-
 static struct platform_driver syscon_led_driver = {
        .probe          = syscon_led_probe,
-       .remove         = syscon_led_remove,
        .driver         = {
                .name   = "leds-syscon",
                .of_match_table = of_syscon_leds_match,
+               .suppress_bind_attrs = true,
        },
 };
-module_platform_driver(syscon_led_driver);
+builtin_platform_driver(syscon_led_driver);
index b806eca83d27ede6ead3c08568a221767fd8bbae..3045316449384d383533fafcea92060f933dc682 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/of_device.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
-#include <linux/workqueue.h>
 
 #define TLC591XX_MAX_LEDS      16
 
 #define LEDOUT_MASK            0x3
 
 #define ldev_to_led(c)         container_of(c, struct tlc591xx_led, ldev)
-#define work_to_led(work)      container_of(work, struct tlc591xx_led, work)
 
 struct tlc591xx_led {
        bool active;
        unsigned int led_no;
        struct led_classdev ldev;
-       struct work_struct work;
        struct tlc591xx_priv *priv;
 };
 
@@ -110,12 +107,12 @@ tlc591xx_set_pwm(struct tlc591xx_priv *priv, struct tlc591xx_led *led,
        return regmap_write(priv->regmap, pwm, brightness);
 }
 
-static void
-tlc591xx_led_work(struct work_struct *work)
+static int
+tlc591xx_brightness_set(struct led_classdev *led_cdev,
+                       enum led_brightness brightness)
 {
-       struct tlc591xx_led *led = work_to_led(work);
+       struct tlc591xx_led *led = ldev_to_led(led_cdev);
        struct tlc591xx_priv *priv = led->priv;
-       enum led_brightness brightness = led->ldev.brightness;
        int err;
 
        switch (brightness) {
@@ -131,18 +128,7 @@ tlc591xx_led_work(struct work_struct *work)
                        err = tlc591xx_set_pwm(priv, led, brightness);
        }
 
-       if (err)
-               dev_err(led->ldev.dev, "Failed setting brightness\n");
-}
-
-static void
-tlc591xx_brightness_set(struct led_classdev *led_cdev,
-                       enum led_brightness brightness)
-{
-       struct tlc591xx_led *led = ldev_to_led(led_cdev);
-
-       led->ldev.brightness = brightness;
-       schedule_work(&led->work);
+       return err;
 }
 
 static void
@@ -151,10 +137,8 @@ tlc591xx_destroy_devices(struct tlc591xx_priv *priv, unsigned int j)
        int i = j;
 
        while (--i >= 0) {
-               if (priv->leds[i].active) {
+               if (priv->leds[i].active)
                        led_classdev_unregister(&priv->leds[i].ldev);
-                       cancel_work_sync(&priv->leds[i].work);
-               }
        }
 }
 
@@ -175,9 +159,8 @@ tlc591xx_configure(struct device *dev,
 
                led->priv = priv;
                led->led_no = i;
-               led->ldev.brightness_set = tlc591xx_brightness_set;
+               led->ldev.brightness_set_blocking = tlc591xx_brightness_set;
                led->ldev.max_brightness = LED_FULL;
-               INIT_WORK(&led->work, tlc591xx_led_work);
                err = led_classdev_register(dev, &led->ldev);
                if (err < 0) {
                        dev_err(dev, "couldn't register LED %s\n",
index 56027ef7c7e83427418ee70c99d52906db97e8a8..64a22263e7fc50fd5dca571a7ee2f78804b3e8ee 100644 (file)
@@ -23,7 +23,6 @@
 struct wm831x_status {
        struct led_classdev cdev;
        struct wm831x *wm831x;
-       struct work_struct work;
        struct mutex mutex;
 
        spinlock_t value_lock;
@@ -40,10 +39,8 @@ struct wm831x_status {
 #define to_wm831x_status(led_cdev) \
        container_of(led_cdev, struct wm831x_status, cdev)
 
-static void wm831x_status_work(struct work_struct *work)
+static void wm831x_status_set(struct wm831x_status *led)
 {
-       struct wm831x_status *led = container_of(work, struct wm831x_status,
-                                                work);
        unsigned long flags;
 
        mutex_lock(&led->mutex);
@@ -70,8 +67,8 @@ static void wm831x_status_work(struct work_struct *work)
        mutex_unlock(&led->mutex);
 }
 
-static void wm831x_status_set(struct led_classdev *led_cdev,
-                          enum led_brightness value)
+static int wm831x_status_brightness_set(struct led_classdev *led_cdev,
+                                        enum led_brightness value)
 {
        struct wm831x_status *led = to_wm831x_status(led_cdev);
        unsigned long flags;
@@ -80,8 +77,10 @@ static void wm831x_status_set(struct led_classdev *led_cdev,
        led->brightness = value;
        if (value == LED_OFF)
                led->blink = 0;
-       schedule_work(&led->work);
        spin_unlock_irqrestore(&led->value_lock, flags);
+       wm831x_status_set(led);
+
+       return 0;
 }
 
 static int wm831x_status_blink_set(struct led_classdev *led_cdev,
@@ -147,11 +146,8 @@ static int wm831x_status_blink_set(struct led_classdev *led_cdev,
        else
                led->blink = 0;
 
-       /* Always update; if we fail turn off blinking since we expect
-        * a software fallback. */
-       schedule_work(&led->work);
-
        spin_unlock_irqrestore(&led->value_lock, flags);
+       wm831x_status_set(led);
 
        return ret;
 }
@@ -206,11 +202,9 @@ static ssize_t wm831x_status_src_store(struct device *dev,
        for (i = 0; i < ARRAY_SIZE(led_src_texts); i++) {
                if (!strcmp(name, led_src_texts[i])) {
                        mutex_lock(&led->mutex);
-
                        led->src = i;
-                       schedule_work(&led->work);
-
                        mutex_unlock(&led->mutex);
+                       wm831x_status_set(led);
                }
        }
 
@@ -262,7 +256,6 @@ static int wm831x_status_probe(struct platform_device *pdev)
                pdata.name = dev_name(&pdev->dev);
 
        mutex_init(&drvdata->mutex);
-       INIT_WORK(&drvdata->work, wm831x_status_work);
        spin_lock_init(&drvdata->value_lock);
 
        /* We cache the configuration register and read startup values
@@ -287,7 +280,7 @@ static int wm831x_status_probe(struct platform_device *pdev)
 
        drvdata->cdev.name = pdata.name;
        drvdata->cdev.default_trigger = pdata.default_trigger;
-       drvdata->cdev.brightness_set = wm831x_status_set;
+       drvdata->cdev.brightness_set_blocking = wm831x_status_brightness_set;
        drvdata->cdev.blink_set = wm831x_status_blink_set;
        drvdata->cdev.groups = wm831x_status_groups;
 
index 0d121835673f2180edd30f8cdf53a53ca6e474af..e1e4e9d0b8b187a35b55e8fe0213b4eb96428491 100644 (file)
@@ -89,40 +89,42 @@ static const int isink_cur[] = {
 #define to_wm8350_led(led_cdev) \
        container_of(led_cdev, struct wm8350_led, cdev)
 
-static void wm8350_led_enable(struct wm8350_led *led)
+static int wm8350_led_enable(struct wm8350_led *led)
 {
-       int ret;
+       int ret = 0;
 
        if (led->enabled)
-               return;
+               return ret;
 
        ret = regulator_enable(led->isink);
        if (ret != 0) {
                dev_err(led->cdev.dev, "Failed to enable ISINK: %d\n", ret);
-               return;
+               return ret;
        }
 
        ret = regulator_enable(led->dcdc);
        if (ret != 0) {
                dev_err(led->cdev.dev, "Failed to enable DCDC: %d\n", ret);
                regulator_disable(led->isink);
-               return;
+               return ret;
        }
 
        led->enabled = 1;
+
+       return ret;
 }
 
-static void wm8350_led_disable(struct wm8350_led *led)
+static int wm8350_led_disable(struct wm8350_led *led)
 {
-       int ret;
+       int ret = 0;
 
        if (!led->enabled)
-               return;
+               return ret;
 
        ret = regulator_disable(led->dcdc);
        if (ret != 0) {
                dev_err(led->cdev.dev, "Failed to disable DCDC: %d\n", ret);
-               return;
+               return ret;
        }
 
        ret = regulator_disable(led->isink);
@@ -132,27 +134,29 @@ static void wm8350_led_disable(struct wm8350_led *led)
                if (ret != 0)
                        dev_err(led->cdev.dev, "Failed to reenable DCDC: %d\n",
                                ret);
-               return;
+               return ret;
        }
 
        led->enabled = 0;
+
+       return ret;
 }
 
-static void led_work(struct work_struct *work)
+static int wm8350_led_set(struct led_classdev *led_cdev,
+                          enum led_brightness value)
 {
-       struct wm8350_led *led = container_of(work, struct wm8350_led, work);
+       struct wm8350_led *led = to_wm8350_led(led_cdev);
+       unsigned long flags;
        int ret;
        int uA;
-       unsigned long flags;
 
-       mutex_lock(&led->mutex);
+       led->value = value;
 
        spin_lock_irqsave(&led->value_lock, flags);
 
        if (led->value == LED_OFF) {
                spin_unlock_irqrestore(&led->value_lock, flags);
-               wm8350_led_disable(led);
-               goto out;
+               return wm8350_led_disable(led);
        }
 
        /* This scales linearly into the index of valid current
@@ -166,36 +170,21 @@ static void led_work(struct work_struct *work)
 
        ret = regulator_set_current_limit(led->isink, isink_cur[uA],
                                          isink_cur[uA]);
-       if (ret != 0)
+       if (ret != 0) {
                dev_err(led->cdev.dev, "Failed to set %duA: %d\n",
                        isink_cur[uA], ret);
+               return ret;
+       }
 
-       wm8350_led_enable(led);
-
-out:
-       mutex_unlock(&led->mutex);
-}
-
-static void wm8350_led_set(struct led_classdev *led_cdev,
-                          enum led_brightness value)
-{
-       struct wm8350_led *led = to_wm8350_led(led_cdev);
-       unsigned long flags;
-
-       spin_lock_irqsave(&led->value_lock, flags);
-       led->value = value;
-       schedule_work(&led->work);
-       spin_unlock_irqrestore(&led->value_lock, flags);
+       return wm8350_led_enable(led);
 }
 
 static void wm8350_led_shutdown(struct platform_device *pdev)
 {
        struct wm8350_led *led = platform_get_drvdata(pdev);
 
-       mutex_lock(&led->mutex);
        led->value = LED_OFF;
        wm8350_led_disable(led);
-       mutex_unlock(&led->mutex);
 }
 
 static int wm8350_led_probe(struct platform_device *pdev)
@@ -232,7 +221,7 @@ static int wm8350_led_probe(struct platform_device *pdev)
        if (led == NULL)
                return -ENOMEM;
 
-       led->cdev.brightness_set = wm8350_led_set;
+       led->cdev.brightness_set_blocking = wm8350_led_set;
        led->cdev.default_trigger = pdata->default_trigger;
        led->cdev.name = pdata->name;
        led->cdev.flags |= LED_CORE_SUSPENDRESUME;
@@ -251,8 +240,6 @@ static int wm8350_led_probe(struct platform_device *pdev)
                         pdata->max_uA);
 
        spin_lock_init(&led->value_lock);
-       mutex_init(&led->mutex);
-       INIT_WORK(&led->work, led_work);
        led->value = LED_OFF;
        platform_set_drvdata(pdev, led);
 
@@ -264,7 +251,6 @@ static int wm8350_led_remove(struct platform_device *pdev)
        struct wm8350_led *led = platform_get_drvdata(pdev);
 
        led_classdev_unregister(&led->cdev);
-       flush_work(&led->work);
        wm8350_led_disable(led);
        return 0;
 }
index 4238fbc31d3587923f95a61f5ba2b33e5cf74d92..db3f20da7221738920bf49bd35fbc13b1768e65d 100644 (file)
 #include <linux/rwsem.h>
 #include <linux/leds.h>
 
-static inline void led_set_brightness_async(struct led_classdev *led_cdev,
-                                       enum led_brightness value)
-{
-       value = min(value, led_cdev->max_brightness);
-       led_cdev->brightness = value;
-
-       if (!(led_cdev->flags & LED_SUSPENDED))
-               led_cdev->brightness_set(led_cdev, value);
-}
-
-static inline int led_set_brightness_sync(struct led_classdev *led_cdev,
-                                       enum led_brightness value)
-{
-       int ret = 0;
-
-       led_cdev->brightness = min(value, led_cdev->max_brightness);
-
-       if (!(led_cdev->flags & LED_SUSPENDED))
-               ret = led_cdev->brightness_set_sync(led_cdev,
-                                               led_cdev->brightness);
-       return ret;
-}
-
 static inline int led_get_brightness(struct led_classdev *led_cdev)
 {
        return led_cdev->brightness;
@@ -46,6 +23,10 @@ static inline int led_get_brightness(struct led_classdev *led_cdev)
 
 void led_init_core(struct led_classdev *led_cdev);
 void led_stop_software_blink(struct led_classdev *led_cdev);
+void led_set_brightness_nopm(struct led_classdev *led_cdev,
+                               enum led_brightness value);
+void led_set_brightness_nosleep(struct led_classdev *led_cdev,
+                               enum led_brightness value);
 
 extern struct rw_semaphore leds_list_lock;
 extern struct list_head leds_list;
index 59eca17d9661a60adef8ff0f8280fe402f37ba1d..1ca1f1608f766cec60f058e24dd26bf22caf2fc9 100644 (file)
@@ -51,9 +51,9 @@ static int fb_notifier_callback(struct notifier_block *p,
 
        if ((n->old_status == UNBLANK) ^ n->invert) {
                n->brightness = led->brightness;
-               led_set_brightness_async(led, LED_OFF);
+               led_set_brightness_nosleep(led, LED_OFF);
        } else {
-               led_set_brightness_async(led, n->brightness);
+               led_set_brightness_nosleep(led, n->brightness);
        }
 
        n->old_status = new_status;
@@ -89,9 +89,9 @@ static ssize_t bl_trig_invert_store(struct device *dev,
 
        /* After inverting, we need to update the LED. */
        if ((n->old_status == BLANK) ^ n->invert)
-               led_set_brightness_async(led, LED_OFF);
+               led_set_brightness_nosleep(led, LED_OFF);
        else
-               led_set_brightness_async(led, n->brightness);
+               led_set_brightness_nosleep(led, n->brightness);
 
        return num;
 }
index aec0f02b6b3ef21c7d6ba005c03b47500966b13b..938467fb82be4bd57b5e9bda975da2b557c4abc1 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -140,27 +139,4 @@ static int __init ledtrig_cpu_init(void)
 
        return 0;
 }
-module_init(ledtrig_cpu_init);
-
-static void __exit ledtrig_cpu_exit(void)
-{
-       int cpu;
-
-       unregister_cpu_notifier(&ledtrig_cpu_nb);
-
-       for_each_possible_cpu(cpu) {
-               struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);
-
-               led_trigger_unregister_simple(trig->_trig);
-               trig->_trig = NULL;
-               memset(trig->name, 0, MAX_NAME_LEN);
-       }
-
-       unregister_syscore_ops(&ledtrig_cpu_syscore_ops);
-}
-module_exit(ledtrig_cpu_exit);
-
-MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
-MODULE_AUTHOR("Bryan Wu <bryan.wu@canonical.com>");
-MODULE_DESCRIPTION("CPU LED trigger");
-MODULE_LICENSE("GPL");
+device_initcall(ledtrig_cpu_init);
index 6f38f883aaf16a296ef2dad87b5a54b8f67b5794..ff455cb466805f53971b4d124d6f8e5c84c8becc 100644 (file)
@@ -19,7 +19,7 @@
 
 static void defon_trig_activate(struct led_classdev *led_cdev)
 {
-       led_set_brightness_async(led_cdev, led_cdev->max_brightness);
+       led_set_brightness_nosleep(led_cdev, led_cdev->max_brightness);
 }
 
 static struct led_trigger defon_led_trigger = {
index 4cc7040746c66584e8c0c348aa8f1e33dd882c9e..51288a45fbcb95ea68c0eba89c2e975b0c0dc8e0 100644 (file)
@@ -54,12 +54,12 @@ static void gpio_trig_work(struct work_struct *work)
 
        if (tmp) {
                if (gpio_data->desired_brightness)
-                       led_set_brightness_async(gpio_data->led,
+                       led_set_brightness_nosleep(gpio_data->led,
                                           gpio_data->desired_brightness);
                else
-                       led_set_brightness_async(gpio_data->led, LED_FULL);
+                       led_set_brightness_nosleep(gpio_data->led, LED_FULL);
        } else {
-               led_set_brightness_async(gpio_data->led, LED_OFF);
+               led_set_brightness_nosleep(gpio_data->led, LED_OFF);
        }
 }
 
index 8622ce651ae28f1b94ee8debd97d520bf1a9d004..410c39c62dc7f1c3bdfa3b5dd305bbef031aef25 100644 (file)
@@ -38,7 +38,7 @@ static void led_heartbeat_function(unsigned long data)
        unsigned long delay = 0;
 
        if (unlikely(panic_heartbeats)) {
-               led_set_brightness(led_cdev, LED_OFF);
+               led_set_brightness_nosleep(led_cdev, LED_OFF);
                return;
        }
 
@@ -81,7 +81,7 @@ static void led_heartbeat_function(unsigned long data)
                break;
        }
 
-       led_set_brightness_async(led_cdev, brightness);
+       led_set_brightness_nosleep(led_cdev, brightness);
        mod_timer(&heartbeat_data->timer, jiffies + delay);
 }
 
index 2cd7c0cf5924fe17807446d12287058566fadd36..c02a3ac3cd2bf124777e44741142a35a90d2f19d 100644 (file)
@@ -11,7 +11,6 @@
  *
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/leds.h>
@@ -33,15 +32,4 @@ static int __init ledtrig_ide_init(void)
        led_trigger_register_simple("ide-disk", &ledtrig_ide);
        return 0;
 }
-
-static void __exit ledtrig_ide_exit(void)
-{
-       led_trigger_unregister_simple(ledtrig_ide);
-}
-
-module_init(ledtrig_ide_init);
-module_exit(ledtrig_ide_exit);
-
-MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
-MODULE_DESCRIPTION("LED IDE Disk Activity Trigger");
-MODULE_LICENSE("GPL");
+device_initcall(ledtrig_ide_init);
index fbd02cdc3ad7d29a83cac5565117eb60f4cf9960..b8ea9f0f1e197a1d0a5d8ffc1dd016b18bf61f7f 100644 (file)
@@ -63,9 +63,9 @@ static ssize_t led_invert_store(struct device *dev,
        oneshot_data->invert = !!state;
 
        if (oneshot_data->invert)
-               led_set_brightness_async(led_cdev, LED_FULL);
+               led_set_brightness_nosleep(led_cdev, LED_FULL);
        else
-               led_set_brightness_async(led_cdev, LED_OFF);
+               led_set_brightness_nosleep(led_cdev, LED_OFF);
 
        return size;
 }
@@ -201,4 +201,4 @@ module_exit(oneshot_trig_exit);
 
 MODULE_AUTHOR("Fabio Baltieri <fabio.baltieri@gmail.com>");
 MODULE_DESCRIPTION("One-shot LED trigger");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
index 3c34de404d181012dab17fd1965e8b48efd4b371..7e6011bd36465517fc6840e7eae2b818aa0c9b12 100644 (file)
@@ -41,7 +41,7 @@ static void transient_timer_function(unsigned long data)
        struct transient_trig_data *transient_data = led_cdev->trigger_data;
 
        transient_data->activate = 0;
-       led_set_brightness_async(led_cdev, transient_data->restore_state);
+       led_set_brightness_nosleep(led_cdev, transient_data->restore_state);
 }
 
 static ssize_t transient_activate_show(struct device *dev,
@@ -72,7 +72,7 @@ static ssize_t transient_activate_store(struct device *dev,
        if (state == 0 && transient_data->activate == 1) {
                del_timer(&transient_data->timer);
                transient_data->activate = state;
-               led_set_brightness_async(led_cdev,
+               led_set_brightness_nosleep(led_cdev,
                                        transient_data->restore_state);
                return size;
        }
@@ -81,11 +81,11 @@ static ssize_t transient_activate_store(struct device *dev,
        if (state == 1 && transient_data->activate == 0 &&
            transient_data->duration != 0) {
                transient_data->activate = state;
-               led_set_brightness_async(led_cdev, transient_data->state);
+               led_set_brightness_nosleep(led_cdev, transient_data->state);
                transient_data->restore_state =
                    (transient_data->state == LED_FULL) ? LED_OFF : LED_FULL;
                mod_timer(&transient_data->timer,
-                         jiffies + transient_data->duration);
+                         jiffies + msecs_to_jiffies(transient_data->duration));
        }
 
        /* state == 0 && transient_data->activate == 0
@@ -204,7 +204,7 @@ static void transient_trig_deactivate(struct led_classdev *led_cdev)
 
        if (led_cdev->activated) {
                del_timer_sync(&transient_data->timer);
-               led_set_brightness_async(led_cdev,
+               led_set_brightness_nosleep(led_cdev,
                                        transient_data->restore_state);
                device_remove_file(led_cdev->dev, &dev_attr_activate);
                device_remove_file(led_cdev->dev, &dev_attr_duration);
index f434e89e1c7a1d824d0ac491c80234eb955e976f..a54b339951a3e695bfa68e96fb6eaf2e3e451c62 100644 (file)
@@ -75,7 +75,7 @@ static int gennvm_block_bb(struct ppa_addr ppa, int nr_blocks, u8 *blks,
        struct nvm_block *blk;
        int i;
 
-       lun = &gn->luns[(dev->nr_luns * ppa.g.ch) + ppa.g.lun];
+       lun = &gn->luns[(dev->luns_per_chnl * ppa.g.ch) + ppa.g.lun];
 
        for (i = 0; i < nr_blocks; i++) {
                if (blks[i] == 0)
index 7913fdcfc8496bdd7c719a8c3334f6136c74eced..0a2e7273db9e996ea67d9d461172342aaa65d4f1 100644 (file)
@@ -240,6 +240,15 @@ config DM_BUFIO
         as a cache, holding recently-read blocks in memory and performing
         delayed writes.
 
+config DM_DEBUG_BLOCK_STACK_TRACING
+       bool "Keep stack trace of persistent data block lock holders"
+       depends on STACKTRACE_SUPPORT && DM_BUFIO
+       select STACKTRACE
+       ---help---
+        Enable this for messages that may help debug problems with the
+        block manager locking used by thin provisioning and caching.
+
+        If unsure, say N.
 config DM_BIO_PRISON
        tristate
        depends on BLK_DEV_DM
@@ -458,6 +467,18 @@ config DM_VERITY
 
          If unsure, say N.
 
+config DM_VERITY_FEC
+       bool "Verity forward error correction support"
+       depends on DM_VERITY
+       select REED_SOLOMON
+       select REED_SOLOMON_DEC8
+       ---help---
+         Add forward error correction support to dm-verity. This option
+         makes it possible to use pre-generated error correction data to
+         recover from corrupted blocks.
+
+         If unsure, say N.
+
 config DM_SWITCH
        tristate "Switch target support (EXPERIMENTAL)"
        depends on BLK_DEV_DM
index f34979cd141aed02d867f11f3f03c9403d327005..62a65764e8e0f093cede342f0eb4b7d0aec2eb4e 100644 (file)
@@ -16,6 +16,7 @@ dm-cache-mq-y   += dm-cache-policy-mq.o
 dm-cache-smq-y   += dm-cache-policy-smq.o
 dm-cache-cleaner-y += dm-cache-policy-cleaner.o
 dm-era-y       += dm-era-target.o
+dm-verity-y    += dm-verity-target.o
 md-mod-y       += md.o bitmap.o
 raid456-y      += raid5.o raid5-cache.o
 
@@ -63,3 +64,7 @@ obj-$(CONFIG_DM_LOG_WRITES)   += dm-log-writes.o
 ifeq ($(CONFIG_DM_UEVENT),y)
 dm-mod-objs                    += dm-uevent.o
 endif
+
+ifeq ($(CONFIG_DM_VERITY_FEC),y)
+dm-verity-objs                 += dm-verity-fec.o
+endif
index 2dd33085b331da5bee79392dcf30f7e2c734f70b..6b832e06580dd6527bbf6e1a92e36c044db62f4a 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/shrinker.h>
 #include <linux/module.h>
 #include <linux/rbtree.h>
+#include <linux/stacktrace.h>
 
 #define DM_MSG_PREFIX "bufio"
 
@@ -149,6 +150,11 @@ struct dm_buffer {
        struct list_head write_list;
        struct bio bio;
        struct bio_vec bio_vec[DM_BUFIO_INLINE_VECS];
+#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING
+#define MAX_STACK 10
+       struct stack_trace stack_trace;
+       unsigned long stack_entries[MAX_STACK];
+#endif
 };
 
 /*----------------------------------------------------------------*/
@@ -253,6 +259,17 @@ static LIST_HEAD(dm_bufio_all_clients);
  */
 static DEFINE_MUTEX(dm_bufio_clients_lock);
 
+#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING
+static void buffer_record_stack(struct dm_buffer *b)
+{
+       b->stack_trace.nr_entries = 0;
+       b->stack_trace.max_entries = MAX_STACK;
+       b->stack_trace.entries = b->stack_entries;
+       b->stack_trace.skip = 2;
+       save_stack_trace(&b->stack_trace);
+}
+#endif
+
 /*----------------------------------------------------------------
  * A red/black tree acts as an index for all the buffers.
  *--------------------------------------------------------------*/
@@ -454,6 +471,9 @@ static struct dm_buffer *alloc_buffer(struct dm_bufio_client *c, gfp_t gfp_mask)
 
        adjust_total_allocated(b->data_mode, (long)c->block_size);
 
+#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING
+       memset(&b->stack_trace, 0, sizeof(b->stack_trace));
+#endif
        return b;
 }
 
@@ -1063,12 +1083,16 @@ static void *new_read(struct dm_bufio_client *c, sector_t block,
 
        dm_bufio_lock(c);
        b = __bufio_new(c, block, nf, &need_submit, &write_list);
+#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING
+       if (b && b->hold_count == 1)
+               buffer_record_stack(b);
+#endif
        dm_bufio_unlock(c);
 
        __flush_write_list(&write_list);
 
        if (!b)
-               return b;
+               return NULL;
 
        if (need_submit)
                submit_io(b, READ, b->block, read_endio);
@@ -1462,6 +1486,7 @@ static void drop_buffers(struct dm_bufio_client *c)
 {
        struct dm_buffer *b;
        int i;
+       bool warned = false;
 
        BUG_ON(dm_bufio_in_request());
 
@@ -1476,9 +1501,21 @@ static void drop_buffers(struct dm_bufio_client *c)
                __free_buffer_wake(b);
 
        for (i = 0; i < LIST_SIZE; i++)
-               list_for_each_entry(b, &c->lru[i], lru_list)
+               list_for_each_entry(b, &c->lru[i], lru_list) {
+                       WARN_ON(!warned);
+                       warned = true;
                        DMERR("leaked buffer %llx, hold count %u, list %d",
                              (unsigned long long)b->block, b->hold_count, i);
+#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING
+                       print_stack_trace(&b->stack_trace, 1);
+                       b->hold_count = 0; /* mark unclaimed to avoid BUG_ON below */
+#endif
+               }
+
+#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING
+       while ((b = __get_unclaimed_buffer(c)))
+               __free_buffer_wake(b);
+#endif
 
        for (i = 0; i < LIST_SIZE; i++)
                BUG_ON(!list_empty(&c->lru[i]));
@@ -1891,8 +1928,7 @@ static void __exit dm_bufio_exit(void)
                bug = 1;
        }
 
-       if (bug)
-               BUG();
+       BUG_ON(bug);
 }
 
 module_init(dm_bufio_init)
index 2fd4c82961441e08b2b20d8db98bfb2bad86e05e..5780accffa3059dfa979ef8ff81752bfabd46452 100644 (file)
@@ -118,14 +118,12 @@ static void iot_io_end(struct io_tracker *iot, sector_t len)
  */
 struct dm_hook_info {
        bio_end_io_t *bi_end_io;
-       void *bi_private;
 };
 
 static void dm_hook_bio(struct dm_hook_info *h, struct bio *bio,
                        bio_end_io_t *bi_end_io, void *bi_private)
 {
        h->bi_end_io = bio->bi_end_io;
-       h->bi_private = bio->bi_private;
 
        bio->bi_end_io = bi_end_io;
        bio->bi_private = bi_private;
@@ -134,7 +132,6 @@ static void dm_hook_bio(struct dm_hook_info *h, struct bio *bio,
 static void dm_unhook_bio(struct dm_hook_info *h, struct bio *bio)
 {
        bio->bi_end_io = h->bi_end_io;
-       bio->bi_private = h->bi_private;
 }
 
 /*----------------------------------------------------------------*/
index fae34e7a0b1e4e4d60b5867eff9422e432fba83b..12b5216c2cfed2758d19f55ba9d2c2d4f58d4deb 100644 (file)
@@ -69,7 +69,7 @@ struct dm_exception_store_type {
         * Update the metadata with this exception.
         */
        void (*commit_exception) (struct dm_exception_store *store,
-                                 struct dm_exception *e,
+                                 struct dm_exception *e, int valid,
                                  void (*callback) (void *, int success),
                                  void *callback_context);
 
index 3164b8bce2948591999f429e4633235c1f7b1062..4d3909393f2cce5488ced8843ccab1375d40d2d9 100644 (file)
@@ -695,7 +695,7 @@ static int persistent_prepare_exception(struct dm_exception_store *store,
 }
 
 static void persistent_commit_exception(struct dm_exception_store *store,
-                                       struct dm_exception *e,
+                                       struct dm_exception *e, int valid,
                                        void (*callback) (void *, int success),
                                        void *callback_context)
 {
@@ -704,6 +704,9 @@ static void persistent_commit_exception(struct dm_exception_store *store,
        struct core_exception ce;
        struct commit_callback *cb;
 
+       if (!valid)
+               ps->valid = 0;
+
        ce.old_chunk = e->old_chunk;
        ce.new_chunk = e->new_chunk;
        write_exception(ps, ps->current_committed++, &ce);
index 9b7c8c8049d6186f54bdfec114c43cb3ce4d77fa..4d50a12cf00c699b85a0df1c0b1dd86f0137b691 100644 (file)
@@ -52,12 +52,12 @@ static int transient_prepare_exception(struct dm_exception_store *store,
 }
 
 static void transient_commit_exception(struct dm_exception_store *store,
-                                      struct dm_exception *e,
+                                      struct dm_exception *e, int valid,
                                       void (*callback) (void *, int success),
                                       void *callback_context)
 {
        /* Just succeed */
-       callback(callback_context, 1);
+       callback(callback_context, valid);
 }
 
 static void transient_usage(struct dm_exception_store *store,
index c06b74e91cd6aeef00ef4eefae9953d4d8c8f91b..3766386080a48fbfb06226ae80646b5e2f0e653a 100644 (file)
@@ -207,7 +207,6 @@ struct dm_snap_pending_exception {
         */
        struct bio *full_bio;
        bio_end_io_t *full_bio_end_io;
-       void *full_bio_private;
 };
 
 /*
@@ -1438,8 +1437,9 @@ static void __invalidate_snapshot(struct dm_snapshot *s, int err)
        dm_table_event(s->ti->table);
 }
 
-static void pending_complete(struct dm_snap_pending_exception *pe, int success)
+static void pending_complete(void *context, int success)
 {
+       struct dm_snap_pending_exception *pe = context;
        struct dm_exception *e;
        struct dm_snapshot *s = pe->snap;
        struct bio *origin_bios = NULL;
@@ -1485,10 +1485,8 @@ out:
        snapshot_bios = bio_list_get(&pe->snapshot_bios);
        origin_bios = bio_list_get(&pe->origin_bios);
        full_bio = pe->full_bio;
-       if (full_bio) {
+       if (full_bio)
                full_bio->bi_end_io = pe->full_bio_end_io;
-               full_bio->bi_private = pe->full_bio_private;
-       }
        increment_pending_exceptions_done_count();
 
        up_write(&s->lock);
@@ -1509,24 +1507,13 @@ out:
        free_pending_exception(pe);
 }
 
-static void commit_callback(void *context, int success)
-{
-       struct dm_snap_pending_exception *pe = context;
-
-       pending_complete(pe, success);
-}
-
 static void complete_exception(struct dm_snap_pending_exception *pe)
 {
        struct dm_snapshot *s = pe->snap;
 
-       if (unlikely(pe->copy_error))
-               pending_complete(pe, 0);
-
-       else
-               /* Update the metadata if we are persistent */
-               s->store->type->commit_exception(s->store, &pe->e,
-                                                commit_callback, pe);
+       /* Update the metadata if we are persistent */
+       s->store->type->commit_exception(s->store, &pe->e, !pe->copy_error,
+                                        pending_complete, pe);
 }
 
 /*
@@ -1605,7 +1592,6 @@ static void start_full_bio(struct dm_snap_pending_exception *pe,
 
        pe->full_bio = bio;
        pe->full_bio_end_io = bio->bi_end_io;
-       pe->full_bio_private = bio->bi_private;
 
        callback_data = dm_kcopyd_prepare_callback(s->kcopyd_client,
                                                   copy_callback, pe);
index c219a053c7f66d1ebae80a19b005af38914dbe8c..f962d6453afd64e33b739253ca4166a276307dab 100644 (file)
@@ -1395,8 +1395,21 @@ static bool __snapshotted_since(struct dm_thin_device *td, uint32_t time)
        return td->snapshotted_time > time;
 }
 
-int dm_thin_find_block(struct dm_thin_device *td, dm_block_t block,
-                      int can_issue_io, struct dm_thin_lookup_result *result)
+static void unpack_lookup_result(struct dm_thin_device *td, __le64 value,
+                                struct dm_thin_lookup_result *result)
+{
+       uint64_t block_time = 0;
+       dm_block_t exception_block;
+       uint32_t exception_time;
+
+       block_time = le64_to_cpu(value);
+       unpack_block_time(block_time, &exception_block, &exception_time);
+       result->block = exception_block;
+       result->shared = __snapshotted_since(td, exception_time);
+}
+
+static int __find_block(struct dm_thin_device *td, dm_block_t block,
+                       int can_issue_io, struct dm_thin_lookup_result *result)
 {
        int r;
        __le64 value;
@@ -1404,39 +1417,56 @@ int dm_thin_find_block(struct dm_thin_device *td, dm_block_t block,
        dm_block_t keys[2] = { td->id, block };
        struct dm_btree_info *info;
 
-       down_read(&pmd->root_lock);
-       if (pmd->fail_io) {
-               up_read(&pmd->root_lock);
-               return -EINVAL;
-       }
-
        if (can_issue_io) {
                info = &pmd->info;
        } else
                info = &pmd->nb_info;
 
        r = dm_btree_lookup(info, pmd->root, keys, &value);
-       if (!r) {
-               uint64_t block_time = 0;
-               dm_block_t exception_block;
-               uint32_t exception_time;
-
-               block_time = le64_to_cpu(value);
-               unpack_block_time(block_time, &exception_block,
-                                 &exception_time);
-               result->block = exception_block;
-               result->shared = __snapshotted_since(td, exception_time);
+       if (!r)
+               unpack_lookup_result(td, value, result);
+
+       return r;
+}
+
+int dm_thin_find_block(struct dm_thin_device *td, dm_block_t block,
+                      int can_issue_io, struct dm_thin_lookup_result *result)
+{
+       int r;
+       struct dm_pool_metadata *pmd = td->pmd;
+
+       down_read(&pmd->root_lock);
+       if (pmd->fail_io) {
+               up_read(&pmd->root_lock);
+               return -EINVAL;
        }
 
+       r = __find_block(td, block, can_issue_io, result);
+
        up_read(&pmd->root_lock);
        return r;
 }
 
-/* FIXME: write a more efficient one in btree */
-int dm_thin_find_mapped_range(struct dm_thin_device *td,
-                             dm_block_t begin, dm_block_t end,
-                             dm_block_t *thin_begin, dm_block_t *thin_end,
-                             dm_block_t *pool_begin, bool *maybe_shared)
+static int __find_next_mapped_block(struct dm_thin_device *td, dm_block_t block,
+                                         dm_block_t *vblock,
+                                         struct dm_thin_lookup_result *result)
+{
+       int r;
+       __le64 value;
+       struct dm_pool_metadata *pmd = td->pmd;
+       dm_block_t keys[2] = { td->id, block };
+
+       r = dm_btree_lookup_next(&pmd->info, pmd->root, keys, vblock, &value);
+       if (!r)
+               unpack_lookup_result(td, value, result);
+
+       return r;
+}
+
+static int __find_mapped_range(struct dm_thin_device *td,
+                              dm_block_t begin, dm_block_t end,
+                              dm_block_t *thin_begin, dm_block_t *thin_end,
+                              dm_block_t *pool_begin, bool *maybe_shared)
 {
        int r;
        dm_block_t pool_end;
@@ -1445,21 +1475,11 @@ int dm_thin_find_mapped_range(struct dm_thin_device *td,
        if (end < begin)
                return -ENODATA;
 
-       /*
-        * Find first mapped block.
-        */
-       while (begin < end) {
-               r = dm_thin_find_block(td, begin, true, &lookup);
-               if (r) {
-                       if (r != -ENODATA)
-                               return r;
-               } else
-                       break;
-
-               begin++;
-       }
+       r = __find_next_mapped_block(td, begin, &begin, &lookup);
+       if (r)
+               return r;
 
-       if (begin == end)
+       if (begin >= end)
                return -ENODATA;
 
        *thin_begin = begin;
@@ -1469,7 +1489,7 @@ int dm_thin_find_mapped_range(struct dm_thin_device *td,
        begin++;
        pool_end = *pool_begin + 1;
        while (begin != end) {
-               r = dm_thin_find_block(td, begin, true, &lookup);
+               r = __find_block(td, begin, true, &lookup);
                if (r) {
                        if (r == -ENODATA)
                                break;
@@ -1489,6 +1509,24 @@ int dm_thin_find_mapped_range(struct dm_thin_device *td,
        return 0;
 }
 
+int dm_thin_find_mapped_range(struct dm_thin_device *td,
+                             dm_block_t begin, dm_block_t end,
+                             dm_block_t *thin_begin, dm_block_t *thin_end,
+                             dm_block_t *pool_begin, bool *maybe_shared)
+{
+       int r = -EINVAL;
+       struct dm_pool_metadata *pmd = td->pmd;
+
+       down_read(&pmd->root_lock);
+       if (!pmd->fail_io) {
+               r = __find_mapped_range(td, begin, end, thin_begin, thin_end,
+                                       pool_begin, maybe_shared);
+       }
+       up_read(&pmd->root_lock);
+
+       return r;
+}
+
 static int __insert(struct dm_thin_device *td, dm_block_t block,
                    dm_block_t data_block)
 {
index 63903a5a5d9ee3b580d552673b42b9716b99322c..72d91f477683f2c1dfad5a3a9614aaf0b26992e1 100644 (file)
@@ -3453,8 +3453,8 @@ static void pool_postsuspend(struct dm_target *ti)
        struct pool_c *pt = ti->private;
        struct pool *pool = pt->pool;
 
-       cancel_delayed_work(&pool->waker);
-       cancel_delayed_work(&pool->no_space_timeout);
+       cancel_delayed_work_sync(&pool->waker);
+       cancel_delayed_work_sync(&pool->no_space_timeout);
        flush_workqueue(pool->wq);
        (void) commit(pool);
 }
@@ -3886,7 +3886,7 @@ static struct target_type pool_target = {
        .name = "thin-pool",
        .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
                    DM_TARGET_IMMUTABLE,
-       .version = {1, 16, 0},
+       .version = {1, 17, 0},
        .module = THIS_MODULE,
        .ctr = pool_ctr,
        .dtr = pool_dtr,
@@ -4260,7 +4260,7 @@ static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits)
 
 static struct target_type thin_target = {
        .name = "thin",
-       .version = {1, 16, 0},
+       .version = {1, 17, 0},
        .module = THIS_MODULE,
        .ctr = thin_ctr,
        .dtr = thin_dtr,
diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c
new file mode 100644 (file)
index 0000000..1cc10c4
--- /dev/null
@@ -0,0 +1,818 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Author: Sami Tolvanen <samitolvanen@google.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 "dm-verity-fec.h"
+#include <linux/math64.h>
+
+#define DM_MSG_PREFIX  "verity-fec"
+
+/*
+ * If error correction has been configured, returns true.
+ */
+bool verity_fec_is_enabled(struct dm_verity *v)
+{
+       return v->fec && v->fec->dev;
+}
+
+/*
+ * Return a pointer to dm_verity_fec_io after dm_verity_io and its variable
+ * length fields.
+ */
+static inline struct dm_verity_fec_io *fec_io(struct dm_verity_io *io)
+{
+       return (struct dm_verity_fec_io *) verity_io_digest_end(io->v, io);
+}
+
+/*
+ * Return an interleaved offset for a byte in RS block.
+ */
+static inline u64 fec_interleave(struct dm_verity *v, u64 offset)
+{
+       u32 mod;
+
+       mod = do_div(offset, v->fec->rsn);
+       return offset + mod * (v->fec->rounds << v->data_dev_block_bits);
+}
+
+/*
+ * Decode an RS block using Reed-Solomon.
+ */
+static int fec_decode_rs8(struct dm_verity *v, struct dm_verity_fec_io *fio,
+                         u8 *data, u8 *fec, int neras)
+{
+       int i;
+       uint16_t par[DM_VERITY_FEC_RSM - DM_VERITY_FEC_MIN_RSN];
+
+       for (i = 0; i < v->fec->roots; i++)
+               par[i] = fec[i];
+
+       return decode_rs8(fio->rs, data, par, v->fec->rsn, NULL, neras,
+                         fio->erasures, 0, NULL);
+}
+
+/*
+ * Read error-correcting codes for the requested RS block. Returns a pointer
+ * to the data block. Caller is responsible for releasing buf.
+ */
+static u8 *fec_read_parity(struct dm_verity *v, u64 rsb, int index,
+                          unsigned *offset, struct dm_buffer **buf)
+{
+       u64 position, block;
+       u8 *res;
+
+       position = (index + rsb) * v->fec->roots;
+       block = position >> v->data_dev_block_bits;
+       *offset = (unsigned)(position - (block << v->data_dev_block_bits));
+
+       res = dm_bufio_read(v->fec->bufio, v->fec->start + block, buf);
+       if (unlikely(IS_ERR(res))) {
+               DMERR("%s: FEC %llu: parity read failed (block %llu): %ld",
+                     v->data_dev->name, (unsigned long long)rsb,
+                     (unsigned long long)(v->fec->start + block),
+                     PTR_ERR(res));
+               *buf = NULL;
+       }
+
+       return res;
+}
+
+/* Loop over each preallocated buffer slot. */
+#define fec_for_each_prealloc_buffer(__i) \
+       for (__i = 0; __i < DM_VERITY_FEC_BUF_PREALLOC; __i++)
+
+/* Loop over each extra buffer slot. */
+#define fec_for_each_extra_buffer(io, __i) \
+       for (__i = DM_VERITY_FEC_BUF_PREALLOC; __i < DM_VERITY_FEC_BUF_MAX; __i++)
+
+/* Loop over each allocated buffer. */
+#define fec_for_each_buffer(io, __i) \
+       for (__i = 0; __i < (io)->nbufs; __i++)
+
+/* Loop over each RS block in each allocated buffer. */
+#define fec_for_each_buffer_rs_block(io, __i, __j) \
+       fec_for_each_buffer(io, __i) \
+               for (__j = 0; __j < 1 << DM_VERITY_FEC_BUF_RS_BITS; __j++)
+
+/*
+ * Return a pointer to the current RS block when called inside
+ * fec_for_each_buffer_rs_block.
+ */
+static inline u8 *fec_buffer_rs_block(struct dm_verity *v,
+                                     struct dm_verity_fec_io *fio,
+                                     unsigned i, unsigned j)
+{
+       return &fio->bufs[i][j * v->fec->rsn];
+}
+
+/*
+ * Return an index to the current RS block when called inside
+ * fec_for_each_buffer_rs_block.
+ */
+static inline unsigned fec_buffer_rs_index(unsigned i, unsigned j)
+{
+       return (i << DM_VERITY_FEC_BUF_RS_BITS) + j;
+}
+
+/*
+ * Decode all RS blocks from buffers and copy corrected bytes into fio->output
+ * starting from block_offset.
+ */
+static int fec_decode_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio,
+                          u64 rsb, int byte_index, unsigned block_offset,
+                          int neras)
+{
+       int r, corrected = 0, res;
+       struct dm_buffer *buf;
+       unsigned n, i, offset;
+       u8 *par, *block;
+
+       par = fec_read_parity(v, rsb, block_offset, &offset, &buf);
+       if (IS_ERR(par))
+               return PTR_ERR(par);
+
+       /*
+        * Decode the RS blocks we have in bufs. Each RS block results in
+        * one corrected target byte and consumes fec->roots parity bytes.
+        */
+       fec_for_each_buffer_rs_block(fio, n, i) {
+               block = fec_buffer_rs_block(v, fio, n, i);
+               res = fec_decode_rs8(v, fio, block, &par[offset], neras);
+               if (res < 0) {
+                       dm_bufio_release(buf);
+
+                       r = res;
+                       goto error;
+               }
+
+               corrected += res;
+               fio->output[block_offset] = block[byte_index];
+
+               block_offset++;
+               if (block_offset >= 1 << v->data_dev_block_bits)
+                       goto done;
+
+               /* read the next block when we run out of parity bytes */
+               offset += v->fec->roots;
+               if (offset >= 1 << v->data_dev_block_bits) {
+                       dm_bufio_release(buf);
+
+                       par = fec_read_parity(v, rsb, block_offset, &offset, &buf);
+                       if (unlikely(IS_ERR(par)))
+                               return PTR_ERR(par);
+               }
+       }
+done:
+       r = corrected;
+error:
+       if (r < 0 && neras)
+               DMERR_LIMIT("%s: FEC %llu: failed to correct: %d",
+                           v->data_dev->name, (unsigned long long)rsb, r);
+       else if (r > 0)
+               DMWARN_LIMIT("%s: FEC %llu: corrected %d errors",
+                            v->data_dev->name, (unsigned long long)rsb, r);
+
+       return r;
+}
+
+/*
+ * Locate data block erasures using verity hashes.
+ */
+static int fec_is_erasure(struct dm_verity *v, struct dm_verity_io *io,
+                         u8 *want_digest, u8 *data)
+{
+       if (unlikely(verity_hash(v, verity_io_hash_desc(v, io),
+                                data, 1 << v->data_dev_block_bits,
+                                verity_io_real_digest(v, io))))
+               return 0;
+
+       return memcmp(verity_io_real_digest(v, io), want_digest,
+                     v->digest_size) != 0;
+}
+
+/*
+ * Read data blocks that are part of the RS block and deinterleave as much as
+ * fits into buffers. Check for erasure locations if @neras is non-NULL.
+ */
+static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io,
+                        u64 rsb, u64 target, unsigned block_offset,
+                        int *neras)
+{
+       bool is_zero;
+       int i, j, target_index = -1;
+       struct dm_buffer *buf;
+       struct dm_bufio_client *bufio;
+       struct dm_verity_fec_io *fio = fec_io(io);
+       u64 block, ileaved;
+       u8 *bbuf, *rs_block;
+       u8 want_digest[v->digest_size];
+       unsigned n, k;
+
+       if (neras)
+               *neras = 0;
+
+       /*
+        * read each of the rsn data blocks that are part of the RS block, and
+        * interleave contents to available bufs
+        */
+       for (i = 0; i < v->fec->rsn; i++) {
+               ileaved = fec_interleave(v, rsb * v->fec->rsn + i);
+
+               /*
+                * target is the data block we want to correct, target_index is
+                * the index of this block within the rsn RS blocks
+                */
+               if (ileaved == target)
+                       target_index = i;
+
+               block = ileaved >> v->data_dev_block_bits;
+               bufio = v->fec->data_bufio;
+
+               if (block >= v->data_blocks) {
+                       block -= v->data_blocks;
+
+                       /*
+                        * blocks outside the area were assumed to contain
+                        * zeros when encoding data was generated
+                        */
+                       if (unlikely(block >= v->fec->hash_blocks))
+                               continue;
+
+                       block += v->hash_start;
+                       bufio = v->bufio;
+               }
+
+               bbuf = dm_bufio_read(bufio, block, &buf);
+               if (unlikely(IS_ERR(bbuf))) {
+                       DMWARN_LIMIT("%s: FEC %llu: read failed (%llu): %ld",
+                                    v->data_dev->name,
+                                    (unsigned long long)rsb,
+                                    (unsigned long long)block, PTR_ERR(bbuf));
+
+                       /* assume the block is corrupted */
+                       if (neras && *neras <= v->fec->roots)
+                               fio->erasures[(*neras)++] = i;
+
+                       continue;
+               }
+
+               /* locate erasures if the block is on the data device */
+               if (bufio == v->fec->data_bufio &&
+                   verity_hash_for_block(v, io, block, want_digest,
+                                         &is_zero) == 0) {
+                       /* skip known zero blocks entirely */
+                       if (is_zero)
+                               continue;
+
+                       /*
+                        * skip if we have already found the theoretical
+                        * maximum number (i.e. fec->roots) of erasures
+                        */
+                       if (neras && *neras <= v->fec->roots &&
+                           fec_is_erasure(v, io, want_digest, bbuf))
+                               fio->erasures[(*neras)++] = i;
+               }
+
+               /*
+                * deinterleave and copy the bytes that fit into bufs,
+                * starting from block_offset
+                */
+               fec_for_each_buffer_rs_block(fio, n, j) {
+                       k = fec_buffer_rs_index(n, j) + block_offset;
+
+                       if (k >= 1 << v->data_dev_block_bits)
+                               goto done;
+
+                       rs_block = fec_buffer_rs_block(v, fio, n, j);
+                       rs_block[i] = bbuf[k];
+               }
+done:
+               dm_bufio_release(buf);
+       }
+
+       return target_index;
+}
+
+/*
+ * Allocate RS control structure and FEC buffers from preallocated mempools,
+ * and attempt to allocate as many extra buffers as available.
+ */
+static int fec_alloc_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio)
+{
+       unsigned n;
+
+       if (!fio->rs) {
+               fio->rs = mempool_alloc(v->fec->rs_pool, 0);
+               if (unlikely(!fio->rs)) {
+                       DMERR("failed to allocate RS");
+                       return -ENOMEM;
+               }
+       }
+
+       fec_for_each_prealloc_buffer(n) {
+               if (fio->bufs[n])
+                       continue;
+
+               fio->bufs[n] = mempool_alloc(v->fec->prealloc_pool, GFP_NOIO);
+               if (unlikely(!fio->bufs[n])) {
+                       DMERR("failed to allocate FEC buffer");
+                       return -ENOMEM;
+               }
+       }
+
+       /* try to allocate the maximum number of buffers */
+       fec_for_each_extra_buffer(fio, n) {
+               if (fio->bufs[n])
+                       continue;
+
+               fio->bufs[n] = mempool_alloc(v->fec->extra_pool, GFP_NOIO);
+               /* we can manage with even one buffer if necessary */
+               if (unlikely(!fio->bufs[n]))
+                       break;
+       }
+       fio->nbufs = n;
+
+       if (!fio->output) {
+               fio->output = mempool_alloc(v->fec->output_pool, GFP_NOIO);
+
+               if (!fio->output) {
+                       DMERR("failed to allocate FEC page");
+                       return -ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Initialize buffers and clear erasures. fec_read_bufs() assumes buffers are
+ * zeroed before deinterleaving.
+ */
+static void fec_init_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio)
+{
+       unsigned n;
+
+       fec_for_each_buffer(fio, n)
+               memset(fio->bufs[n], 0, v->fec->rsn << DM_VERITY_FEC_BUF_RS_BITS);
+
+       memset(fio->erasures, 0, sizeof(fio->erasures));
+}
+
+/*
+ * Decode all RS blocks in a single data block and return the target block
+ * (indicated by @offset) in fio->output. If @use_erasures is non-zero, uses
+ * hashes to locate erasures.
+ */
+static int fec_decode_rsb(struct dm_verity *v, struct dm_verity_io *io,
+                         struct dm_verity_fec_io *fio, u64 rsb, u64 offset,
+                         bool use_erasures)
+{
+       int r, neras = 0;
+       unsigned pos;
+
+       r = fec_alloc_bufs(v, fio);
+       if (unlikely(r < 0))
+               return r;
+
+       for (pos = 0; pos < 1 << v->data_dev_block_bits; ) {
+               fec_init_bufs(v, fio);
+
+               r = fec_read_bufs(v, io, rsb, offset, pos,
+                                 use_erasures ? &neras : NULL);
+               if (unlikely(r < 0))
+                       return r;
+
+               r = fec_decode_bufs(v, fio, rsb, r, pos, neras);
+               if (r < 0)
+                       return r;
+
+               pos += fio->nbufs << DM_VERITY_FEC_BUF_RS_BITS;
+       }
+
+       /* Always re-validate the corrected block against the expected hash */
+       r = verity_hash(v, verity_io_hash_desc(v, io), fio->output,
+                       1 << v->data_dev_block_bits,
+                       verity_io_real_digest(v, io));
+       if (unlikely(r < 0))
+               return r;
+
+       if (memcmp(verity_io_real_digest(v, io), verity_io_want_digest(v, io),
+                  v->digest_size)) {
+               DMERR_LIMIT("%s: FEC %llu: failed to correct (%d erasures)",
+                           v->data_dev->name, (unsigned long long)rsb, neras);
+               return -EILSEQ;
+       }
+
+       return 0;
+}
+
+static int fec_bv_copy(struct dm_verity *v, struct dm_verity_io *io, u8 *data,
+                      size_t len)
+{
+       struct dm_verity_fec_io *fio = fec_io(io);
+
+       memcpy(data, &fio->output[fio->output_pos], len);
+       fio->output_pos += len;
+
+       return 0;
+}
+
+/*
+ * Correct errors in a block. Copies corrected block to dest if non-NULL,
+ * otherwise to a bio_vec starting from iter.
+ */
+int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io,
+                     enum verity_block_type type, sector_t block, u8 *dest,
+                     struct bvec_iter *iter)
+{
+       int r;
+       struct dm_verity_fec_io *fio = fec_io(io);
+       u64 offset, res, rsb;
+
+       if (!verity_fec_is_enabled(v))
+               return -EOPNOTSUPP;
+
+       if (type == DM_VERITY_BLOCK_TYPE_METADATA)
+               block += v->data_blocks;
+
+       /*
+        * For RS(M, N), the continuous FEC data is divided into blocks of N
+        * bytes. Since block size may not be divisible by N, the last block
+        * is zero padded when decoding.
+        *
+        * Each byte of the block is covered by a different RS(M, N) code,
+        * and each code is interleaved over N blocks to make it less likely
+        * that bursty corruption will leave us in unrecoverable state.
+        */
+
+       offset = block << v->data_dev_block_bits;
+
+       res = offset;
+       div64_u64(res, v->fec->rounds << v->data_dev_block_bits);
+
+       /*
+        * The base RS block we can feed to the interleaver to find out all
+        * blocks required for decoding.
+        */
+       rsb = offset - res * (v->fec->rounds << v->data_dev_block_bits);
+
+       /*
+        * Locating erasures is slow, so attempt to recover the block without
+        * them first. Do a second attempt with erasures if the corruption is
+        * bad enough.
+        */
+       r = fec_decode_rsb(v, io, fio, rsb, offset, false);
+       if (r < 0) {
+               r = fec_decode_rsb(v, io, fio, rsb, offset, true);
+               if (r < 0)
+                       return r;
+       }
+
+       if (dest)
+               memcpy(dest, fio->output, 1 << v->data_dev_block_bits);
+       else if (iter) {
+               fio->output_pos = 0;
+               r = verity_for_bv_block(v, io, iter, fec_bv_copy);
+       }
+
+       return r;
+}
+
+/*
+ * Clean up per-bio data.
+ */
+void verity_fec_finish_io(struct dm_verity_io *io)
+{
+       unsigned n;
+       struct dm_verity_fec *f = io->v->fec;
+       struct dm_verity_fec_io *fio = fec_io(io);
+
+       if (!verity_fec_is_enabled(io->v))
+               return;
+
+       mempool_free(fio->rs, f->rs_pool);
+
+       fec_for_each_prealloc_buffer(n)
+               mempool_free(fio->bufs[n], f->prealloc_pool);
+
+       fec_for_each_extra_buffer(fio, n)
+               mempool_free(fio->bufs[n], f->extra_pool);
+
+       mempool_free(fio->output, f->output_pool);
+}
+
+/*
+ * Initialize per-bio data.
+ */
+void verity_fec_init_io(struct dm_verity_io *io)
+{
+       struct dm_verity_fec_io *fio = fec_io(io);
+
+       if (!verity_fec_is_enabled(io->v))
+               return;
+
+       fio->rs = NULL;
+       memset(fio->bufs, 0, sizeof(fio->bufs));
+       fio->nbufs = 0;
+       fio->output = NULL;
+}
+
+/*
+ * Append feature arguments and values to the status table.
+ */
+unsigned verity_fec_status_table(struct dm_verity *v, unsigned sz,
+                                char *result, unsigned maxlen)
+{
+       if (!verity_fec_is_enabled(v))
+               return sz;
+
+       DMEMIT(" " DM_VERITY_OPT_FEC_DEV " %s "
+              DM_VERITY_OPT_FEC_BLOCKS " %llu "
+              DM_VERITY_OPT_FEC_START " %llu "
+              DM_VERITY_OPT_FEC_ROOTS " %d",
+              v->fec->dev->name,
+              (unsigned long long)v->fec->blocks,
+              (unsigned long long)v->fec->start,
+              v->fec->roots);
+
+       return sz;
+}
+
+void verity_fec_dtr(struct dm_verity *v)
+{
+       struct dm_verity_fec *f = v->fec;
+
+       if (!verity_fec_is_enabled(v))
+               goto out;
+
+       mempool_destroy(f->rs_pool);
+       mempool_destroy(f->prealloc_pool);
+       mempool_destroy(f->extra_pool);
+       kmem_cache_destroy(f->cache);
+
+       if (f->data_bufio)
+               dm_bufio_client_destroy(f->data_bufio);
+       if (f->bufio)
+               dm_bufio_client_destroy(f->bufio);
+
+       if (f->dev)
+               dm_put_device(v->ti, f->dev);
+out:
+       kfree(f);
+       v->fec = NULL;
+}
+
+static void *fec_rs_alloc(gfp_t gfp_mask, void *pool_data)
+{
+       struct dm_verity *v = (struct dm_verity *)pool_data;
+
+       return init_rs(8, 0x11d, 0, 1, v->fec->roots);
+}
+
+static void fec_rs_free(void *element, void *pool_data)
+{
+       struct rs_control *rs = (struct rs_control *)element;
+
+       if (rs)
+               free_rs(rs);
+}
+
+bool verity_is_fec_opt_arg(const char *arg_name)
+{
+       return (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_DEV) ||
+               !strcasecmp(arg_name, DM_VERITY_OPT_FEC_BLOCKS) ||
+               !strcasecmp(arg_name, DM_VERITY_OPT_FEC_START) ||
+               !strcasecmp(arg_name, DM_VERITY_OPT_FEC_ROOTS));
+}
+
+int verity_fec_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
+                             unsigned *argc, const char *arg_name)
+{
+       int r;
+       struct dm_target *ti = v->ti;
+       const char *arg_value;
+       unsigned long long num_ll;
+       unsigned char num_c;
+       char dummy;
+
+       if (!*argc) {
+               ti->error = "FEC feature arguments require a value";
+               return -EINVAL;
+       }
+
+       arg_value = dm_shift_arg(as);
+       (*argc)--;
+
+       if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_DEV)) {
+               r = dm_get_device(ti, arg_value, FMODE_READ, &v->fec->dev);
+               if (r) {
+                       ti->error = "FEC device lookup failed";
+                       return r;
+               }
+
+       } else if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_BLOCKS)) {
+               if (sscanf(arg_value, "%llu%c", &num_ll, &dummy) != 1 ||
+                   ((sector_t)(num_ll << (v->data_dev_block_bits - SECTOR_SHIFT))
+                    >> (v->data_dev_block_bits - SECTOR_SHIFT) != num_ll)) {
+                       ti->error = "Invalid " DM_VERITY_OPT_FEC_BLOCKS;
+                       return -EINVAL;
+               }
+               v->fec->blocks = num_ll;
+
+       } else if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_START)) {
+               if (sscanf(arg_value, "%llu%c", &num_ll, &dummy) != 1 ||
+                   ((sector_t)(num_ll << (v->data_dev_block_bits - SECTOR_SHIFT)) >>
+                    (v->data_dev_block_bits - SECTOR_SHIFT) != num_ll)) {
+                       ti->error = "Invalid " DM_VERITY_OPT_FEC_START;
+                       return -EINVAL;
+               }
+               v->fec->start = num_ll;
+
+       } else if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_ROOTS)) {
+               if (sscanf(arg_value, "%hhu%c", &num_c, &dummy) != 1 || !num_c ||
+                   num_c < (DM_VERITY_FEC_RSM - DM_VERITY_FEC_MAX_RSN) ||
+                   num_c > (DM_VERITY_FEC_RSM - DM_VERITY_FEC_MIN_RSN)) {
+                       ti->error = "Invalid " DM_VERITY_OPT_FEC_ROOTS;
+                       return -EINVAL;
+               }
+               v->fec->roots = num_c;
+
+       } else {
+               ti->error = "Unrecognized verity FEC feature request";
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * Allocate dm_verity_fec for v->fec. Must be called before verity_fec_ctr.
+ */
+int verity_fec_ctr_alloc(struct dm_verity *v)
+{
+       struct dm_verity_fec *f;
+
+       f = kzalloc(sizeof(struct dm_verity_fec), GFP_KERNEL);
+       if (!f) {
+               v->ti->error = "Cannot allocate FEC structure";
+               return -ENOMEM;
+       }
+       v->fec = f;
+
+       return 0;
+}
+
+/*
+ * Validate arguments and preallocate memory. Must be called after arguments
+ * have been parsed using verity_fec_parse_opt_args.
+ */
+int verity_fec_ctr(struct dm_verity *v)
+{
+       struct dm_verity_fec *f = v->fec;
+       struct dm_target *ti = v->ti;
+       u64 hash_blocks;
+
+       if (!verity_fec_is_enabled(v)) {
+               verity_fec_dtr(v);
+               return 0;
+       }
+
+       /*
+        * FEC is computed over data blocks, possible metadata, and
+        * hash blocks. In other words, FEC covers total of fec_blocks
+        * blocks consisting of the following:
+        *
+        *  data blocks | hash blocks | metadata (optional)
+        *
+        * We allow metadata after hash blocks to support a use case
+        * where all data is stored on the same device and FEC covers
+        * the entire area.
+        *
+        * If metadata is included, we require it to be available on the
+        * hash device after the hash blocks.
+        */
+
+       hash_blocks = v->hash_blocks - v->hash_start;
+
+       /*
+        * Require matching block sizes for data and hash devices for
+        * simplicity.
+        */
+       if (v->data_dev_block_bits != v->hash_dev_block_bits) {
+               ti->error = "Block sizes must match to use FEC";
+               return -EINVAL;
+       }
+
+       if (!f->roots) {
+               ti->error = "Missing " DM_VERITY_OPT_FEC_ROOTS;
+               return -EINVAL;
+       }
+       f->rsn = DM_VERITY_FEC_RSM - f->roots;
+
+       if (!f->blocks) {
+               ti->error = "Missing " DM_VERITY_OPT_FEC_BLOCKS;
+               return -EINVAL;
+       }
+
+       f->rounds = f->blocks;
+       if (sector_div(f->rounds, f->rsn))
+               f->rounds++;
+
+       /*
+        * Due to optional metadata, f->blocks can be larger than
+        * data_blocks and hash_blocks combined.
+        */
+       if (f->blocks < v->data_blocks + hash_blocks || !f->rounds) {
+               ti->error = "Invalid " DM_VERITY_OPT_FEC_BLOCKS;
+               return -EINVAL;
+       }
+
+       /*
+        * Metadata is accessed through the hash device, so we require
+        * it to be large enough.
+        */
+       f->hash_blocks = f->blocks - v->data_blocks;
+       if (dm_bufio_get_device_size(v->bufio) < f->hash_blocks) {
+               ti->error = "Hash device is too small for "
+                       DM_VERITY_OPT_FEC_BLOCKS;
+               return -E2BIG;
+       }
+
+       f->bufio = dm_bufio_client_create(f->dev->bdev,
+                                         1 << v->data_dev_block_bits,
+                                         1, 0, NULL, NULL);
+       if (IS_ERR(f->bufio)) {
+               ti->error = "Cannot initialize FEC bufio client";
+               return PTR_ERR(f->bufio);
+       }
+
+       if (dm_bufio_get_device_size(f->bufio) <
+           ((f->start + f->rounds * f->roots) >> v->data_dev_block_bits)) {
+               ti->error = "FEC device is too small";
+               return -E2BIG;
+       }
+
+       f->data_bufio = dm_bufio_client_create(v->data_dev->bdev,
+                                              1 << v->data_dev_block_bits,
+                                              1, 0, NULL, NULL);
+       if (IS_ERR(f->data_bufio)) {
+               ti->error = "Cannot initialize FEC data bufio client";
+               return PTR_ERR(f->data_bufio);
+       }
+
+       if (dm_bufio_get_device_size(f->data_bufio) < v->data_blocks) {
+               ti->error = "Data device is too small";
+               return -E2BIG;
+       }
+
+       /* Preallocate an rs_control structure for each worker thread */
+       f->rs_pool = mempool_create(num_online_cpus(), fec_rs_alloc,
+                                   fec_rs_free, (void *) v);
+       if (!f->rs_pool) {
+               ti->error = "Cannot allocate RS pool";
+               return -ENOMEM;
+       }
+
+       f->cache = kmem_cache_create("dm_verity_fec_buffers",
+                                    f->rsn << DM_VERITY_FEC_BUF_RS_BITS,
+                                    0, 0, NULL);
+       if (!f->cache) {
+               ti->error = "Cannot create FEC buffer cache";
+               return -ENOMEM;
+       }
+
+       /* Preallocate DM_VERITY_FEC_BUF_PREALLOC buffers for each thread */
+       f->prealloc_pool = mempool_create_slab_pool(num_online_cpus() *
+                                                   DM_VERITY_FEC_BUF_PREALLOC,
+                                                   f->cache);
+       if (!f->prealloc_pool) {
+               ti->error = "Cannot allocate FEC buffer prealloc pool";
+               return -ENOMEM;
+       }
+
+       f->extra_pool = mempool_create_slab_pool(0, f->cache);
+       if (!f->extra_pool) {
+               ti->error = "Cannot allocate FEC buffer extra pool";
+               return -ENOMEM;
+       }
+
+       /* Preallocate an output buffer for each thread */
+       f->output_pool = mempool_create_kmalloc_pool(num_online_cpus(),
+                                                    1 << v->data_dev_block_bits);
+       if (!f->output_pool) {
+               ti->error = "Cannot allocate FEC output pool";
+               return -ENOMEM;
+       }
+
+       /* Reserve space for our per-bio data */
+       ti->per_bio_data_size += sizeof(struct dm_verity_fec_io);
+
+       return 0;
+}
diff --git a/drivers/md/dm-verity-fec.h b/drivers/md/dm-verity-fec.h
new file mode 100644 (file)
index 0000000..7fa0298
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Author: Sami Tolvanen <samitolvanen@google.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#ifndef DM_VERITY_FEC_H
+#define DM_VERITY_FEC_H
+
+#include "dm-verity.h"
+#include <linux/rslib.h>
+
+/* Reed-Solomon(M, N) parameters */
+#define DM_VERITY_FEC_RSM              255
+#define DM_VERITY_FEC_MAX_RSN          253
+#define DM_VERITY_FEC_MIN_RSN          231     /* ~10% space overhead */
+
+/* buffers for deinterleaving and decoding */
+#define DM_VERITY_FEC_BUF_PREALLOC     1       /* buffers to preallocate */
+#define DM_VERITY_FEC_BUF_RS_BITS      4       /* 1 << RS blocks per buffer */
+/* we need buffers for at most 1 << block size RS blocks */
+#define DM_VERITY_FEC_BUF_MAX \
+       (1 << (PAGE_SHIFT - DM_VERITY_FEC_BUF_RS_BITS))
+
+#define DM_VERITY_OPT_FEC_DEV          "use_fec_from_device"
+#define DM_VERITY_OPT_FEC_BLOCKS       "fec_blocks"
+#define DM_VERITY_OPT_FEC_START                "fec_start"
+#define DM_VERITY_OPT_FEC_ROOTS                "fec_roots"
+
+/* configuration */
+struct dm_verity_fec {
+       struct dm_dev *dev;     /* parity data device */
+       struct dm_bufio_client *data_bufio;     /* for data dev access */
+       struct dm_bufio_client *bufio;          /* for parity data access */
+       sector_t start;         /* parity data start in blocks */
+       sector_t blocks;        /* number of blocks covered */
+       sector_t rounds;        /* number of interleaving rounds */
+       sector_t hash_blocks;   /* blocks covered after v->hash_start */
+       unsigned char roots;    /* number of parity bytes, M-N of RS(M, N) */
+       unsigned char rsn;      /* N of RS(M, N) */
+       mempool_t *rs_pool;     /* mempool for fio->rs */
+       mempool_t *prealloc_pool;       /* mempool for preallocated buffers */
+       mempool_t *extra_pool;  /* mempool for extra buffers */
+       mempool_t *output_pool; /* mempool for output */
+       struct kmem_cache *cache;       /* cache for buffers */
+};
+
+/* per-bio data */
+struct dm_verity_fec_io {
+       struct rs_control *rs;  /* Reed-Solomon state */
+       int erasures[DM_VERITY_FEC_MAX_RSN];    /* erasures for decode_rs8 */
+       u8 *bufs[DM_VERITY_FEC_BUF_MAX];        /* bufs for deinterleaving */
+       unsigned nbufs;         /* number of buffers allocated */
+       u8 *output;             /* buffer for corrected output */
+       size_t output_pos;
+};
+
+#ifdef CONFIG_DM_VERITY_FEC
+
+/* each feature parameter requires a value */
+#define DM_VERITY_OPTS_FEC     8
+
+extern bool verity_fec_is_enabled(struct dm_verity *v);
+
+extern int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io,
+                            enum verity_block_type type, sector_t block,
+                            u8 *dest, struct bvec_iter *iter);
+
+extern unsigned verity_fec_status_table(struct dm_verity *v, unsigned sz,
+                                       char *result, unsigned maxlen);
+
+extern void verity_fec_finish_io(struct dm_verity_io *io);
+extern void verity_fec_init_io(struct dm_verity_io *io);
+
+extern bool verity_is_fec_opt_arg(const char *arg_name);
+extern int verity_fec_parse_opt_args(struct dm_arg_set *as,
+                                    struct dm_verity *v, unsigned *argc,
+                                    const char *arg_name);
+
+extern void verity_fec_dtr(struct dm_verity *v);
+
+extern int verity_fec_ctr_alloc(struct dm_verity *v);
+extern int verity_fec_ctr(struct dm_verity *v);
+
+#else /* !CONFIG_DM_VERITY_FEC */
+
+#define DM_VERITY_OPTS_FEC     0
+
+static inline bool verity_fec_is_enabled(struct dm_verity *v)
+{
+       return false;
+}
+
+static inline int verity_fec_decode(struct dm_verity *v,
+                                   struct dm_verity_io *io,
+                                   enum verity_block_type type,
+                                   sector_t block, u8 *dest,
+                                   struct bvec_iter *iter)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline unsigned verity_fec_status_table(struct dm_verity *v,
+                                              unsigned sz, char *result,
+                                              unsigned maxlen)
+{
+       return sz;
+}
+
+static inline void verity_fec_finish_io(struct dm_verity_io *io)
+{
+}
+
+static inline void verity_fec_init_io(struct dm_verity_io *io)
+{
+}
+
+static inline bool verity_is_fec_opt_arg(const char *arg_name)
+{
+       return false;
+}
+
+static inline int verity_fec_parse_opt_args(struct dm_arg_set *as,
+                                           struct dm_verity *v,
+                                           unsigned *argc,
+                                           const char *arg_name)
+{
+       return -EINVAL;
+}
+
+static inline void verity_fec_dtr(struct dm_verity *v)
+{
+}
+
+static inline int verity_fec_ctr_alloc(struct dm_verity *v)
+{
+       return 0;
+}
+
+static inline int verity_fec_ctr(struct dm_verity *v)
+{
+       return 0;
+}
+
+#endif /* CONFIG_DM_VERITY_FEC */
+
+#endif /* DM_VERITY_FEC_H */
diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
new file mode 100644 (file)
index 0000000..5c5d30c
--- /dev/null
@@ -0,0 +1,1093 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * Author: Mikulas Patocka <mpatocka@redhat.com>
+ *
+ * Based on Chromium dm-verity driver (C) 2011 The Chromium OS Authors
+ *
+ * This file is released under the GPLv2.
+ *
+ * In the file "/sys/module/dm_verity/parameters/prefetch_cluster" you can set
+ * default prefetch value. Data are read in "prefetch_cluster" chunks from the
+ * hash device. Setting this greatly improves performance when data and hash
+ * are on the same disk on different partitions on devices with poor random
+ * access behavior.
+ */
+
+#include "dm-verity.h"
+#include "dm-verity-fec.h"
+
+#include <linux/module.h>
+#include <linux/reboot.h>
+
+#define DM_MSG_PREFIX                  "verity"
+
+#define DM_VERITY_ENV_LENGTH           42
+#define DM_VERITY_ENV_VAR_NAME         "DM_VERITY_ERR_BLOCK_NR"
+
+#define DM_VERITY_DEFAULT_PREFETCH_SIZE        262144
+
+#define DM_VERITY_MAX_CORRUPTED_ERRS   100
+
+#define DM_VERITY_OPT_LOGGING          "ignore_corruption"
+#define DM_VERITY_OPT_RESTART          "restart_on_corruption"
+#define DM_VERITY_OPT_IGN_ZEROES       "ignore_zero_blocks"
+
+#define DM_VERITY_OPTS_MAX             (2 + DM_VERITY_OPTS_FEC)
+
+static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE;
+
+module_param_named(prefetch_cluster, dm_verity_prefetch_cluster, uint, S_IRUGO | S_IWUSR);
+
+struct dm_verity_prefetch_work {
+       struct work_struct work;
+       struct dm_verity *v;
+       sector_t block;
+       unsigned n_blocks;
+};
+
+/*
+ * Auxiliary structure appended to each dm-bufio buffer. If the value
+ * hash_verified is nonzero, hash of the block has been verified.
+ *
+ * The variable hash_verified is set to 0 when allocating the buffer, then
+ * it can be changed to 1 and it is never reset to 0 again.
+ *
+ * There is no lock around this value, a race condition can at worst cause
+ * that multiple processes verify the hash of the same buffer simultaneously
+ * and write 1 to hash_verified simultaneously.
+ * This condition is harmless, so we don't need locking.
+ */
+struct buffer_aux {
+       int hash_verified;
+};
+
+/*
+ * Initialize struct buffer_aux for a freshly created buffer.
+ */
+static void dm_bufio_alloc_callback(struct dm_buffer *buf)
+{
+       struct buffer_aux *aux = dm_bufio_get_aux_data(buf);
+
+       aux->hash_verified = 0;
+}
+
+/*
+ * Translate input sector number to the sector number on the target device.
+ */
+static sector_t verity_map_sector(struct dm_verity *v, sector_t bi_sector)
+{
+       return v->data_start + dm_target_offset(v->ti, bi_sector);
+}
+
+/*
+ * Return hash position of a specified block at a specified tree level
+ * (0 is the lowest level).
+ * The lowest "hash_per_block_bits"-bits of the result denote hash position
+ * inside a hash block. The remaining bits denote location of the hash block.
+ */
+static sector_t verity_position_at_level(struct dm_verity *v, sector_t block,
+                                        int level)
+{
+       return block >> (level * v->hash_per_block_bits);
+}
+
+/*
+ * Wrapper for crypto_shash_init, which handles verity salting.
+ */
+static int verity_hash_init(struct dm_verity *v, struct shash_desc *desc)
+{
+       int r;
+
+       desc->tfm = v->tfm;
+       desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       r = crypto_shash_init(desc);
+
+       if (unlikely(r < 0)) {
+               DMERR("crypto_shash_init failed: %d", r);
+               return r;
+       }
+
+       if (likely(v->version >= 1)) {
+               r = crypto_shash_update(desc, v->salt, v->salt_size);
+
+               if (unlikely(r < 0)) {
+                       DMERR("crypto_shash_update failed: %d", r);
+                       return r;
+               }
+       }
+
+       return 0;
+}
+
+static int verity_hash_update(struct dm_verity *v, struct shash_desc *desc,
+                             const u8 *data, size_t len)
+{
+       int r = crypto_shash_update(desc, data, len);
+
+       if (unlikely(r < 0))
+               DMERR("crypto_shash_update failed: %d", r);
+
+       return r;
+}
+
+static int verity_hash_final(struct dm_verity *v, struct shash_desc *desc,
+                            u8 *digest)
+{
+       int r;
+
+       if (unlikely(!v->version)) {
+               r = crypto_shash_update(desc, v->salt, v->salt_size);
+
+               if (r < 0) {
+                       DMERR("crypto_shash_update failed: %d", r);
+                       return r;
+               }
+       }
+
+       r = crypto_shash_final(desc, digest);
+
+       if (unlikely(r < 0))
+               DMERR("crypto_shash_final failed: %d", r);
+
+       return r;
+}
+
+int verity_hash(struct dm_verity *v, struct shash_desc *desc,
+               const u8 *data, size_t len, u8 *digest)
+{
+       int r;
+
+       r = verity_hash_init(v, desc);
+       if (unlikely(r < 0))
+               return r;
+
+       r = verity_hash_update(v, desc, data, len);
+       if (unlikely(r < 0))
+               return r;
+
+       return verity_hash_final(v, desc, digest);
+}
+
+static void verity_hash_at_level(struct dm_verity *v, sector_t block, int level,
+                                sector_t *hash_block, unsigned *offset)
+{
+       sector_t position = verity_position_at_level(v, block, level);
+       unsigned idx;
+
+       *hash_block = v->hash_level_block[level] + (position >> v->hash_per_block_bits);
+
+       if (!offset)
+               return;
+
+       idx = position & ((1 << v->hash_per_block_bits) - 1);
+       if (!v->version)
+               *offset = idx * v->digest_size;
+       else
+               *offset = idx << (v->hash_dev_block_bits - v->hash_per_block_bits);
+}
+
+/*
+ * Handle verification errors.
+ */
+static int verity_handle_err(struct dm_verity *v, enum verity_block_type type,
+                            unsigned long long block)
+{
+       char verity_env[DM_VERITY_ENV_LENGTH];
+       char *envp[] = { verity_env, NULL };
+       const char *type_str = "";
+       struct mapped_device *md = dm_table_get_md(v->ti->table);
+
+       /* Corruption should be visible in device status in all modes */
+       v->hash_failed = 1;
+
+       if (v->corrupted_errs >= DM_VERITY_MAX_CORRUPTED_ERRS)
+               goto out;
+
+       v->corrupted_errs++;
+
+       switch (type) {
+       case DM_VERITY_BLOCK_TYPE_DATA:
+               type_str = "data";
+               break;
+       case DM_VERITY_BLOCK_TYPE_METADATA:
+               type_str = "metadata";
+               break;
+       default:
+               BUG();
+       }
+
+       DMERR("%s: %s block %llu is corrupted", v->data_dev->name, type_str,
+               block);
+
+       if (v->corrupted_errs == DM_VERITY_MAX_CORRUPTED_ERRS)
+               DMERR("%s: reached maximum errors", v->data_dev->name);
+
+       snprintf(verity_env, DM_VERITY_ENV_LENGTH, "%s=%d,%llu",
+               DM_VERITY_ENV_VAR_NAME, type, block);
+
+       kobject_uevent_env(&disk_to_dev(dm_disk(md))->kobj, KOBJ_CHANGE, envp);
+
+out:
+       if (v->mode == DM_VERITY_MODE_LOGGING)
+               return 0;
+
+       if (v->mode == DM_VERITY_MODE_RESTART)
+               kernel_restart("dm-verity device corrupted");
+
+       return 1;
+}
+
+/*
+ * Verify hash of a metadata block pertaining to the specified data block
+ * ("block" argument) at a specified level ("level" argument).
+ *
+ * On successful return, verity_io_want_digest(v, io) contains the hash value
+ * for a lower tree level or for the data block (if we're at the lowest level).
+ *
+ * If "skip_unverified" is true, unverified buffer is skipped and 1 is returned.
+ * If "skip_unverified" is false, unverified buffer is hashed and verified
+ * against current value of verity_io_want_digest(v, io).
+ */
+static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
+                              sector_t block, int level, bool skip_unverified,
+                              u8 *want_digest)
+{
+       struct dm_buffer *buf;
+       struct buffer_aux *aux;
+       u8 *data;
+       int r;
+       sector_t hash_block;
+       unsigned offset;
+
+       verity_hash_at_level(v, block, level, &hash_block, &offset);
+
+       data = dm_bufio_read(v->bufio, hash_block, &buf);
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       aux = dm_bufio_get_aux_data(buf);
+
+       if (!aux->hash_verified) {
+               if (skip_unverified) {
+                       r = 1;
+                       goto release_ret_r;
+               }
+
+               r = verity_hash(v, verity_io_hash_desc(v, io),
+                               data, 1 << v->hash_dev_block_bits,
+                               verity_io_real_digest(v, io));
+               if (unlikely(r < 0))
+                       goto release_ret_r;
+
+               if (likely(memcmp(verity_io_real_digest(v, io), want_digest,
+                                 v->digest_size) == 0))
+                       aux->hash_verified = 1;
+               else if (verity_fec_decode(v, io,
+                                          DM_VERITY_BLOCK_TYPE_METADATA,
+                                          hash_block, data, NULL) == 0)
+                       aux->hash_verified = 1;
+               else if (verity_handle_err(v,
+                                          DM_VERITY_BLOCK_TYPE_METADATA,
+                                          hash_block)) {
+                       r = -EIO;
+                       goto release_ret_r;
+               }
+       }
+
+       data += offset;
+       memcpy(want_digest, data, v->digest_size);
+       r = 0;
+
+release_ret_r:
+       dm_bufio_release(buf);
+       return r;
+}
+
+/*
+ * Find a hash for a given block, write it to digest and verify the integrity
+ * of the hash tree if necessary.
+ */
+int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,
+                         sector_t block, u8 *digest, bool *is_zero)
+{
+       int r = 0, i;
+
+       if (likely(v->levels)) {
+               /*
+                * First, we try to get the requested hash for
+                * the current block. If the hash block itself is
+                * verified, zero is returned. If it isn't, this
+                * function returns 1 and we fall back to whole
+                * chain verification.
+                */
+               r = verity_verify_level(v, io, block, 0, true, digest);
+               if (likely(r <= 0))
+                       goto out;
+       }
+
+       memcpy(digest, v->root_digest, v->digest_size);
+
+       for (i = v->levels - 1; i >= 0; i--) {
+               r = verity_verify_level(v, io, block, i, false, digest);
+               if (unlikely(r))
+                       goto out;
+       }
+out:
+       if (!r && v->zero_digest)
+               *is_zero = !memcmp(v->zero_digest, digest, v->digest_size);
+       else
+               *is_zero = false;
+
+       return r;
+}
+
+/*
+ * Calls function process for 1 << v->data_dev_block_bits bytes in the bio_vec
+ * starting from iter.
+ */
+int verity_for_bv_block(struct dm_verity *v, struct dm_verity_io *io,
+                       struct bvec_iter *iter,
+                       int (*process)(struct dm_verity *v,
+                                      struct dm_verity_io *io, u8 *data,
+                                      size_t len))
+{
+       unsigned todo = 1 << v->data_dev_block_bits;
+       struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_bio_data_size);
+
+       do {
+               int r;
+               u8 *page;
+               unsigned len;
+               struct bio_vec bv = bio_iter_iovec(bio, *iter);
+
+               page = kmap_atomic(bv.bv_page);
+               len = bv.bv_len;
+
+               if (likely(len >= todo))
+                       len = todo;
+
+               r = process(v, io, page + bv.bv_offset, len);
+               kunmap_atomic(page);
+
+               if (r < 0)
+                       return r;
+
+               bio_advance_iter(bio, iter, len);
+               todo -= len;
+       } while (todo);
+
+       return 0;
+}
+
+static int verity_bv_hash_update(struct dm_verity *v, struct dm_verity_io *io,
+                                u8 *data, size_t len)
+{
+       return verity_hash_update(v, verity_io_hash_desc(v, io), data, len);
+}
+
+static int verity_bv_zero(struct dm_verity *v, struct dm_verity_io *io,
+                         u8 *data, size_t len)
+{
+       memset(data, 0, len);
+       return 0;
+}
+
+/*
+ * Verify one "dm_verity_io" structure.
+ */
+static int verity_verify_io(struct dm_verity_io *io)
+{
+       bool is_zero;
+       struct dm_verity *v = io->v;
+       struct bvec_iter start;
+       unsigned b;
+
+       for (b = 0; b < io->n_blocks; b++) {
+               int r;
+               struct shash_desc *desc = verity_io_hash_desc(v, io);
+
+               r = verity_hash_for_block(v, io, io->block + b,
+                                         verity_io_want_digest(v, io),
+                                         &is_zero);
+               if (unlikely(r < 0))
+                       return r;
+
+               if (is_zero) {
+                       /*
+                        * If we expect a zero block, don't validate, just
+                        * return zeros.
+                        */
+                       r = verity_for_bv_block(v, io, &io->iter,
+                                               verity_bv_zero);
+                       if (unlikely(r < 0))
+                               return r;
+
+                       continue;
+               }
+
+               r = verity_hash_init(v, desc);
+               if (unlikely(r < 0))
+                       return r;
+
+               start = io->iter;
+               r = verity_for_bv_block(v, io, &io->iter, verity_bv_hash_update);
+               if (unlikely(r < 0))
+                       return r;
+
+               r = verity_hash_final(v, desc, verity_io_real_digest(v, io));
+               if (unlikely(r < 0))
+                       return r;
+
+               if (likely(memcmp(verity_io_real_digest(v, io),
+                                 verity_io_want_digest(v, io), v->digest_size) == 0))
+                       continue;
+               else if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_DATA,
+                                          io->block + b, NULL, &start) == 0)
+                       continue;
+               else if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_DATA,
+                                          io->block + b))
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+/*
+ * End one "io" structure with a given error.
+ */
+static void verity_finish_io(struct dm_verity_io *io, int error)
+{
+       struct dm_verity *v = io->v;
+       struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_bio_data_size);
+
+       bio->bi_end_io = io->orig_bi_end_io;
+       bio->bi_error = error;
+
+       verity_fec_finish_io(io);
+
+       bio_endio(bio);
+}
+
+static void verity_work(struct work_struct *w)
+{
+       struct dm_verity_io *io = container_of(w, struct dm_verity_io, work);
+
+       verity_finish_io(io, verity_verify_io(io));
+}
+
+static void verity_end_io(struct bio *bio)
+{
+       struct dm_verity_io *io = bio->bi_private;
+
+       if (bio->bi_error && !verity_fec_is_enabled(io->v)) {
+               verity_finish_io(io, bio->bi_error);
+               return;
+       }
+
+       INIT_WORK(&io->work, verity_work);
+       queue_work(io->v->verify_wq, &io->work);
+}
+
+/*
+ * Prefetch buffers for the specified io.
+ * The root buffer is not prefetched, it is assumed that it will be cached
+ * all the time.
+ */
+static void verity_prefetch_io(struct work_struct *work)
+{
+       struct dm_verity_prefetch_work *pw =
+               container_of(work, struct dm_verity_prefetch_work, work);
+       struct dm_verity *v = pw->v;
+       int i;
+
+       for (i = v->levels - 2; i >= 0; i--) {
+               sector_t hash_block_start;
+               sector_t hash_block_end;
+               verity_hash_at_level(v, pw->block, i, &hash_block_start, NULL);
+               verity_hash_at_level(v, pw->block + pw->n_blocks - 1, i, &hash_block_end, NULL);
+               if (!i) {
+                       unsigned cluster = ACCESS_ONCE(dm_verity_prefetch_cluster);
+
+                       cluster >>= v->data_dev_block_bits;
+                       if (unlikely(!cluster))
+                               goto no_prefetch_cluster;
+
+                       if (unlikely(cluster & (cluster - 1)))
+                               cluster = 1 << __fls(cluster);
+
+                       hash_block_start &= ~(sector_t)(cluster - 1);
+                       hash_block_end |= cluster - 1;
+                       if (unlikely(hash_block_end >= v->hash_blocks))
+                               hash_block_end = v->hash_blocks - 1;
+               }
+no_prefetch_cluster:
+               dm_bufio_prefetch(v->bufio, hash_block_start,
+                                 hash_block_end - hash_block_start + 1);
+       }
+
+       kfree(pw);
+}
+
+static void verity_submit_prefetch(struct dm_verity *v, struct dm_verity_io *io)
+{
+       struct dm_verity_prefetch_work *pw;
+
+       pw = kmalloc(sizeof(struct dm_verity_prefetch_work),
+               GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN);
+
+       if (!pw)
+               return;
+
+       INIT_WORK(&pw->work, verity_prefetch_io);
+       pw->v = v;
+       pw->block = io->block;
+       pw->n_blocks = io->n_blocks;
+       queue_work(v->verify_wq, &pw->work);
+}
+
+/*
+ * Bio map function. It allocates dm_verity_io structure and bio vector and
+ * fills them. Then it issues prefetches and the I/O.
+ */
+static int verity_map(struct dm_target *ti, struct bio *bio)
+{
+       struct dm_verity *v = ti->private;
+       struct dm_verity_io *io;
+
+       bio->bi_bdev = v->data_dev->bdev;
+       bio->bi_iter.bi_sector = verity_map_sector(v, bio->bi_iter.bi_sector);
+
+       if (((unsigned)bio->bi_iter.bi_sector | bio_sectors(bio)) &
+           ((1 << (v->data_dev_block_bits - SECTOR_SHIFT)) - 1)) {
+               DMERR_LIMIT("unaligned io");
+               return -EIO;
+       }
+
+       if (bio_end_sector(bio) >>
+           (v->data_dev_block_bits - SECTOR_SHIFT) > v->data_blocks) {
+               DMERR_LIMIT("io out of range");
+               return -EIO;
+       }
+
+       if (bio_data_dir(bio) == WRITE)
+               return -EIO;
+
+       io = dm_per_bio_data(bio, ti->per_bio_data_size);
+       io->v = v;
+       io->orig_bi_end_io = bio->bi_end_io;
+       io->block = bio->bi_iter.bi_sector >> (v->data_dev_block_bits - SECTOR_SHIFT);
+       io->n_blocks = bio->bi_iter.bi_size >> v->data_dev_block_bits;
+
+       bio->bi_end_io = verity_end_io;
+       bio->bi_private = io;
+       io->iter = bio->bi_iter;
+
+       verity_fec_init_io(io);
+
+       verity_submit_prefetch(v, io);
+
+       generic_make_request(bio);
+
+       return DM_MAPIO_SUBMITTED;
+}
+
+/*
+ * Status: V (valid) or C (corruption found)
+ */
+static void verity_status(struct dm_target *ti, status_type_t type,
+                         unsigned status_flags, char *result, unsigned maxlen)
+{
+       struct dm_verity *v = ti->private;
+       unsigned args = 0;
+       unsigned sz = 0;
+       unsigned x;
+
+       switch (type) {
+       case STATUSTYPE_INFO:
+               DMEMIT("%c", v->hash_failed ? 'C' : 'V');
+               break;
+       case STATUSTYPE_TABLE:
+               DMEMIT("%u %s %s %u %u %llu %llu %s ",
+                       v->version,
+                       v->data_dev->name,
+                       v->hash_dev->name,
+                       1 << v->data_dev_block_bits,
+                       1 << v->hash_dev_block_bits,
+                       (unsigned long long)v->data_blocks,
+                       (unsigned long long)v->hash_start,
+                       v->alg_name
+                       );
+               for (x = 0; x < v->digest_size; x++)
+                       DMEMIT("%02x", v->root_digest[x]);
+               DMEMIT(" ");
+               if (!v->salt_size)
+                       DMEMIT("-");
+               else
+                       for (x = 0; x < v->salt_size; x++)
+                               DMEMIT("%02x", v->salt[x]);
+               if (v->mode != DM_VERITY_MODE_EIO)
+                       args++;
+               if (verity_fec_is_enabled(v))
+                       args += DM_VERITY_OPTS_FEC;
+               if (v->zero_digest)
+                       args++;
+               if (!args)
+                       return;
+               DMEMIT(" %u", args);
+               if (v->mode != DM_VERITY_MODE_EIO) {
+                       DMEMIT(" ");
+                       switch (v->mode) {
+                       case DM_VERITY_MODE_LOGGING:
+                               DMEMIT(DM_VERITY_OPT_LOGGING);
+                               break;
+                       case DM_VERITY_MODE_RESTART:
+                               DMEMIT(DM_VERITY_OPT_RESTART);
+                               break;
+                       default:
+                               BUG();
+                       }
+               }
+               if (v->zero_digest)
+                       DMEMIT(" " DM_VERITY_OPT_IGN_ZEROES);
+               sz = verity_fec_status_table(v, sz, result, maxlen);
+               break;
+       }
+}
+
+static int verity_prepare_ioctl(struct dm_target *ti,
+               struct block_device **bdev, fmode_t *mode)
+{
+       struct dm_verity *v = ti->private;
+
+       *bdev = v->data_dev->bdev;
+
+       if (v->data_start ||
+           ti->len != i_size_read(v->data_dev->bdev->bd_inode) >> SECTOR_SHIFT)
+               return 1;
+       return 0;
+}
+
+static int verity_iterate_devices(struct dm_target *ti,
+                                 iterate_devices_callout_fn fn, void *data)
+{
+       struct dm_verity *v = ti->private;
+
+       return fn(ti, v->data_dev, v->data_start, ti->len, data);
+}
+
+static void verity_io_hints(struct dm_target *ti, struct queue_limits *limits)
+{
+       struct dm_verity *v = ti->private;
+
+       if (limits->logical_block_size < 1 << v->data_dev_block_bits)
+               limits->logical_block_size = 1 << v->data_dev_block_bits;
+
+       if (limits->physical_block_size < 1 << v->data_dev_block_bits)
+               limits->physical_block_size = 1 << v->data_dev_block_bits;
+
+       blk_limits_io_min(limits, limits->logical_block_size);
+}
+
+static void verity_dtr(struct dm_target *ti)
+{
+       struct dm_verity *v = ti->private;
+
+       if (v->verify_wq)
+               destroy_workqueue(v->verify_wq);
+
+       if (v->bufio)
+               dm_bufio_client_destroy(v->bufio);
+
+       kfree(v->salt);
+       kfree(v->root_digest);
+       kfree(v->zero_digest);
+
+       if (v->tfm)
+               crypto_free_shash(v->tfm);
+
+       kfree(v->alg_name);
+
+       if (v->hash_dev)
+               dm_put_device(ti, v->hash_dev);
+
+       if (v->data_dev)
+               dm_put_device(ti, v->data_dev);
+
+       verity_fec_dtr(v);
+
+       kfree(v);
+}
+
+static int verity_alloc_zero_digest(struct dm_verity *v)
+{
+       int r = -ENOMEM;
+       struct shash_desc *desc;
+       u8 *zero_data;
+
+       v->zero_digest = kmalloc(v->digest_size, GFP_KERNEL);
+
+       if (!v->zero_digest)
+               return r;
+
+       desc = kmalloc(v->shash_descsize, GFP_KERNEL);
+
+       if (!desc)
+               return r; /* verity_dtr will free zero_digest */
+
+       zero_data = kzalloc(1 << v->data_dev_block_bits, GFP_KERNEL);
+
+       if (!zero_data)
+               goto out;
+
+       r = verity_hash(v, desc, zero_data, 1 << v->data_dev_block_bits,
+                       v->zero_digest);
+
+out:
+       kfree(desc);
+       kfree(zero_data);
+
+       return r;
+}
+
+static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v)
+{
+       int r;
+       unsigned argc;
+       struct dm_target *ti = v->ti;
+       const char *arg_name;
+
+       static struct dm_arg _args[] = {
+               {0, DM_VERITY_OPTS_MAX, "Invalid number of feature args"},
+       };
+
+       r = dm_read_arg_group(_args, as, &argc, &ti->error);
+       if (r)
+               return -EINVAL;
+
+       if (!argc)
+               return 0;
+
+       do {
+               arg_name = dm_shift_arg(as);
+               argc--;
+
+               if (!strcasecmp(arg_name, DM_VERITY_OPT_LOGGING)) {
+                       v->mode = DM_VERITY_MODE_LOGGING;
+                       continue;
+
+               } else if (!strcasecmp(arg_name, DM_VERITY_OPT_RESTART)) {
+                       v->mode = DM_VERITY_MODE_RESTART;
+                       continue;
+
+               } else if (!strcasecmp(arg_name, DM_VERITY_OPT_IGN_ZEROES)) {
+                       r = verity_alloc_zero_digest(v);
+                       if (r) {
+                               ti->error = "Cannot allocate zero digest";
+                               return r;
+                       }
+                       continue;
+
+               } else if (verity_is_fec_opt_arg(arg_name)) {
+                       r = verity_fec_parse_opt_args(as, v, &argc, arg_name);
+                       if (r)
+                               return r;
+                       continue;
+               }
+
+               ti->error = "Unrecognized verity feature request";
+               return -EINVAL;
+       } while (argc && !r);
+
+       return r;
+}
+
+/*
+ * Target parameters:
+ *     <version>       The current format is version 1.
+ *                     Vsn 0 is compatible with original Chromium OS releases.
+ *     <data device>
+ *     <hash device>
+ *     <data block size>
+ *     <hash block size>
+ *     <the number of data blocks>
+ *     <hash start block>
+ *     <algorithm>
+ *     <digest>
+ *     <salt>          Hex string or "-" if no salt.
+ */
+static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
+{
+       struct dm_verity *v;
+       struct dm_arg_set as;
+       unsigned int num;
+       unsigned long long num_ll;
+       int r;
+       int i;
+       sector_t hash_position;
+       char dummy;
+
+       v = kzalloc(sizeof(struct dm_verity), GFP_KERNEL);
+       if (!v) {
+               ti->error = "Cannot allocate verity structure";
+               return -ENOMEM;
+       }
+       ti->private = v;
+       v->ti = ti;
+
+       r = verity_fec_ctr_alloc(v);
+       if (r)
+               goto bad;
+
+       if ((dm_table_get_mode(ti->table) & ~FMODE_READ)) {
+               ti->error = "Device must be readonly";
+               r = -EINVAL;
+               goto bad;
+       }
+
+       if (argc < 10) {
+               ti->error = "Not enough arguments";
+               r = -EINVAL;
+               goto bad;
+       }
+
+       if (sscanf(argv[0], "%u%c", &num, &dummy) != 1 ||
+           num > 1) {
+               ti->error = "Invalid version";
+               r = -EINVAL;
+               goto bad;
+       }
+       v->version = num;
+
+       r = dm_get_device(ti, argv[1], FMODE_READ, &v->data_dev);
+       if (r) {
+               ti->error = "Data device lookup failed";
+               goto bad;
+       }
+
+       r = dm_get_device(ti, argv[2], FMODE_READ, &v->hash_dev);
+       if (r) {
+               ti->error = "Data device lookup failed";
+               goto bad;
+       }
+
+       if (sscanf(argv[3], "%u%c", &num, &dummy) != 1 ||
+           !num || (num & (num - 1)) ||
+           num < bdev_logical_block_size(v->data_dev->bdev) ||
+           num > PAGE_SIZE) {
+               ti->error = "Invalid data device block size";
+               r = -EINVAL;
+               goto bad;
+       }
+       v->data_dev_block_bits = __ffs(num);
+
+       if (sscanf(argv[4], "%u%c", &num, &dummy) != 1 ||
+           !num || (num & (num - 1)) ||
+           num < bdev_logical_block_size(v->hash_dev->bdev) ||
+           num > INT_MAX) {
+               ti->error = "Invalid hash device block size";
+               r = -EINVAL;
+               goto bad;
+       }
+       v->hash_dev_block_bits = __ffs(num);
+
+       if (sscanf(argv[5], "%llu%c", &num_ll, &dummy) != 1 ||
+           (sector_t)(num_ll << (v->data_dev_block_bits - SECTOR_SHIFT))
+           >> (v->data_dev_block_bits - SECTOR_SHIFT) != num_ll) {
+               ti->error = "Invalid data blocks";
+               r = -EINVAL;
+               goto bad;
+       }
+       v->data_blocks = num_ll;
+
+       if (ti->len > (v->data_blocks << (v->data_dev_block_bits - SECTOR_SHIFT))) {
+               ti->error = "Data device is too small";
+               r = -EINVAL;
+               goto bad;
+       }
+
+       if (sscanf(argv[6], "%llu%c", &num_ll, &dummy) != 1 ||
+           (sector_t)(num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT))
+           >> (v->hash_dev_block_bits - SECTOR_SHIFT) != num_ll) {
+               ti->error = "Invalid hash start";
+               r = -EINVAL;
+               goto bad;
+       }
+       v->hash_start = num_ll;
+
+       v->alg_name = kstrdup(argv[7], GFP_KERNEL);
+       if (!v->alg_name) {
+               ti->error = "Cannot allocate algorithm name";
+               r = -ENOMEM;
+               goto bad;
+       }
+
+       v->tfm = crypto_alloc_shash(v->alg_name, 0, 0);
+       if (IS_ERR(v->tfm)) {
+               ti->error = "Cannot initialize hash function";
+               r = PTR_ERR(v->tfm);
+               v->tfm = NULL;
+               goto bad;
+       }
+       v->digest_size = crypto_shash_digestsize(v->tfm);
+       if ((1 << v->hash_dev_block_bits) < v->digest_size * 2) {
+               ti->error = "Digest size too big";
+               r = -EINVAL;
+               goto bad;
+       }
+       v->shash_descsize =
+               sizeof(struct shash_desc) + crypto_shash_descsize(v->tfm);
+
+       v->root_digest = kmalloc(v->digest_size, GFP_KERNEL);
+       if (!v->root_digest) {
+               ti->error = "Cannot allocate root digest";
+               r = -ENOMEM;
+               goto bad;
+       }
+       if (strlen(argv[8]) != v->digest_size * 2 ||
+           hex2bin(v->root_digest, argv[8], v->digest_size)) {
+               ti->error = "Invalid root digest";
+               r = -EINVAL;
+               goto bad;
+       }
+
+       if (strcmp(argv[9], "-")) {
+               v->salt_size = strlen(argv[9]) / 2;
+               v->salt = kmalloc(v->salt_size, GFP_KERNEL);
+               if (!v->salt) {
+                       ti->error = "Cannot allocate salt";
+                       r = -ENOMEM;
+                       goto bad;
+               }
+               if (strlen(argv[9]) != v->salt_size * 2 ||
+                   hex2bin(v->salt, argv[9], v->salt_size)) {
+                       ti->error = "Invalid salt";
+                       r = -EINVAL;
+                       goto bad;
+               }
+       }
+
+       argv += 10;
+       argc -= 10;
+
+       /* Optional parameters */
+       if (argc) {
+               as.argc = argc;
+               as.argv = argv;
+
+               r = verity_parse_opt_args(&as, v);
+               if (r < 0)
+                       goto bad;
+       }
+
+       v->hash_per_block_bits =
+               __fls((1 << v->hash_dev_block_bits) / v->digest_size);
+
+       v->levels = 0;
+       if (v->data_blocks)
+               while (v->hash_per_block_bits * v->levels < 64 &&
+                      (unsigned long long)(v->data_blocks - 1) >>
+                      (v->hash_per_block_bits * v->levels))
+                       v->levels++;
+
+       if (v->levels > DM_VERITY_MAX_LEVELS) {
+               ti->error = "Too many tree levels";
+               r = -E2BIG;
+               goto bad;
+       }
+
+       hash_position = v->hash_start;
+       for (i = v->levels - 1; i >= 0; i--) {
+               sector_t s;
+               v->hash_level_block[i] = hash_position;
+               s = (v->data_blocks + ((sector_t)1 << ((i + 1) * v->hash_per_block_bits)) - 1)
+                                       >> ((i + 1) * v->hash_per_block_bits);
+               if (hash_position + s < hash_position) {
+                       ti->error = "Hash device offset overflow";
+                       r = -E2BIG;
+                       goto bad;
+               }
+               hash_position += s;
+       }
+       v->hash_blocks = hash_position;
+
+       v->bufio = dm_bufio_client_create(v->hash_dev->bdev,
+               1 << v->hash_dev_block_bits, 1, sizeof(struct buffer_aux),
+               dm_bufio_alloc_callback, NULL);
+       if (IS_ERR(v->bufio)) {
+               ti->error = "Cannot initialize dm-bufio";
+               r = PTR_ERR(v->bufio);
+               v->bufio = NULL;
+               goto bad;
+       }
+
+       if (dm_bufio_get_device_size(v->bufio) < v->hash_blocks) {
+               ti->error = "Hash device is too small";
+               r = -E2BIG;
+               goto bad;
+       }
+
+       /* WQ_UNBOUND greatly improves performance when running on ramdisk */
+       v->verify_wq = alloc_workqueue("kverityd", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND, num_online_cpus());
+       if (!v->verify_wq) {
+               ti->error = "Cannot allocate workqueue";
+               r = -ENOMEM;
+               goto bad;
+       }
+
+       ti->per_bio_data_size = sizeof(struct dm_verity_io) +
+                               v->shash_descsize + v->digest_size * 2;
+
+       r = verity_fec_ctr(v);
+       if (r)
+               goto bad;
+
+       ti->per_bio_data_size = roundup(ti->per_bio_data_size,
+                                       __alignof__(struct dm_verity_io));
+
+       return 0;
+
+bad:
+       verity_dtr(ti);
+
+       return r;
+}
+
+static struct target_type verity_target = {
+       .name           = "verity",
+       .version        = {1, 3, 0},
+       .module         = THIS_MODULE,
+       .ctr            = verity_ctr,
+       .dtr            = verity_dtr,
+       .map            = verity_map,
+       .status         = verity_status,
+       .prepare_ioctl  = verity_prepare_ioctl,
+       .iterate_devices = verity_iterate_devices,
+       .io_hints       = verity_io_hints,
+};
+
+static int __init dm_verity_init(void)
+{
+       int r;
+
+       r = dm_register_target(&verity_target);
+       if (r < 0)
+               DMERR("register failed %d", r);
+
+       return r;
+}
+
+static void __exit dm_verity_exit(void)
+{
+       dm_unregister_target(&verity_target);
+}
+
+module_init(dm_verity_init);
+module_exit(dm_verity_exit);
+
+MODULE_AUTHOR("Mikulas Patocka <mpatocka@redhat.com>");
+MODULE_AUTHOR("Mandeep Baines <msb@chromium.org>");
+MODULE_AUTHOR("Will Drewry <wad@chromium.org>");
+MODULE_DESCRIPTION(DM_NAME " target for transparent disk integrity checking");
+MODULE_LICENSE("GPL");
diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c
deleted file mode 100644 (file)
index ccf4188..0000000
+++ /dev/null
@@ -1,995 +0,0 @@
-/*
- * Copyright (C) 2012 Red Hat, Inc.
- *
- * Author: Mikulas Patocka <mpatocka@redhat.com>
- *
- * Based on Chromium dm-verity driver (C) 2011 The Chromium OS Authors
- *
- * This file is released under the GPLv2.
- *
- * In the file "/sys/module/dm_verity/parameters/prefetch_cluster" you can set
- * default prefetch value. Data are read in "prefetch_cluster" chunks from the
- * hash device. Setting this greatly improves performance when data and hash
- * are on the same disk on different partitions on devices with poor random
- * access behavior.
- */
-
-#include "dm-bufio.h"
-
-#include <linux/module.h>
-#include <linux/device-mapper.h>
-#include <linux/reboot.h>
-#include <crypto/hash.h>
-
-#define DM_MSG_PREFIX                  "verity"
-
-#define DM_VERITY_ENV_LENGTH           42
-#define DM_VERITY_ENV_VAR_NAME         "DM_VERITY_ERR_BLOCK_NR"
-
-#define DM_VERITY_DEFAULT_PREFETCH_SIZE        262144
-
-#define DM_VERITY_MAX_LEVELS           63
-#define DM_VERITY_MAX_CORRUPTED_ERRS   100
-
-#define DM_VERITY_OPT_LOGGING          "ignore_corruption"
-#define DM_VERITY_OPT_RESTART          "restart_on_corruption"
-
-static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE;
-
-module_param_named(prefetch_cluster, dm_verity_prefetch_cluster, uint, S_IRUGO | S_IWUSR);
-
-enum verity_mode {
-       DM_VERITY_MODE_EIO,
-       DM_VERITY_MODE_LOGGING,
-       DM_VERITY_MODE_RESTART
-};
-
-enum verity_block_type {
-       DM_VERITY_BLOCK_TYPE_DATA,
-       DM_VERITY_BLOCK_TYPE_METADATA
-};
-
-struct dm_verity {
-       struct dm_dev *data_dev;
-       struct dm_dev *hash_dev;
-       struct dm_target *ti;
-       struct dm_bufio_client *bufio;
-       char *alg_name;
-       struct crypto_shash *tfm;
-       u8 *root_digest;        /* digest of the root block */
-       u8 *salt;               /* salt: its size is salt_size */
-       unsigned salt_size;
-       sector_t data_start;    /* data offset in 512-byte sectors */
-       sector_t hash_start;    /* hash start in blocks */
-       sector_t data_blocks;   /* the number of data blocks */
-       sector_t hash_blocks;   /* the number of hash blocks */
-       unsigned char data_dev_block_bits;      /* log2(data blocksize) */
-       unsigned char hash_dev_block_bits;      /* log2(hash blocksize) */
-       unsigned char hash_per_block_bits;      /* log2(hashes in hash block) */
-       unsigned char levels;   /* the number of tree levels */
-       unsigned char version;
-       unsigned digest_size;   /* digest size for the current hash algorithm */
-       unsigned shash_descsize;/* the size of temporary space for crypto */
-       int hash_failed;        /* set to 1 if hash of any block failed */
-       enum verity_mode mode;  /* mode for handling verification errors */
-       unsigned corrupted_errs;/* Number of errors for corrupted blocks */
-
-       struct workqueue_struct *verify_wq;
-
-       /* starting blocks for each tree level. 0 is the lowest level. */
-       sector_t hash_level_block[DM_VERITY_MAX_LEVELS];
-};
-
-struct dm_verity_io {
-       struct dm_verity *v;
-
-       /* original values of bio->bi_end_io and bio->bi_private */
-       bio_end_io_t *orig_bi_end_io;
-       void *orig_bi_private;
-
-       sector_t block;
-       unsigned n_blocks;
-
-       struct bvec_iter iter;
-
-       struct work_struct work;
-
-       /*
-        * Three variably-size fields follow this struct:
-        *
-        * u8 hash_desc[v->shash_descsize];
-        * u8 real_digest[v->digest_size];
-        * u8 want_digest[v->digest_size];
-        *
-        * To access them use: io_hash_desc(), io_real_digest() and io_want_digest().
-        */
-};
-
-struct dm_verity_prefetch_work {
-       struct work_struct work;
-       struct dm_verity *v;
-       sector_t block;
-       unsigned n_blocks;
-};
-
-static struct shash_desc *io_hash_desc(struct dm_verity *v, struct dm_verity_io *io)
-{
-       return (struct shash_desc *)(io + 1);
-}
-
-static u8 *io_real_digest(struct dm_verity *v, struct dm_verity_io *io)
-{
-       return (u8 *)(io + 1) + v->shash_descsize;
-}
-
-static u8 *io_want_digest(struct dm_verity *v, struct dm_verity_io *io)
-{
-       return (u8 *)(io + 1) + v->shash_descsize + v->digest_size;
-}
-
-/*
- * Auxiliary structure appended to each dm-bufio buffer. If the value
- * hash_verified is nonzero, hash of the block has been verified.
- *
- * The variable hash_verified is set to 0 when allocating the buffer, then
- * it can be changed to 1 and it is never reset to 0 again.
- *
- * There is no lock around this value, a race condition can at worst cause
- * that multiple processes verify the hash of the same buffer simultaneously
- * and write 1 to hash_verified simultaneously.
- * This condition is harmless, so we don't need locking.
- */
-struct buffer_aux {
-       int hash_verified;
-};
-
-/*
- * Initialize struct buffer_aux for a freshly created buffer.
- */
-static void dm_bufio_alloc_callback(struct dm_buffer *buf)
-{
-       struct buffer_aux *aux = dm_bufio_get_aux_data(buf);
-
-       aux->hash_verified = 0;
-}
-
-/*
- * Translate input sector number to the sector number on the target device.
- */
-static sector_t verity_map_sector(struct dm_verity *v, sector_t bi_sector)
-{
-       return v->data_start + dm_target_offset(v->ti, bi_sector);
-}
-
-/*
- * Return hash position of a specified block at a specified tree level
- * (0 is the lowest level).
- * The lowest "hash_per_block_bits"-bits of the result denote hash position
- * inside a hash block. The remaining bits denote location of the hash block.
- */
-static sector_t verity_position_at_level(struct dm_verity *v, sector_t block,
-                                        int level)
-{
-       return block >> (level * v->hash_per_block_bits);
-}
-
-static void verity_hash_at_level(struct dm_verity *v, sector_t block, int level,
-                                sector_t *hash_block, unsigned *offset)
-{
-       sector_t position = verity_position_at_level(v, block, level);
-       unsigned idx;
-
-       *hash_block = v->hash_level_block[level] + (position >> v->hash_per_block_bits);
-
-       if (!offset)
-               return;
-
-       idx = position & ((1 << v->hash_per_block_bits) - 1);
-       if (!v->version)
-               *offset = idx * v->digest_size;
-       else
-               *offset = idx << (v->hash_dev_block_bits - v->hash_per_block_bits);
-}
-
-/*
- * Handle verification errors.
- */
-static int verity_handle_err(struct dm_verity *v, enum verity_block_type type,
-                            unsigned long long block)
-{
-       char verity_env[DM_VERITY_ENV_LENGTH];
-       char *envp[] = { verity_env, NULL };
-       const char *type_str = "";
-       struct mapped_device *md = dm_table_get_md(v->ti->table);
-
-       /* Corruption should be visible in device status in all modes */
-       v->hash_failed = 1;
-
-       if (v->corrupted_errs >= DM_VERITY_MAX_CORRUPTED_ERRS)
-               goto out;
-
-       v->corrupted_errs++;
-
-       switch (type) {
-       case DM_VERITY_BLOCK_TYPE_DATA:
-               type_str = "data";
-               break;
-       case DM_VERITY_BLOCK_TYPE_METADATA:
-               type_str = "metadata";
-               break;
-       default:
-               BUG();
-       }
-
-       DMERR("%s: %s block %llu is corrupted", v->data_dev->name, type_str,
-               block);
-
-       if (v->corrupted_errs == DM_VERITY_MAX_CORRUPTED_ERRS)
-               DMERR("%s: reached maximum errors", v->data_dev->name);
-
-       snprintf(verity_env, DM_VERITY_ENV_LENGTH, "%s=%d,%llu",
-               DM_VERITY_ENV_VAR_NAME, type, block);
-
-       kobject_uevent_env(&disk_to_dev(dm_disk(md))->kobj, KOBJ_CHANGE, envp);
-
-out:
-       if (v->mode == DM_VERITY_MODE_LOGGING)
-               return 0;
-
-       if (v->mode == DM_VERITY_MODE_RESTART)
-               kernel_restart("dm-verity device corrupted");
-
-       return 1;
-}
-
-/*
- * Verify hash of a metadata block pertaining to the specified data block
- * ("block" argument) at a specified level ("level" argument).
- *
- * On successful return, io_want_digest(v, io) contains the hash value for
- * a lower tree level or for the data block (if we're at the lowest leve).
- *
- * If "skip_unverified" is true, unverified buffer is skipped and 1 is returned.
- * If "skip_unverified" is false, unverified buffer is hashed and verified
- * against current value of io_want_digest(v, io).
- */
-static int verity_verify_level(struct dm_verity_io *io, sector_t block,
-                              int level, bool skip_unverified)
-{
-       struct dm_verity *v = io->v;
-       struct dm_buffer *buf;
-       struct buffer_aux *aux;
-       u8 *data;
-       int r;
-       sector_t hash_block;
-       unsigned offset;
-
-       verity_hash_at_level(v, block, level, &hash_block, &offset);
-
-       data = dm_bufio_read(v->bufio, hash_block, &buf);
-       if (IS_ERR(data))
-               return PTR_ERR(data);
-
-       aux = dm_bufio_get_aux_data(buf);
-
-       if (!aux->hash_verified) {
-               struct shash_desc *desc;
-               u8 *result;
-
-               if (skip_unverified) {
-                       r = 1;
-                       goto release_ret_r;
-               }
-
-               desc = io_hash_desc(v, io);
-               desc->tfm = v->tfm;
-               desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
-               r = crypto_shash_init(desc);
-               if (r < 0) {
-                       DMERR("crypto_shash_init failed: %d", r);
-                       goto release_ret_r;
-               }
-
-               if (likely(v->version >= 1)) {
-                       r = crypto_shash_update(desc, v->salt, v->salt_size);
-                       if (r < 0) {
-                               DMERR("crypto_shash_update failed: %d", r);
-                               goto release_ret_r;
-                       }
-               }
-
-               r = crypto_shash_update(desc, data, 1 << v->hash_dev_block_bits);
-               if (r < 0) {
-                       DMERR("crypto_shash_update failed: %d", r);
-                       goto release_ret_r;
-               }
-
-               if (!v->version) {
-                       r = crypto_shash_update(desc, v->salt, v->salt_size);
-                       if (r < 0) {
-                               DMERR("crypto_shash_update failed: %d", r);
-                               goto release_ret_r;
-                       }
-               }
-
-               result = io_real_digest(v, io);
-               r = crypto_shash_final(desc, result);
-               if (r < 0) {
-                       DMERR("crypto_shash_final failed: %d", r);
-                       goto release_ret_r;
-               }
-               if (unlikely(memcmp(result, io_want_digest(v, io), v->digest_size))) {
-                       if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_METADATA,
-                                             hash_block)) {
-                               r = -EIO;
-                               goto release_ret_r;
-                       }
-               } else
-                       aux->hash_verified = 1;
-       }
-
-       data += offset;
-
-       memcpy(io_want_digest(v, io), data, v->digest_size);
-
-       dm_bufio_release(buf);
-       return 0;
-
-release_ret_r:
-       dm_bufio_release(buf);
-
-       return r;
-}
-
-/*
- * Verify one "dm_verity_io" structure.
- */
-static int verity_verify_io(struct dm_verity_io *io)
-{
-       struct dm_verity *v = io->v;
-       struct bio *bio = dm_bio_from_per_bio_data(io,
-                                                  v->ti->per_bio_data_size);
-       unsigned b;
-       int i;
-
-       for (b = 0; b < io->n_blocks; b++) {
-               struct shash_desc *desc;
-               u8 *result;
-               int r;
-               unsigned todo;
-
-               if (likely(v->levels)) {
-                       /*
-                        * First, we try to get the requested hash for
-                        * the current block. If the hash block itself is
-                        * verified, zero is returned. If it isn't, this
-                        * function returns 0 and we fall back to whole
-                        * chain verification.
-                        */
-                       int r = verity_verify_level(io, io->block + b, 0, true);
-                       if (likely(!r))
-                               goto test_block_hash;
-                       if (r < 0)
-                               return r;
-               }
-
-               memcpy(io_want_digest(v, io), v->root_digest, v->digest_size);
-
-               for (i = v->levels - 1; i >= 0; i--) {
-                       int r = verity_verify_level(io, io->block + b, i, false);
-                       if (unlikely(r))
-                               return r;
-               }
-
-test_block_hash:
-               desc = io_hash_desc(v, io);
-               desc->tfm = v->tfm;
-               desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
-               r = crypto_shash_init(desc);
-               if (r < 0) {
-                       DMERR("crypto_shash_init failed: %d", r);
-                       return r;
-               }
-
-               if (likely(v->version >= 1)) {
-                       r = crypto_shash_update(desc, v->salt, v->salt_size);
-                       if (r < 0) {
-                               DMERR("crypto_shash_update failed: %d", r);
-                               return r;
-                       }
-               }
-               todo = 1 << v->data_dev_block_bits;
-               do {
-                       u8 *page;
-                       unsigned len;
-                       struct bio_vec bv = bio_iter_iovec(bio, io->iter);
-
-                       page = kmap_atomic(bv.bv_page);
-                       len = bv.bv_len;
-                       if (likely(len >= todo))
-                               len = todo;
-                       r = crypto_shash_update(desc, page + bv.bv_offset, len);
-                       kunmap_atomic(page);
-
-                       if (r < 0) {
-                               DMERR("crypto_shash_update failed: %d", r);
-                               return r;
-                       }
-
-                       bio_advance_iter(bio, &io->iter, len);
-                       todo -= len;
-               } while (todo);
-
-               if (!v->version) {
-                       r = crypto_shash_update(desc, v->salt, v->salt_size);
-                       if (r < 0) {
-                               DMERR("crypto_shash_update failed: %d", r);
-                               return r;
-                       }
-               }
-
-               result = io_real_digest(v, io);
-               r = crypto_shash_final(desc, result);
-               if (r < 0) {
-                       DMERR("crypto_shash_final failed: %d", r);
-                       return r;
-               }
-               if (unlikely(memcmp(result, io_want_digest(v, io), v->digest_size))) {
-                       if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_DATA,
-                                             io->block + b))
-                               return -EIO;
-               }
-       }
-
-       return 0;
-}
-
-/*
- * End one "io" structure with a given error.
- */
-static void verity_finish_io(struct dm_verity_io *io, int error)
-{
-       struct dm_verity *v = io->v;
-       struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_bio_data_size);
-
-       bio->bi_end_io = io->orig_bi_end_io;
-       bio->bi_private = io->orig_bi_private;
-       bio->bi_error = error;
-
-       bio_endio(bio);
-}
-
-static void verity_work(struct work_struct *w)
-{
-       struct dm_verity_io *io = container_of(w, struct dm_verity_io, work);
-
-       verity_finish_io(io, verity_verify_io(io));
-}
-
-static void verity_end_io(struct bio *bio)
-{
-       struct dm_verity_io *io = bio->bi_private;
-
-       if (bio->bi_error) {
-               verity_finish_io(io, bio->bi_error);
-               return;
-       }
-
-       INIT_WORK(&io->work, verity_work);
-       queue_work(io->v->verify_wq, &io->work);
-}
-
-/*
- * Prefetch buffers for the specified io.
- * The root buffer is not prefetched, it is assumed that it will be cached
- * all the time.
- */
-static void verity_prefetch_io(struct work_struct *work)
-{
-       struct dm_verity_prefetch_work *pw =
-               container_of(work, struct dm_verity_prefetch_work, work);
-       struct dm_verity *v = pw->v;
-       int i;
-
-       for (i = v->levels - 2; i >= 0; i--) {
-               sector_t hash_block_start;
-               sector_t hash_block_end;
-               verity_hash_at_level(v, pw->block, i, &hash_block_start, NULL);
-               verity_hash_at_level(v, pw->block + pw->n_blocks - 1, i, &hash_block_end, NULL);
-               if (!i) {
-                       unsigned cluster = ACCESS_ONCE(dm_verity_prefetch_cluster);
-
-                       cluster >>= v->data_dev_block_bits;
-                       if (unlikely(!cluster))
-                               goto no_prefetch_cluster;
-
-                       if (unlikely(cluster & (cluster - 1)))
-                               cluster = 1 << __fls(cluster);
-
-                       hash_block_start &= ~(sector_t)(cluster - 1);
-                       hash_block_end |= cluster - 1;
-                       if (unlikely(hash_block_end >= v->hash_blocks))
-                               hash_block_end = v->hash_blocks - 1;
-               }
-no_prefetch_cluster:
-               dm_bufio_prefetch(v->bufio, hash_block_start,
-                                 hash_block_end - hash_block_start + 1);
-       }
-
-       kfree(pw);
-}
-
-static void verity_submit_prefetch(struct dm_verity *v, struct dm_verity_io *io)
-{
-       struct dm_verity_prefetch_work *pw;
-
-       pw = kmalloc(sizeof(struct dm_verity_prefetch_work),
-               GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN);
-
-       if (!pw)
-               return;
-
-       INIT_WORK(&pw->work, verity_prefetch_io);
-       pw->v = v;
-       pw->block = io->block;
-       pw->n_blocks = io->n_blocks;
-       queue_work(v->verify_wq, &pw->work);
-}
-
-/*
- * Bio map function. It allocates dm_verity_io structure and bio vector and
- * fills them. Then it issues prefetches and the I/O.
- */
-static int verity_map(struct dm_target *ti, struct bio *bio)
-{
-       struct dm_verity *v = ti->private;
-       struct dm_verity_io *io;
-
-       bio->bi_bdev = v->data_dev->bdev;
-       bio->bi_iter.bi_sector = verity_map_sector(v, bio->bi_iter.bi_sector);
-
-       if (((unsigned)bio->bi_iter.bi_sector | bio_sectors(bio)) &
-           ((1 << (v->data_dev_block_bits - SECTOR_SHIFT)) - 1)) {
-               DMERR_LIMIT("unaligned io");
-               return -EIO;
-       }
-
-       if (bio_end_sector(bio) >>
-           (v->data_dev_block_bits - SECTOR_SHIFT) > v->data_blocks) {
-               DMERR_LIMIT("io out of range");
-               return -EIO;
-       }
-
-       if (bio_data_dir(bio) == WRITE)
-               return -EIO;
-
-       io = dm_per_bio_data(bio, ti->per_bio_data_size);
-       io->v = v;
-       io->orig_bi_end_io = bio->bi_end_io;
-       io->orig_bi_private = bio->bi_private;
-       io->block = bio->bi_iter.bi_sector >> (v->data_dev_block_bits - SECTOR_SHIFT);
-       io->n_blocks = bio->bi_iter.bi_size >> v->data_dev_block_bits;
-
-       bio->bi_end_io = verity_end_io;
-       bio->bi_private = io;
-       io->iter = bio->bi_iter;
-
-       verity_submit_prefetch(v, io);
-
-       generic_make_request(bio);
-
-       return DM_MAPIO_SUBMITTED;
-}
-
-/*
- * Status: V (valid) or C (corruption found)
- */
-static void verity_status(struct dm_target *ti, status_type_t type,
-                         unsigned status_flags, char *result, unsigned maxlen)
-{
-       struct dm_verity *v = ti->private;
-       unsigned sz = 0;
-       unsigned x;
-
-       switch (type) {
-       case STATUSTYPE_INFO:
-               DMEMIT("%c", v->hash_failed ? 'C' : 'V');
-               break;
-       case STATUSTYPE_TABLE:
-               DMEMIT("%u %s %s %u %u %llu %llu %s ",
-                       v->version,
-                       v->data_dev->name,
-                       v->hash_dev->name,
-                       1 << v->data_dev_block_bits,
-                       1 << v->hash_dev_block_bits,
-                       (unsigned long long)v->data_blocks,
-                       (unsigned long long)v->hash_start,
-                       v->alg_name
-                       );
-               for (x = 0; x < v->digest_size; x++)
-                       DMEMIT("%02x", v->root_digest[x]);
-               DMEMIT(" ");
-               if (!v->salt_size)
-                       DMEMIT("-");
-               else
-                       for (x = 0; x < v->salt_size; x++)
-                               DMEMIT("%02x", v->salt[x]);
-               if (v->mode != DM_VERITY_MODE_EIO) {
-                       DMEMIT(" 1 ");
-                       switch (v->mode) {
-                       case DM_VERITY_MODE_LOGGING:
-                               DMEMIT(DM_VERITY_OPT_LOGGING);
-                               break;
-                       case DM_VERITY_MODE_RESTART:
-                               DMEMIT(DM_VERITY_OPT_RESTART);
-                               break;
-                       default:
-                               BUG();
-                       }
-               }
-               break;
-       }
-}
-
-static int verity_prepare_ioctl(struct dm_target *ti,
-               struct block_device **bdev, fmode_t *mode)
-{
-       struct dm_verity *v = ti->private;
-
-       *bdev = v->data_dev->bdev;
-
-       if (v->data_start ||
-           ti->len != i_size_read(v->data_dev->bdev->bd_inode) >> SECTOR_SHIFT)
-               return 1;
-       return 0;
-}
-
-static int verity_iterate_devices(struct dm_target *ti,
-                                 iterate_devices_callout_fn fn, void *data)
-{
-       struct dm_verity *v = ti->private;
-
-       return fn(ti, v->data_dev, v->data_start, ti->len, data);
-}
-
-static void verity_io_hints(struct dm_target *ti, struct queue_limits *limits)
-{
-       struct dm_verity *v = ti->private;
-
-       if (limits->logical_block_size < 1 << v->data_dev_block_bits)
-               limits->logical_block_size = 1 << v->data_dev_block_bits;
-
-       if (limits->physical_block_size < 1 << v->data_dev_block_bits)
-               limits->physical_block_size = 1 << v->data_dev_block_bits;
-
-       blk_limits_io_min(limits, limits->logical_block_size);
-}
-
-static void verity_dtr(struct dm_target *ti)
-{
-       struct dm_verity *v = ti->private;
-
-       if (v->verify_wq)
-               destroy_workqueue(v->verify_wq);
-
-       if (v->bufio)
-               dm_bufio_client_destroy(v->bufio);
-
-       kfree(v->salt);
-       kfree(v->root_digest);
-
-       if (v->tfm)
-               crypto_free_shash(v->tfm);
-
-       kfree(v->alg_name);
-
-       if (v->hash_dev)
-               dm_put_device(ti, v->hash_dev);
-
-       if (v->data_dev)
-               dm_put_device(ti, v->data_dev);
-
-       kfree(v);
-}
-
-/*
- * Target parameters:
- *     <version>       The current format is version 1.
- *                     Vsn 0 is compatible with original Chromium OS releases.
- *     <data device>
- *     <hash device>
- *     <data block size>
- *     <hash block size>
- *     <the number of data blocks>
- *     <hash start block>
- *     <algorithm>
- *     <digest>
- *     <salt>          Hex string or "-" if no salt.
- */
-static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
-{
-       struct dm_verity *v;
-       struct dm_arg_set as;
-       const char *opt_string;
-       unsigned int num, opt_params;
-       unsigned long long num_ll;
-       int r;
-       int i;
-       sector_t hash_position;
-       char dummy;
-
-       static struct dm_arg _args[] = {
-               {0, 1, "Invalid number of feature args"},
-       };
-
-       v = kzalloc(sizeof(struct dm_verity), GFP_KERNEL);
-       if (!v) {
-               ti->error = "Cannot allocate verity structure";
-               return -ENOMEM;
-       }
-       ti->private = v;
-       v->ti = ti;
-
-       if ((dm_table_get_mode(ti->table) & ~FMODE_READ)) {
-               ti->error = "Device must be readonly";
-               r = -EINVAL;
-               goto bad;
-       }
-
-       if (argc < 10) {
-               ti->error = "Not enough arguments";
-               r = -EINVAL;
-               goto bad;
-       }
-
-       if (sscanf(argv[0], "%u%c", &num, &dummy) != 1 ||
-           num > 1) {
-               ti->error = "Invalid version";
-               r = -EINVAL;
-               goto bad;
-       }
-       v->version = num;
-
-       r = dm_get_device(ti, argv[1], FMODE_READ, &v->data_dev);
-       if (r) {
-               ti->error = "Data device lookup failed";
-               goto bad;
-       }
-
-       r = dm_get_device(ti, argv[2], FMODE_READ, &v->hash_dev);
-       if (r) {
-               ti->error = "Data device lookup failed";
-               goto bad;
-       }
-
-       if (sscanf(argv[3], "%u%c", &num, &dummy) != 1 ||
-           !num || (num & (num - 1)) ||
-           num < bdev_logical_block_size(v->data_dev->bdev) ||
-           num > PAGE_SIZE) {
-               ti->error = "Invalid data device block size";
-               r = -EINVAL;
-               goto bad;
-       }
-       v->data_dev_block_bits = __ffs(num);
-
-       if (sscanf(argv[4], "%u%c", &num, &dummy) != 1 ||
-           !num || (num & (num - 1)) ||
-           num < bdev_logical_block_size(v->hash_dev->bdev) ||
-           num > INT_MAX) {
-               ti->error = "Invalid hash device block size";
-               r = -EINVAL;
-               goto bad;
-       }
-       v->hash_dev_block_bits = __ffs(num);
-
-       if (sscanf(argv[5], "%llu%c", &num_ll, &dummy) != 1 ||
-           (sector_t)(num_ll << (v->data_dev_block_bits - SECTOR_SHIFT))
-           >> (v->data_dev_block_bits - SECTOR_SHIFT) != num_ll) {
-               ti->error = "Invalid data blocks";
-               r = -EINVAL;
-               goto bad;
-       }
-       v->data_blocks = num_ll;
-
-       if (ti->len > (v->data_blocks << (v->data_dev_block_bits - SECTOR_SHIFT))) {
-               ti->error = "Data device is too small";
-               r = -EINVAL;
-               goto bad;
-       }
-
-       if (sscanf(argv[6], "%llu%c", &num_ll, &dummy) != 1 ||
-           (sector_t)(num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT))
-           >> (v->hash_dev_block_bits - SECTOR_SHIFT) != num_ll) {
-               ti->error = "Invalid hash start";
-               r = -EINVAL;
-               goto bad;
-       }
-       v->hash_start = num_ll;
-
-       v->alg_name = kstrdup(argv[7], GFP_KERNEL);
-       if (!v->alg_name) {
-               ti->error = "Cannot allocate algorithm name";
-               r = -ENOMEM;
-               goto bad;
-       }
-
-       v->tfm = crypto_alloc_shash(v->alg_name, 0, 0);
-       if (IS_ERR(v->tfm)) {
-               ti->error = "Cannot initialize hash function";
-               r = PTR_ERR(v->tfm);
-               v->tfm = NULL;
-               goto bad;
-       }
-       v->digest_size = crypto_shash_digestsize(v->tfm);
-       if ((1 << v->hash_dev_block_bits) < v->digest_size * 2) {
-               ti->error = "Digest size too big";
-               r = -EINVAL;
-               goto bad;
-       }
-       v->shash_descsize =
-               sizeof(struct shash_desc) + crypto_shash_descsize(v->tfm);
-
-       v->root_digest = kmalloc(v->digest_size, GFP_KERNEL);
-       if (!v->root_digest) {
-               ti->error = "Cannot allocate root digest";
-               r = -ENOMEM;
-               goto bad;
-       }
-       if (strlen(argv[8]) != v->digest_size * 2 ||
-           hex2bin(v->root_digest, argv[8], v->digest_size)) {
-               ti->error = "Invalid root digest";
-               r = -EINVAL;
-               goto bad;
-       }
-
-       if (strcmp(argv[9], "-")) {
-               v->salt_size = strlen(argv[9]) / 2;
-               v->salt = kmalloc(v->salt_size, GFP_KERNEL);
-               if (!v->salt) {
-                       ti->error = "Cannot allocate salt";
-                       r = -ENOMEM;
-                       goto bad;
-               }
-               if (strlen(argv[9]) != v->salt_size * 2 ||
-                   hex2bin(v->salt, argv[9], v->salt_size)) {
-                       ti->error = "Invalid salt";
-                       r = -EINVAL;
-                       goto bad;
-               }
-       }
-
-       argv += 10;
-       argc -= 10;
-
-       /* Optional parameters */
-       if (argc) {
-               as.argc = argc;
-               as.argv = argv;
-
-               r = dm_read_arg_group(_args, &as, &opt_params, &ti->error);
-               if (r)
-                       goto bad;
-
-               while (opt_params) {
-                       opt_params--;
-                       opt_string = dm_shift_arg(&as);
-                       if (!opt_string) {
-                               ti->error = "Not enough feature arguments";
-                               r = -EINVAL;
-                               goto bad;
-                       }
-
-                       if (!strcasecmp(opt_string, DM_VERITY_OPT_LOGGING))
-                               v->mode = DM_VERITY_MODE_LOGGING;
-                       else if (!strcasecmp(opt_string, DM_VERITY_OPT_RESTART))
-                               v->mode = DM_VERITY_MODE_RESTART;
-                       else {
-                               ti->error = "Invalid feature arguments";
-                               r = -EINVAL;
-                               goto bad;
-                       }
-               }
-       }
-
-       v->hash_per_block_bits =
-               __fls((1 << v->hash_dev_block_bits) / v->digest_size);
-
-       v->levels = 0;
-       if (v->data_blocks)
-               while (v->hash_per_block_bits * v->levels < 64 &&
-                      (unsigned long long)(v->data_blocks - 1) >>
-                      (v->hash_per_block_bits * v->levels))
-                       v->levels++;
-
-       if (v->levels > DM_VERITY_MAX_LEVELS) {
-               ti->error = "Too many tree levels";
-               r = -E2BIG;
-               goto bad;
-       }
-
-       hash_position = v->hash_start;
-       for (i = v->levels - 1; i >= 0; i--) {
-               sector_t s;
-               v->hash_level_block[i] = hash_position;
-               s = (v->data_blocks + ((sector_t)1 << ((i + 1) * v->hash_per_block_bits)) - 1)
-                                       >> ((i + 1) * v->hash_per_block_bits);
-               if (hash_position + s < hash_position) {
-                       ti->error = "Hash device offset overflow";
-                       r = -E2BIG;
-                       goto bad;
-               }
-               hash_position += s;
-       }
-       v->hash_blocks = hash_position;
-
-       v->bufio = dm_bufio_client_create(v->hash_dev->bdev,
-               1 << v->hash_dev_block_bits, 1, sizeof(struct buffer_aux),
-               dm_bufio_alloc_callback, NULL);
-       if (IS_ERR(v->bufio)) {
-               ti->error = "Cannot initialize dm-bufio";
-               r = PTR_ERR(v->bufio);
-               v->bufio = NULL;
-               goto bad;
-       }
-
-       if (dm_bufio_get_device_size(v->bufio) < v->hash_blocks) {
-               ti->error = "Hash device is too small";
-               r = -E2BIG;
-               goto bad;
-       }
-
-       ti->per_bio_data_size = roundup(sizeof(struct dm_verity_io) + v->shash_descsize + v->digest_size * 2, __alignof__(struct dm_verity_io));
-
-       /* WQ_UNBOUND greatly improves performance when running on ramdisk */
-       v->verify_wq = alloc_workqueue("kverityd", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND, num_online_cpus());
-       if (!v->verify_wq) {
-               ti->error = "Cannot allocate workqueue";
-               r = -ENOMEM;
-               goto bad;
-       }
-
-       return 0;
-
-bad:
-       verity_dtr(ti);
-
-       return r;
-}
-
-static struct target_type verity_target = {
-       .name           = "verity",
-       .version        = {1, 2, 0},
-       .module         = THIS_MODULE,
-       .ctr            = verity_ctr,
-       .dtr            = verity_dtr,
-       .map            = verity_map,
-       .status         = verity_status,
-       .prepare_ioctl  = verity_prepare_ioctl,
-       .iterate_devices = verity_iterate_devices,
-       .io_hints       = verity_io_hints,
-};
-
-static int __init dm_verity_init(void)
-{
-       int r;
-
-       r = dm_register_target(&verity_target);
-       if (r < 0)
-               DMERR("register failed %d", r);
-
-       return r;
-}
-
-static void __exit dm_verity_exit(void)
-{
-       dm_unregister_target(&verity_target);
-}
-
-module_init(dm_verity_init);
-module_exit(dm_verity_exit);
-
-MODULE_AUTHOR("Mikulas Patocka <mpatocka@redhat.com>");
-MODULE_AUTHOR("Mandeep Baines <msb@chromium.org>");
-MODULE_AUTHOR("Will Drewry <wad@chromium.org>");
-MODULE_DESCRIPTION(DM_NAME " target for transparent disk integrity checking");
-MODULE_LICENSE("GPL");
diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h
new file mode 100644 (file)
index 0000000..fb419f4
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc.
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Author: Mikulas Patocka <mpatocka@redhat.com>
+ *
+ * Based on Chromium dm-verity driver (C) 2011 The Chromium OS Authors
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef DM_VERITY_H
+#define DM_VERITY_H
+
+#include "dm-bufio.h"
+#include <linux/device-mapper.h>
+#include <crypto/hash.h>
+
+#define DM_VERITY_MAX_LEVELS           63
+
+enum verity_mode {
+       DM_VERITY_MODE_EIO,
+       DM_VERITY_MODE_LOGGING,
+       DM_VERITY_MODE_RESTART
+};
+
+enum verity_block_type {
+       DM_VERITY_BLOCK_TYPE_DATA,
+       DM_VERITY_BLOCK_TYPE_METADATA
+};
+
+struct dm_verity_fec;
+
+struct dm_verity {
+       struct dm_dev *data_dev;
+       struct dm_dev *hash_dev;
+       struct dm_target *ti;
+       struct dm_bufio_client *bufio;
+       char *alg_name;
+       struct crypto_shash *tfm;
+       u8 *root_digest;        /* digest of the root block */
+       u8 *salt;               /* salt: its size is salt_size */
+       u8 *zero_digest;        /* digest for a zero block */
+       unsigned salt_size;
+       sector_t data_start;    /* data offset in 512-byte sectors */
+       sector_t hash_start;    /* hash start in blocks */
+       sector_t data_blocks;   /* the number of data blocks */
+       sector_t hash_blocks;   /* the number of hash blocks */
+       unsigned char data_dev_block_bits;      /* log2(data blocksize) */
+       unsigned char hash_dev_block_bits;      /* log2(hash blocksize) */
+       unsigned char hash_per_block_bits;      /* log2(hashes in hash block) */
+       unsigned char levels;   /* the number of tree levels */
+       unsigned char version;
+       unsigned digest_size;   /* digest size for the current hash algorithm */
+       unsigned shash_descsize;/* the size of temporary space for crypto */
+       int hash_failed;        /* set to 1 if hash of any block failed */
+       enum verity_mode mode;  /* mode for handling verification errors */
+       unsigned corrupted_errs;/* Number of errors for corrupted blocks */
+
+       struct workqueue_struct *verify_wq;
+
+       /* starting blocks for each tree level. 0 is the lowest level. */
+       sector_t hash_level_block[DM_VERITY_MAX_LEVELS];
+
+       struct dm_verity_fec *fec;      /* forward error correction */
+};
+
+struct dm_verity_io {
+       struct dm_verity *v;
+
+       /* original value of bio->bi_end_io */
+       bio_end_io_t *orig_bi_end_io;
+
+       sector_t block;
+       unsigned n_blocks;
+
+       struct bvec_iter iter;
+
+       struct work_struct work;
+
+       /*
+        * Three variably-size fields follow this struct:
+        *
+        * u8 hash_desc[v->shash_descsize];
+        * u8 real_digest[v->digest_size];
+        * u8 want_digest[v->digest_size];
+        *
+        * To access them use: verity_io_hash_desc(), verity_io_real_digest()
+        * and verity_io_want_digest().
+        */
+};
+
+static inline struct shash_desc *verity_io_hash_desc(struct dm_verity *v,
+                                                    struct dm_verity_io *io)
+{
+       return (struct shash_desc *)(io + 1);
+}
+
+static inline u8 *verity_io_real_digest(struct dm_verity *v,
+                                       struct dm_verity_io *io)
+{
+       return (u8 *)(io + 1) + v->shash_descsize;
+}
+
+static inline u8 *verity_io_want_digest(struct dm_verity *v,
+                                       struct dm_verity_io *io)
+{
+       return (u8 *)(io + 1) + v->shash_descsize + v->digest_size;
+}
+
+static inline u8 *verity_io_digest_end(struct dm_verity *v,
+                                      struct dm_verity_io *io)
+{
+       return verity_io_want_digest(v, io) + v->digest_size;
+}
+
+extern int verity_for_bv_block(struct dm_verity *v, struct dm_verity_io *io,
+                              struct bvec_iter *iter,
+                              int (*process)(struct dm_verity *v,
+                                             struct dm_verity_io *io,
+                                             u8 *data, size_t len));
+
+extern int verity_hash(struct dm_verity *v, struct shash_desc *desc,
+                      const u8 *data, size_t len, u8 *digest);
+
+extern int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,
+                                sector_t block, u8 *digest, bool *is_zero);
+
+#endif /* DM_VERITY_H */
index 78c74bb71ba42f11ff5035a5a593ed5732df9791..a53cbc928af1927c1c10d8f79abce0c64a939ed7 100644 (file)
@@ -7,12 +7,3 @@ config DM_PERSISTENT_DATA
         Library providing immutable on-disk data structure support for
         device-mapper targets such as the thin provisioning target.
 
-config DM_DEBUG_BLOCK_STACK_TRACING
-       bool "Keep stack trace of persistent data block lock holders"
-       depends on STACKTRACE_SUPPORT && DM_PERSISTENT_DATA
-       select STACKTRACE
-       ---help---
-        Enable this for messages that may help debug problems with the
-        block manager locking used by thin provisioning and caching.
-
-        If unsure, say N.
index f2393ba838eb57cfa977228da492814d7dda42af..1e33dd51c21ff766418a30c8f44cff6846a92f55 100644 (file)
@@ -97,10 +97,6 @@ static void __del_holder(struct block_lock *lock, struct task_struct *task)
 static int __check_holder(struct block_lock *lock)
 {
        unsigned i;
-#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING
-       static struct stack_trace t;
-       static stack_entries entries;
-#endif
 
        for (i = 0; i < MAX_HOLDERS; i++) {
                if (lock->holders[i] == current) {
@@ -110,12 +106,7 @@ static int __check_holder(struct block_lock *lock)
                        print_stack_trace(lock->traces + i, 4);
 
                        DMERR("subsequent acquisition attempted here:");
-                       t.nr_entries = 0;
-                       t.max_entries = MAX_STACK;
-                       t.entries = entries;
-                       t.skip = 3;
-                       save_stack_trace(&t);
-                       print_stack_trace(&t, 4);
+                       dump_stack();
 #endif
                        return -EINVAL;
                }
index b1ced58eb5e1475b440a15de0e26811fb90b8159..ea3d3b656fd0a1f8f55a0bcb0285bf4a94f6c38d 100644 (file)
@@ -754,12 +754,19 @@ static int btree_insert_raw(struct shadow_spine *s, dm_block_t root,
        return 0;
 }
 
+static bool need_insert(struct btree_node *node, uint64_t *keys,
+                       unsigned level, unsigned index)
+{
+        return ((index >= le32_to_cpu(node->header.nr_entries)) ||
+               (le64_to_cpu(node->keys[index]) != keys[level]));
+}
+
 static int insert(struct dm_btree_info *info, dm_block_t root,
                  uint64_t *keys, void *value, dm_block_t *new_root,
                  int *inserted)
                  __dm_written_to_disk(value)
 {
-       int r, need_insert;
+       int r;
        unsigned level, index = -1, last_level = info->levels - 1;
        dm_block_t block = root;
        struct shadow_spine spine;
@@ -775,10 +782,8 @@ static int insert(struct dm_btree_info *info, dm_block_t root,
                        goto bad;
 
                n = dm_block_data(shadow_current(&spine));
-               need_insert = ((index >= le32_to_cpu(n->header.nr_entries)) ||
-                              (le64_to_cpu(n->keys[index]) != keys[level]));
 
-               if (need_insert) {
+               if (need_insert(n, keys, level, index)) {
                        dm_block_t new_tree;
                        __le64 new_le;
 
@@ -805,10 +810,8 @@ static int insert(struct dm_btree_info *info, dm_block_t root,
                goto bad;
 
        n = dm_block_data(shadow_current(&spine));
-       need_insert = ((index >= le32_to_cpu(n->header.nr_entries)) ||
-                      (le64_to_cpu(n->keys[index]) != keys[level]));
 
-       if (need_insert) {
+       if (need_insert(n, keys, level, index)) {
                if (inserted)
                        *inserted = 1;
 
index fca6dbcf9a4727f85d61f7d161094870f5db24d5..7e44005595c1e77d1982e7e89b1259ddea97bf9a 100644 (file)
@@ -152,12 +152,9 @@ static int brb_peek(struct bop_ring_buffer *brb, struct block_op *result)
 
 static int brb_pop(struct bop_ring_buffer *brb)
 {
-       struct block_op *bop;
-
        if (brb_empty(brb))
                return -ENODATA;
 
-       bop = brb->bops + brb->begin;
        brb->begin = brb_next(brb, brb->begin);
 
        return 0;
index 3ef3d6c6bbf81b1efd39df2c703545450f8a5176..9264ea73b3be5b0eb8c40a4703eaef6685b696b5 100644 (file)
@@ -9,7 +9,7 @@ menuconfig MEDIA_SUPPORT
          If you want to use Webcams, Video grabber devices and/or TV devices
          enable this option and other options below.
          Additional info and docs are available on the web at
-         <http://linuxtv.org>
+         <https://linuxtv.org>
 
 if MEDIA_SUPPORT
 
@@ -51,7 +51,7 @@ config MEDIA_RADIO_SUPPORT
          Enable AM/FM radio support.
 
          Additional info and docs are available on the web at
-         <http://linuxtv.org>
+         <https://linuxtv.org>
 
          Say Y when you have a board with radio support.
 
index c07b9db51b05293d3ac039733286e5f36924ce0f..5e4afa0131e6847df1268b10ffbdafeed551c025 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/videodev2.h>
 
 #include <media/tuner.h>
-#include <media/cx2341x.h>
+#include <media/drv-intf/cx2341x.h>
 #include <media/v4l2-common.h>
 
 MODULE_DESCRIPTION("cx23415/6/8 driver");
index 1ff9f5323bc3426996e8810b5720b18f30e45b3d..9f7c5b0a6b45787f127934e21f498efbe3d599f8 100644 (file)
@@ -20,7 +20,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <media/saa7146.h>
+#include <media/drv-intf/saa7146.h>
 #include <linux/module.h>
 
 static int saa7146_num;
index df1e8c975cd82d97b6b5d9bb4edf0e2db7f006bd..930d2c94d5d30458b7ef40ad72a5155454613516 100644 (file)
@@ -1,6 +1,6 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <media/saa7146_vv.h>
+#include <media/drv-intf/saa7146_vv.h>
 #include <linux/module.h>
 
 /****************************************************************************/
index 3dc6a838ca6f745ba2b416029ed05ac2a08381c9..6ebcbc6450f57c1112efde87b958e220579748a5 100644 (file)
@@ -2,7 +2,7 @@
 
 #include <linux/kernel.h>
 #include <linux/export.h>
-#include <media/saa7146_vv.h>
+#include <media/drv-intf/saa7146_vv.h>
 
 static void calculate_output_format_register(struct saa7146_dev* saa, u32 palette, u32* clip_format)
 {
index 22027198129d375ed063b0d3bbeb7073b5130d32..239a2db35068bfd4e5f3d6b2cf7e175b5703e787 100644 (file)
@@ -1,6 +1,6 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <media/saa7146_vv.h>
+#include <media/drv-intf/saa7146_vv.h>
 
 static u32 saa7146_i2c_func(struct i2c_adapter *adapter)
 {
index 2da99575877802157f0e20358419cee638f1af00..49237518d65fb27dca2146ea5455b043b057bfbb 100644 (file)
@@ -1,4 +1,4 @@
-#include <media/saa7146_vv.h>
+#include <media/drv-intf/saa7146_vv.h>
 
 static int vbi_pixel_to_capture = 720 * 2;
 
index 30779498c173fa846af6769294c94c44c7058e0d..d5837be3e8cfe846cf8c6a24bb3a7acb8f777ad7 100644 (file)
@@ -1,6 +1,6 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <media/saa7146_vv.h>
+#include <media/drv-intf/saa7146_vv.h>
 #include <media/v4l2-event.h>
 #include <media/v4l2-ctrls.h>
 #include <linux/module.h>
index fc8b7925c53252c28b3ba46e4fca8bf961873c43..d9abd96ef48bf5e0a3f9bb9ccdf7f407669ddfd1 100644 (file)
@@ -30,8 +30,6 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include <linux/input.h>
 #include <media/rc-core.h>
 
-#define IR_DEFAULT_TIMEOUT             100
-
 struct smscore_device_t;
 
 struct ir_t {
index ccc1f43cb9a9b11767c0eee35aa323f908fee370..6d3b95b8939db2bf07eab47ea1aef197d2d86379 100644 (file)
 #include <linux/time.h>
 #include <linux/dvb/dmx.h>
 
+/**
+ * DOC: Digital TV Demux
+ *
+ * The Kernel Digital TV Demux kABI defines a driver-internal interface for
+ * registering low-level, hardware specific driver to a hardware independent
+ * demux layer. It is only of interest for Digital TV device driver writers.
+ * The header file for this kABI is named demux.h and located in
+ * drivers/media/dvb-core.
+ *
+ * The demux kABI should be implemented for each demux in the system. It is
+ * used to select the TS source of a demux and to manage the demux resources.
+ * When the demux client allocates a resource via the demux kABI, it receives
+ * a pointer to the kABI of that resource.
+ *
+ * Each demux receives its TS input from a DVB front-end or from memory, as
+ * set via this demux kABI. In a system with more than one front-end, the kABI
+ * can be used to select one of the DVB front-ends as a TS source for a demux,
+ * unless this is fixed in the HW platform.
+ *
+ * The demux kABI only controls front-ends regarding to their connections with
+ * demuxes; the kABI used to set the other front-end parameters, such as
+ * tuning, are devined via the Digital TV Frontend kABI.
+ *
+ * The functions that implement the abstract interface demux should be defined
+ * static or module private and registered to the Demux core for external
+ * access. It is not necessary to implement every function in the struct
+ * &dmx_demux. For example, a demux interface might support Section filtering,
+ * but not PES filtering. The kABI client is expected to check the value of any
+ * function pointer before calling the function: the value of NULL means
+ * that the function is not available.
+ *
+ * Whenever the functions of the demux API modify shared data, the
+ * possibilities of lost update and race condition problems should be
+ * addressed, e.g. by protecting parts of code with mutexes.
+ *
+ * Note that functions called from a bottom half context must not sleep.
+ * Even a simple memory allocation without using %GFP_ATOMIC can result in a
+ * kernel thread being put to sleep if swapping is needed. For example, the
+ * Linux Kernel calls the functions of a network device interface from a
+ * bottom half context. Thus, if a demux kABI function is called from network
+ * device code, the function must not sleep.
+ */
+
 /*
  * Common definitions
  */
@@ -187,8 +230,28 @@ struct dmx_section_feed {
        int (*stop_filtering)(struct dmx_section_feed *feed);
 };
 
-/*
- * Callback functions
+/**
+ * DOC: Demux Callback
+ *
+ * This kernel-space API comprises the callback functions that deliver filtered
+ * data to the demux client. Unlike the other DVB kABIs, these functions are
+ * provided by the client and called from the demux code.
+ *
+ * The function pointers of this abstract interface are not packed into a
+ * structure as in the other demux APIs, because the callback functions are
+ * registered and used independent of each other. As an example, it is possible
+ * for the API client to provide several callback functions for receiving TS
+ * packets and no callbacks for PES packets or sections.
+ *
+ * The functions that implement the callback API need not be re-entrant: when
+ * a demux driver calls one of these functions, the driver is not allowed to
+ * call the function again before the original call returns. If a callback is
+ * triggered by a hardware interrupt, it is recommended to use the Linux
+ * bottom half mechanism or start a tasklet instead of making the callback
+ * function call directly from a hardware interrupt.
+ *
+ * This mechanism is implemented by dmx_ts_cb() and dmx_section_cb()
+ * callbacks.
  */
 
 /**
index 0a46580b5376de993458ca17d8898dfcbfd03521..1c1c298d2289b9bba1ab8fdd1629c660dedfba92 100644 (file)
 #define USB_PID_PCTV_2002E_SE                           0x025d
 #define USB_PID_SVEON_STV27                             0xd3af
 #define USB_PID_TURBOX_DTT_2000                         0xd3a4
+#define USB_PID_WINTV_SOLOHD                            0x0264
 #endif
index c38ef1a72b4aee35e0fbb2491cc89a07565065e9..b64f33776b740259e54ecaea17f47f1331d1e19d 100644 (file)
@@ -891,21 +891,21 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
 }
 
 /*
- * Sleep until gettimeofday() > waketime + add_usec
- * This needs to be as precise as possible, but as the delay is
- * usually between 2ms and 32ms, it is done using a scheduled msleep
- * followed by usleep (normally a busy-wait loop) for the remainder
+ * Sleep for the amount of time given by add_usec parameter
+ *
+ * This needs to be as precise as possible, as it affects the detection of
+ * the dish tone command at the satellite subsystem. The precision is improved
+ * by using a scheduled msleep followed by udelay for the remainder.
  */
 void dvb_frontend_sleep_until(ktime_t *waketime, u32 add_usec)
 {
-       s32 delta, newdelta;
+       s32 delta;
 
-       ktime_add_us(*waketime, add_usec);
+       *waketime = ktime_add_us(*waketime, add_usec);
        delta = ktime_us_delta(ktime_get_real(), *waketime);
        if (delta > 2500) {
                msleep((delta - 1500) / 1000);
-               newdelta = ktime_us_delta(ktime_get_real(), *waketime);
-               delta = (newdelta > delta) ? 0 : newdelta;
+               delta = ktime_us_delta(ktime_get_real(), *waketime);
        }
        if (delta > 0)
                udelay(delta);
@@ -2313,9 +2313,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
                dev_dbg(fe->dvb->device, "%s: current delivery system on cache: %d, V3 type: %d\n",
                                 __func__, c->delivery_system, fe->ops.info.type);
 
-               /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
-                * do it, it is done for it. */
-               info->caps |= FE_CAN_INVERSION_AUTO;
+               /* Set CAN_INVERSION_AUTO bit on in other than oneshot mode */
+               if (!(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT))
+                       info->caps |= FE_CAN_INVERSION_AUTO;
                err = 0;
                break;
        }
@@ -2710,6 +2710,11 @@ int dvb_frontend_resume(struct dvb_frontend *fe)
        else if (fe->ops.tuner_ops.init)
                ret = fe->ops.tuner_ops.init(fe);
 
+       if (fe->ops.set_tone && fepriv->tone != -1)
+               fe->ops.set_tone(fe, fepriv->tone);
+       if (fe->ops.set_voltage && fepriv->voltage != -1)
+               fe->ops.set_voltage(fe, fepriv->voltage);
+
        fe->exit = DVB_FE_NO_EXIT;
        fepriv->state = FESTATE_RETUNE;
        dvb_frontend_wakeup(fe);
index 97661b2f247ad9352862d0385d1964981db39a23..458bcce20e3847e106b7af3ba2592764cef5f9bf 100644 (file)
 
 #include "dvbdev.h"
 
+/**
+ * DOC: Digital TV Frontend
+ *
+ * The Digital TV Frontend kABI defines a driver-internal interface for
+ * registering low-level, hardware specific driver to a hardware independent
+ * frontend layer. It is only of interest for Digital TV device driver writers.
+ * The header file for this API is named dvb_frontend.h and located in
+ * drivers/media/dvb-core.
+ *
+ * Before using the Digital TV frontend core, the bridge driver should attach
+ * the frontend demod, tuner and SEC devices and call dvb_register_frontend(),
+ * in order to register the new frontend at the subsystem. At device
+ * detach/removal, the bridge driver should call dvb_unregister_frontend() to
+ * remove the frontend from the core and then dvb_frontend_detach() to free the
+ * memory allocated by the frontend drivers.
+ *
+ * The drivers should also call dvb_frontend_suspend() as part of their
+ * handler for the &device_driver.suspend(), and dvb_frontend_resume() as
+ * part of their handler for &device_driver.resume().
+ *
+ * A few other optional functions are provided to handle some special cases.
+ */
+
 /*
  * Maximum number of Delivery systems per frontend. It
  * should be smaller or equal to 32
@@ -112,16 +135,6 @@ struct analog_parameters {
        u64 std;
 };
 
-enum tuner_param {
-       DVBFE_TUNER_FREQUENCY           = (1 <<  0),
-       DVBFE_TUNER_TUNERSTEP           = (1 <<  1),
-       DVBFE_TUNER_IFFREQ              = (1 <<  2),
-       DVBFE_TUNER_BANDWIDTH           = (1 <<  3),
-       DVBFE_TUNER_REFCLOCK            = (1 <<  4),
-       DVBFE_TUNER_IQSENSE             = (1 <<  5),
-       DVBFE_TUNER_DUMMY               = (1 << 31)
-};
-
 /**
  * enum dvbfe_algo - defines the algorithm used to tune into a channel
  *
@@ -152,15 +165,6 @@ enum dvbfe_algo {
        DVBFE_ALGO_RECOVERY             = (1 << 31)
 };
 
-struct tuner_state {
-       u32 frequency;
-       u32 tunerstep;
-       u32 ifreq;
-       u32 bandwidth;
-       u32 iqsense;
-       u32 refclock;
-};
-
 /**
  * enum dvbfe_search - search callback possible return status
  *
@@ -209,12 +213,12 @@ enum dvbfe_search {
  *                     are stored at @dvb_frontend.dtv_property_cache;. The
  *                     tuner demod can change the parameters to reflect the
  *                     changes needed for the channel to be tuned, and
- *                     update statistics.
+ *                     update statistics. This is the recommended way to set
+ *                     the tuner parameters and should be used on newer
+ *                     drivers.
  * @set_analog_params: callback function used to tune into an analog TV
  *                     channel on hybrid tuners. It passes @analog_parameters;
  *                     to the driver.
- * @calc_regs:         callback function used to pass register data settings
- *                     for simple tuners.
  * @set_config:                callback function used to send some tuner-specific
  *                     parameters.
  * @get_frequency:     get the actual tuned frequency
@@ -227,16 +231,10 @@ enum dvbfe_search {
  *                     via DVBv5 API (@dvb_frontend.dtv_property_cache;).
  * @get_afc:           Used only by analog TV core. Reports the frequency
  *                     drift due to AFC.
- * @set_frequency:     Set a new frequency. Please notice that using
- *                     set_params is preferred.
- * @set_bandwidth:     Set a new frequency. Please notice that using
- *                     set_params is preferred.
- * @set_state:         callback function used on some legacy drivers that
- *                     don't implement set_params in order to set properties.
- *                     Shouldn't be used on new drivers.
- * @get_state:         callback function used to get properties by some
- *                     legacy drivers that don't implement set_params.
- *                     Shouldn't be used on new drivers.
+ * @calc_regs:         callback function used to pass register data settings
+ *                     for simple tuners.  Shouldn't be used on newer drivers.
+ * @set_frequency:     Set a new frequency. Shouldn't be used on newer drivers.
+ * @set_bandwidth:     Set a new frequency. Shouldn't be used on newer drivers.
  *
  * NOTE: frequencies used on get_frequency and set_frequency are in Hz for
  * terrestrial/cable or kHz for satellite.
@@ -252,14 +250,10 @@ struct dvb_tuner_ops {
        int (*suspend)(struct dvb_frontend *fe);
        int (*resume)(struct dvb_frontend *fe);
 
-       /** This is for simple PLLs - set all parameters in one go. */
+       /* This is the recomended way to set the tuner */
        int (*set_params)(struct dvb_frontend *fe);
        int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p);
 
-       /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
-       int (*calc_regs)(struct dvb_frontend *fe, u8 *buf, int buf_len);
-
-       /** This is to allow setting tuner-specific configs */
        int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
 
        int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
@@ -272,17 +266,23 @@ struct dvb_tuner_ops {
        int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
        int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
 
-       /** These are provided separately from set_params in order to facilitate silicon
-        * tuners which require sophisticated tuning loops, controlling each parameter separately. */
-       int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
-       int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
+       /*
+        * This is support for demods like the mt352 - fills out the supplied
+        * buffer with what to write.
+        *
+        * Don't use on newer drivers.
+        */
+       int (*calc_regs)(struct dvb_frontend *fe, u8 *buf, int buf_len);
 
        /*
-        * These are provided separately from set_params in order to facilitate silicon
-        * tuners which require sophisticated tuning loops, controlling each parameter separately.
+        * These are provided separately from set_params in order to
+        * facilitate silicon tuners which require sophisticated tuning loops,
+        * controlling each parameter separately.
+        *
+        * Don't use on newer drivers.
         */
-       int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
-       int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
+       int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
+       int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
 };
 
 /**
@@ -404,6 +404,11 @@ struct dtv_frontend_properties;
  *                     FE_ENABLE_HIGH_LNB_VOLTAGE ioctl (only Satellite).
  * @dishnetwork_send_legacy_command: callback function to implement the
  *                     FE_DISHNETWORK_SEND_LEGACY_CMD ioctl (only Satellite).
+ *                     Drivers should not use this, except when the DVB
+ *                     core emulation fails to provide proper support (e.g.
+ *                     if set_voltage() takes more than 8ms to work), and
+ *                     when backward compatibility with this legacy API is
+ *                     required.
  * @i2c_gate_ctrl:     controls the I2C gate. Newer drivers should use I2C
  *                     mux support instead.
  * @ts_bus_ctrl:       callback function used to take control of the TS bus.
@@ -466,7 +471,8 @@ struct dvb_frontend_ops {
        int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
        int (*set_lna)(struct dvb_frontend *);
 
-       /* These callbacks are for devices that implement their own
+       /*
+        * These callbacks are for devices that implement their own
         * tuning algorithms, rather than a simple swzigzag
         */
        enum dvbfe_search (*search)(struct dvb_frontend *fe);
@@ -682,17 +688,126 @@ struct dvb_frontend {
        unsigned int exit;
 };
 
-extern int dvb_register_frontend(struct dvb_adapter *dvb,
+/**
+ * dvb_register_frontend() - Registers a DVB frontend at the adapter
+ *
+ * @dvb: pointer to the dvb adapter
+ * @fe: pointer to the frontend struct
+ *
+ * Allocate and initialize the private data needed by the frontend core to
+ * manage the frontend and calls dvb_register_device() to register a new
+ * frontend. It also cleans the property cache that stores the frontend
+ * parameters and selects the first available delivery system.
+ */
+int dvb_register_frontend(struct dvb_adapter *dvb,
                                 struct dvb_frontend *fe);
 
-extern int dvb_unregister_frontend(struct dvb_frontend *fe);
+/**
+ * dvb_unregister_frontend() - Unregisters a DVB frontend
+ *
+ * @fe: pointer to the frontend struct
+ *
+ * Stops the frontend kthread, calls dvb_unregister_device() and frees the
+ * private frontend data allocated by dvb_register_frontend().
+ *
+ * NOTE: This function doesn't frees the memory allocated by the demod,
+ * by the SEC driver and by the tuner. In order to free it, an explicit call to
+ * dvb_frontend_detach() is needed, after calling this function.
+ */
+int dvb_unregister_frontend(struct dvb_frontend *fe);
 
-extern void dvb_frontend_detach(struct dvb_frontend *fe);
+/**
+ * dvb_frontend_detach() - Detaches and frees frontend specific data
+ *
+ * @fe: pointer to the frontend struct
+ *
+ * This function should be called after dvb_unregister_frontend(). It
+ * calls the SEC, tuner and demod release functions:
+ * &dvb_frontend_ops.release_sec, &dvb_frontend_ops.tuner_ops.release,
+ * &dvb_frontend_ops.analog_ops.release and &dvb_frontend_ops.release.
+ *
+ * If the driver is compiled with CONFIG_MEDIA_ATTACH, it also decreases
+ * the module reference count, needed to allow userspace to remove the
+ * previously used DVB frontend modules.
+ */
+void dvb_frontend_detach(struct dvb_frontend *fe);
+
+/**
+ * dvb_frontend_suspend() - Suspends a Digital TV frontend
+ *
+ * @fe: pointer to the frontend struct
+ *
+ * This function prepares a Digital TV frontend to suspend.
+ *
+ * In order to prepare the tuner to suspend, if
+ * &dvb_frontend_ops.tuner_ops.suspend() is available, it calls it. Otherwise,
+ * it will call &dvb_frontend_ops.tuner_ops.sleep(), if available.
+ *
+ * It will also call &dvb_frontend_ops.sleep() to put the demod to suspend.
+ *
+ * The drivers should also call dvb_frontend_suspend() as part of their
+ * handler for the &device_driver.suspend().
+ */
+int dvb_frontend_suspend(struct dvb_frontend *fe);
+
+/**
+ * dvb_frontend_resume() - Resumes a Digital TV frontend
+ *
+ * @fe: pointer to the frontend struct
+ *
+ * This function resumes the usual operation of the tuner after resume.
+ *
+ * In order to resume the frontend, it calls the demod &dvb_frontend_ops.init().
+ *
+ * If &dvb_frontend_ops.tuner_ops.resume() is available, It, it calls it.
+ * Otherwise,t will call &dvb_frontend_ops.tuner_ops.init(), if available.
+ *
+ * Once tuner and demods are resumed, it will enforce that the SEC voltage and
+ * tone are restored to their previous values and wake up the frontend's
+ * kthread in order to retune the frontend.
+ *
+ * The drivers should also call dvb_frontend_resume() as part of their
+ * handler for the &device_driver.resume().
+ */
+int dvb_frontend_resume(struct dvb_frontend *fe);
 
-extern void dvb_frontend_reinitialise(struct dvb_frontend *fe);
-extern int dvb_frontend_suspend(struct dvb_frontend *fe);
-extern int dvb_frontend_resume(struct dvb_frontend *fe);
+/**
+ * dvb_frontend_reinitialise() - forces a reinitialisation at the frontend
+ *
+ * @fe: pointer to the frontend struct
+ *
+ * Calls &dvb_frontend_ops.init() and &dvb_frontend_ops.tuner_ops.init(),
+ * and resets SEC tone and voltage (for Satellite systems).
+ *
+ * NOTE: Currently, this function is used only by one driver (budget-av).
+ * It seems to be due to address some special issue with that specific
+ * frontend.
+ */
+void dvb_frontend_reinitialise(struct dvb_frontend *fe);
 
-extern void dvb_frontend_sleep_until(ktime_t *waketime, u32 add_usec);
+/**
+ * dvb_frontend_sleep_until() - Sleep for the amount of time given by
+ *                      add_usec parameter
+ *
+ * @waketime: pointer to a struct ktime_t
+ * @add_usec: time to sleep, in microseconds
+ *
+ * This function is used to measure the time required for the
+ * %FE_DISHNETWORK_SEND_LEGACY_CMD ioctl to work. It needs to be as precise
+ * as possible, as it affects the detection of the dish tone command at the
+ * satellite subsystem.
+ *
+ * Its used internally by the DVB frontend core, in order to emulate
+ * %FE_DISHNETWORK_SEND_LEGACY_CMD using the &dvb_frontend_ops.set_voltage()
+ * callback.
+ *
+ * NOTE: it should not be used at the drivers, as the emulation for the
+ * legacy callback is provided by the Kernel. The only situation where this
+ * should be at the drivers is when there are some bugs at the hardware that
+ * would prevent the core emulation to work. On such cases, the driver would
+ * be writing a &dvb_frontend_ops.dishnetwork_send_legacy_command() and
+ * calling this function directly.
+ */
+void dvb_frontend_sleep_until(ktime_t *waketime, u32 add_usec);
 
 #endif
index 292c9479bb75e391bdb82597cc2ba154abc839c5..310e4b8beae89672ed341747cca221b51d3ca1b3 100644 (file)
@@ -264,7 +264,7 @@ config DVB_MB86A16
 config DVB_TDA10071
        tristate "NXP TDA10071"
        depends on DVB_CORE && I2C
-       select REGMAP
+       select REGMAP_I2C
        default m if !MEDIA_SUBDRV_AUTOSELECT
        help
          Say Y when you want to support this frontend.
index 3559ff230045450ad885bf8e118aaa27a80c50df..f135126bc373ed1e8e7ad161e40b4fcec16ab0bf 100644 (file)
@@ -44,7 +44,7 @@ int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
        int ret;
        u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
 
-       struct i2c_msg msg = { .addr = state->config->demod_address,
+       struct i2c_msg msg = { .addr = state->config.demod_address,
                               .flags = 0, .buf = buf, .len = 3 };
 
        ret = i2c_transfer(state->i2c, &msg, 1);
@@ -64,9 +64,9 @@ u8 au8522_readreg(struct au8522_state *state, u16 reg)
        u8 b1[] = { 0 };
 
        struct i2c_msg msg[] = {
-               { .addr = state->config->demod_address, .flags = 0,
+               { .addr = state->config.demod_address, .flags = 0,
                  .buf = b0, .len = 2 },
-               { .addr = state->config->demod_address, .flags = I2C_M_RD,
+               { .addr = state->config.demod_address, .flags = I2C_M_RD,
                  .buf = b1, .len = 1 } };
 
        ret = i2c_transfer(state->i2c, msg, 2);
@@ -140,7 +140,7 @@ EXPORT_SYMBOL(au8522_release_state);
 
 static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
 {
-       struct au8522_led_config *led_config = state->config->led_cfg;
+       struct au8522_led_config *led_config = state->config.led_cfg;
        u8 val;
 
        /* bail out if we can't control an LED */
@@ -170,7 +170,7 @@ static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
  */
 int au8522_led_ctrl(struct au8522_state *state, int led)
 {
-       struct au8522_led_config *led_config = state->config->led_cfg;
+       struct au8522_led_config *led_config = state->config.led_cfg;
        int i, ret = 0;
 
        /* bail out if we can't control an LED */
index 28d7dc2fee34e94bb3fbb0db4e05e1bc9934cd9e..c8f13d8370e507979bcc2d552aec637b0eed16b4 100644 (file)
@@ -730,7 +730,6 @@ static int au8522_probe(struct i2c_client *client,
        struct v4l2_ctrl_handler *hdl;
        struct v4l2_subdev *sd;
        int instance;
-       struct au8522_config *demod_config;
 
        /* Check if the adapter supports the needed features */
        if (!i2c_check_functionality(client->adapter,
@@ -754,15 +753,7 @@ static int au8522_probe(struct i2c_client *client,
                break;
        }
 
-       demod_config = kzalloc(sizeof(struct au8522_config), GFP_KERNEL);
-       if (demod_config == NULL) {
-               if (instance == 1)
-                       kfree(state);
-               return -ENOMEM;
-       }
-       demod_config->demod_address = 0x8e >> 1;
-
-       state->config = demod_config;
+       state->config.demod_address = 0x8e >> 1;
        state->i2c = client->adapter;
 
        sd = &state->sd;
@@ -784,8 +775,7 @@ static int au8522_probe(struct i2c_client *client,
                int err = hdl->error;
 
                v4l2_ctrl_handler_free(hdl);
-               kfree(demod_config);
-               kfree(state);
+               au8522_release_state(state);
                return err;
        }
 
index f956f13fb3dc04b4f9458e8a6bc8b06f8f5dde5c..6c1e97640f3f6519dbb4689adf578488483803d3 100644 (file)
@@ -566,7 +566,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
                        au8522_writereg(state,
                                VSB_mod_tab[i].reg,
                                VSB_mod_tab[i].data);
-               au8522_set_if(fe, state->config->vsb_if);
+               au8522_set_if(fe, state->config.vsb_if);
                break;
        case QAM_64:
                dprintk("%s() QAM 64\n", __func__);
@@ -574,7 +574,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
                        au8522_writereg(state,
                                QAM64_mod_tab[i].reg,
                                QAM64_mod_tab[i].data);
-               au8522_set_if(fe, state->config->qam_if);
+               au8522_set_if(fe, state->config.qam_if);
                break;
        case QAM_256:
                if (zv_mode) {
@@ -583,7 +583,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
                                au8522_writereg(state,
                                        QAM256_mod_tab_zv_mode[i].reg,
                                        QAM256_mod_tab_zv_mode[i].data);
-                       au8522_set_if(fe, state->config->qam_if);
+                       au8522_set_if(fe, state->config.qam_if);
                        msleep(100);
                        au8522_writereg(state, 0x821a, 0x00);
                } else {
@@ -592,7 +592,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
                                au8522_writereg(state,
                                        QAM256_mod_tab[i].reg,
                                        QAM256_mod_tab[i].data);
-                       au8522_set_if(fe, state->config->qam_if);
+                       au8522_set_if(fe, state->config.qam_if);
                }
                break;
        default:
@@ -666,7 +666,7 @@ static int au8522_read_status(struct dvb_frontend *fe, enum fe_status *status)
                        *status |= FE_HAS_LOCK | FE_HAS_SYNC;
        }
 
-       switch (state->config->status_mode) {
+       switch (state->config.status_mode) {
        case AU8522_DEMODLOCKING:
                dprintk("%s() DEMODLOCKING\n", __func__);
                if (*status & FE_HAS_VITERBI)
@@ -704,7 +704,7 @@ static int au8522_read_status(struct dvb_frontend *fe, enum fe_status *status)
 
 static int au8522_led_status(struct au8522_state *state, const u16 *snr)
 {
-       struct au8522_led_config *led_config = state->config->led_cfg;
+       struct au8522_led_config *led_config = state->config.led_cfg;
        int led;
        u16 strong;
 
@@ -758,7 +758,7 @@ static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
                                            au8522_readreg(state, 0x4311),
                                            snr);
 
-       if (state->config->led_cfg)
+       if (state->config.led_cfg)
                au8522_led_status(state, snr);
 
        return ret;
@@ -866,7 +866,7 @@ struct dvb_frontend *au8522_attach(const struct au8522_config *config,
        }
 
        /* setup the state */
-       state->config = config;
+       state->config = *config;
        state->i2c = i2c;
        state->operational_mode = AU8522_DIGITAL_MODE;
 
index 951b3847e6f66a95775118a96bf3c4279bb528ef..ee330c61aa613e6792071b0fbd8144e565e4f18a 100644 (file)
@@ -50,7 +50,7 @@ struct au8522_state {
        struct list_head hybrid_tuner_instance_list;
 
        /* configuration settings */
-       const struct au8522_config *config;
+       struct au8522_config config;
 
        struct dvb_frontend frontend;
 
index 7ed3c424178ca0b97ebcb858d4b349c6301a0ced..baaf89e768cf500ea96497d930dbfb1ac6004f30 100644 (file)
@@ -21,7 +21,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
  */
 
 #ifndef BSBE1_D01A_H
index 53e4d0dbb745ccabd5001c5b0780631e547d0f78..4ad7661547415e1a0dc398bc8b59a2f59cb8f425 100644 (file)
@@ -19,7 +19,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
  */
 
 #ifndef BSBE1_H
index c2a578e1314dce5ffb4495de51c5e97277036c12..275c1782597d91a420939598e35324dab29a15bf 100644 (file)
@@ -19,7 +19,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
  */
 
 #ifndef BSRU6_H
index b46450a10b80ac48e39e942bd5f42bcbc7446797..6913cd687b4d514d8c8063c526492619fd823fda 100644 (file)
@@ -22,7 +22,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
  */
 #include <linux/delay.h>
 #include <linux/errno.h>
index 3c148b830bd199f6e72b3bb2bee1554568689488..4a23d3bdf3e6b6200fb60ded487aa963bcc96c7b 100644 (file)
@@ -22,7 +22,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
  */
 
 #ifndef _ISL6405_H
index 3a4d4606a4268bdac9bfdda5bef3fa094928599a..0b6d3837d5de52c0ecea33980a4c9f2afd3809ca 100644 (file)
@@ -22,7 +22,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
  */
 #include <linux/delay.h>
 #include <linux/errno.h>
index 3273597833fda0c9d683ef3f0df65978363de9d2..00f9874ca5a28b61f8e2942041066d3456a477d7 100644 (file)
@@ -22,7 +22,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
  */
 
 #ifndef _ISL6421_H
index 4aca0fb9a8a7d161da4dfb7dfbc9532b53f15fbf..6261460d93a7f069e9b2e06a5e6972d413a5ef77 100644 (file)
@@ -22,7 +22,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
  */
 #include <linux/delay.h>
 #include <linux/errno.h>
index a9b530de62a60582a6574ab3325baac003d229ed..cd9101f6e5799366c30d99d458bfabd232ab64fc 100644 (file)
@@ -21,7 +21,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
  */
 
 #ifndef _LNBP21_H
index d7ca0fdd008416836c5cc9d503b0c11642e8c844..5c5fd04fd4a73dfacc3fb867eb32ee0f6a669bdd 100644 (file)
@@ -22,7 +22,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
  */
 #include <linux/delay.h>
 #include <linux/errno.h>
index 628148385182af8a8ab2eebeb3d6f726b0e6166a..5d01d92814c21b7feb30357f0ab68ec30d869cd4 100644 (file)
@@ -22,7 +22,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
  */
 
 #ifndef _LNBP22_H
index 78b87b260d745c88d7c07dd9983ea9b70d9995db..10f2119935da8b69402dc21cae1c040e6f8aadf4 100644 (file)
@@ -976,7 +976,8 @@ static int rtl2832_regmap_read(void *context, const void *reg_buf,
 
        ret = __i2c_transfer(client->adapter, msg, 2);
        if (ret != 2) {
-               dev_warn(&client->dev, "i2c reg read failed %d\n", ret);
+               dev_warn(&client->dev, "i2c reg read failed %d reg %02x\n",
+                        ret, *(u8 *)reg_buf);
                if (ret >= 0)
                        ret = -EREMOTEIO;
                return ret;
@@ -999,7 +1000,8 @@ static int rtl2832_regmap_write(void *context, const void *data, size_t count)
 
        ret = __i2c_transfer(client->adapter, msg, 1);
        if (ret != 1) {
-               dev_warn(&client->dev, "i2c reg write failed %d\n", ret);
+               dev_warn(&client->dev, "i2c reg write failed %d reg %02x\n",
+                        ret, *(u8 *)data);
                if (ret >= 0)
                        ret = -EREMOTEIO;
                return ret;
@@ -1028,7 +1030,8 @@ static int rtl2832_regmap_gather_write(void *context, const void *reg,
 
        ret = __i2c_transfer(client->adapter, msg, 1);
        if (ret != 1) {
-               dev_warn(&client->dev, "i2c reg write failed %d\n", ret);
+               dev_warn(&client->dev, "i2c reg write failed %d reg %02x\n",
+                        ret, *(u8 const *)reg);
                if (ret >= 0)
                        ret = -EREMOTEIO;
                return ret;
@@ -1097,18 +1100,6 @@ static int rtl2832_enable_slave_ts(struct i2c_client *client)
        if (ret)
                goto err;
 
-       ret = rtl2832_bulk_write(client, 0x022, "\x01", 1);
-       if (ret)
-               goto err;
-
-       ret = rtl2832_bulk_write(client, 0x026, "\x1f", 1);
-       if (ret)
-               goto err;
-
-       ret = rtl2832_bulk_write(client, 0x027, "\xff", 1);
-       if (ret)
-               goto err;
-
        ret = rtl2832_bulk_write(client, 0x192, "\x7f\xf7\xff", 3);
        if (ret)
                goto err;
index dcd8d94c10376ce31ab691a1c460696c14d876b2..b860f02a4e55b4eff83e03a149f4eac2003b53e6 100644 (file)
@@ -310,7 +310,7 @@ static void rtl2832_sdr_urb_complete(struct urb *urb)
                len = rtl2832_sdr_convert_stream(dev, ptr, urb->transfer_buffer,
                                urb->actual_length);
                vb2_set_plane_payload(&fbuf->vb.vb2_buf, 0, len);
-               v4l2_get_timestamp(&fbuf->vb.timestamp);
+               fbuf->vb.vb2_buf.timestamp = ktime_get_ns();
                fbuf->vb.sequence = dev->sequence++;
                vb2_buffer_done(&fbuf->vb.vb2_buf, VB2_BUF_STATE_DONE);
        }
@@ -490,7 +490,7 @@ static int rtl2832_sdr_querycap(struct file *file, void *fh,
 
 /* Videobuf2 operations */
 static int rtl2832_sdr_queue_setup(struct vb2_queue *vq,
-               const void *parg, unsigned int *nbuffers,
+               unsigned int *nbuffers,
                unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
 {
        struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vq);
index 7c2eeee69757756957938ac287cdda4eaa1ea364..1cf6e52e010512123af9d5fb39491d97c1f63522 100644 (file)
@@ -1,21 +1,21 @@
 /*
   Driver for Silicon Labs Si2161 DVB-T and Si2165 DVB-C/-T Demodulator
-
   Copyright (C) 2013-2014 Matthias Schwarzott <zzam@gentoo.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.
-
   References:
   http://www.silabs.com/Support%20Documents/TechnicalDocs/Si2165-short.pdf
-*/
*  Driver for Silicon Labs Si2161 DVB-T and Si2165 DVB-C/-T Demodulator
+ *
*  Copyright (C) 2013-2014 Matthias Schwarzott <zzam@gentoo.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.
+ *
*  References:
*  http://www.silabs.com/Support%20Documents/TechnicalDocs/Si2165-short.pdf
+ */
 
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include "si2165_priv.h"
 #include "si2165.h"
 
-/* Hauppauge WinTV-HVR-930C-HD B130 / PCTV QuatroStick 521e 1113xx
- * uses 16 MHz xtal */
-
-/* Hauppauge WinTV-HVR-930C-HD B131 / PCTV QuatroStick 522e 1114xx
- * uses 24 MHz clock provided by tuner */
+/*
+ * Hauppauge WinTV-HVR-930C-HD B130 / PCTV QuatroStick 521e 1113xx
+ * uses 16 MHz xtal
+ *
+ * Hauppauge WinTV-HVR-930C-HD B131 / PCTV QuatroStick 522e 1114xx
+ * uses 24 MHz clock provided by tuner
+ */
 
 struct si2165_state {
        struct i2c_adapter *i2c;
 
-       struct dvb_frontend frontend;
+       struct dvb_frontend fe;
 
        struct si2165_config config;
 
@@ -241,6 +243,27 @@ err:
        return ret;
 }
 
+#define REG16(reg, val) { (reg), (val) & 0xff }, { (reg)+1, (val)>>8 & 0xff }
+struct si2165_reg_value_pair {
+       u16 reg;
+       u8 val;
+};
+
+static int si2165_write_reg_list(struct si2165_state *state,
+                                const struct si2165_reg_value_pair *regs,
+                                int count)
+{
+       int i;
+       int ret;
+
+       for (i = 0; i < count; i++) {
+               ret = si2165_writereg8(state, regs[i].reg, regs[i].val);
+               if (ret < 0)
+                       return ret;
+       }
+       return 0;
+}
+
 static int si2165_get_tune_settings(struct dvb_frontend *fe,
                                    struct dvb_frontend_tune_settings *s)
 {
@@ -258,8 +281,10 @@ static int si2165_init_pll(struct si2165_state *state)
        u8 divl = 12;
        u8 buf[4];
 
-       /* hardcoded values can be deleted if calculation is verified
-        * or it yields the same values as the windows driver */
+       /*
+        * hardcoded values can be deleted if calculation is verified
+        * or it yields the same values as the windows driver
+        */
        switch (ref_freq_Hz) {
        case 16000000u:
                divn = 56;
@@ -274,8 +299,10 @@ static int si2165_init_pll(struct si2165_state *state)
                if (ref_freq_Hz > 16000000u)
                        divr = 2;
 
-               /* now select divn and divp such that
-                * fvco is in 1624..1824 MHz */
+               /*
+                * now select divn and divp such that
+                * fvco is in 1624..1824 MHz
+                */
                if (1624000000u * divr > ref_freq_Hz * 2u * 63u)
                        divp = 4;
 
@@ -341,10 +368,12 @@ static int si2165_upload_firmware_block(struct si2165_state *state,
        if (len % 4 != 0)
                return -EINVAL;
 
-       deb_fw_load("si2165_upload_firmware_block called with len=0x%x offset=0x%x blockcount=0x%x\n",
+       deb_fw_load(
+               "si2165_upload_firmware_block called with len=0x%x offset=0x%x blockcount=0x%x\n",
                                len, offset, block_count);
        while (offset+12 <= len && cur_block < block_count) {
-               deb_fw_load("si2165_upload_firmware_block in while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n",
+               deb_fw_load(
+                       "si2165_upload_firmware_block in while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n",
                                        len, offset, cur_block, block_count);
                wordcount = data[offset];
                if (wordcount < 1 || data[offset+1] ||
@@ -383,7 +412,8 @@ static int si2165_upload_firmware_block(struct si2165_state *state,
                cur_block++;
        }
 
-       deb_fw_load("si2165_upload_firmware_block after while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n",
+       deb_fw_load(
+               "si2165_upload_firmware_block after while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n",
                                len, offset, cur_block, block_count);
 
        if (poffset)
@@ -633,7 +663,7 @@ static int si2165_init(struct dvb_frontend *fe)
                goto error;
 
        /* ber_pkt */
-       ret = si2165_writereg16(state, 0x0470 , 0x7530);
+       ret = si2165_writereg16(state, 0x0470, 0x7530);
        if (ret < 0)
                goto error;
 
@@ -660,22 +690,19 @@ static int si2165_init(struct dvb_frontend *fe)
                        goto error;
        }
 
-       /* write adc values after each reset*/
-       ret = si2165_writereg8(state, 0x012a, 0x46);
-       if (ret < 0)
-               goto error;
-       ret = si2165_writereg8(state, 0x012c, 0x00);
+       /* ts output config */
+       ret = si2165_writereg8(state, 0x04e4, 0x20);
        if (ret < 0)
-               goto error;
-       ret = si2165_writereg8(state, 0x012e, 0x0a);
+               return ret;
+       ret = si2165_writereg16(state, 0x04ef, 0x00fe);
        if (ret < 0)
-               goto error;
-       ret = si2165_writereg8(state, 0x012f, 0xff);
+               return ret;
+       ret = si2165_writereg24(state, 0x04f4, 0x555555);
        if (ret < 0)
-               goto error;
-       ret = si2165_writereg8(state, 0x0123, 0x70);
+               return ret;
+       ret = si2165_writereg8(state, 0x04e5, 0x01);
        if (ret < 0)
-               goto error;
+               return ret;
 
        return 0;
 error:
@@ -733,16 +760,26 @@ static int si2165_set_oversamp(struct si2165_state *state, u32 dvb_rate)
        do_div(oversamp, dvb_rate);
        reg_value = oversamp & 0x3fffffff;
 
-       /* oversamp, usbdump contained 0x03100000; */
+       dprintk("%s: Write oversamp=%#x\n", __func__, reg_value);
        return si2165_writereg32(state, 0x00e4, reg_value);
 }
 
-static int si2165_set_if_freq_shift(struct si2165_state *state, u32 IF)
+static int si2165_set_if_freq_shift(struct si2165_state *state)
 {
+       struct dvb_frontend *fe = &state->fe;
        u64 if_freq_shift;
        s32 reg_value = 0;
        u32 fe_clk = si2165_get_fe_clk(state);
+       u32 IF = 0;
 
+       if (!fe->ops.tuner_ops.get_if_frequency) {
+               dev_err(&state->i2c->dev,
+                       "%s: Error: get_if_frequency() not defined at tuner. Can't work without it!\n",
+                       KBUILD_MODNAME);
+               return -EINVAL;
+       }
+
+       fe->ops.tuner_ops.get_if_frequency(fe, &IF);
        if_freq_shift = IF;
        if_freq_shift <<= 29;
 
@@ -758,25 +795,39 @@ static int si2165_set_if_freq_shift(struct si2165_state *state, u32 IF)
        return si2165_writereg32(state, 0x00e8, reg_value);
 }
 
-static int si2165_set_parameters(struct dvb_frontend *fe)
+static const struct si2165_reg_value_pair dvbt_regs[] = {
+       /* standard = DVB-T */
+       { 0x00ec, 0x01 },
+       { 0x08f8, 0x00 },
+       /* impulsive_noise_remover */
+       { 0x031c, 0x01 },
+       { 0x00cb, 0x00 },
+       /* agc2 */
+       { 0x016e, 0x41 },
+       { 0x016c, 0x0e },
+       { 0x016d, 0x10 },
+       /* agc */
+       { 0x015b, 0x03 },
+       { 0x0150, 0x78 },
+       /* agc */
+       { 0x01a0, 0x78 },
+       { 0x01c8, 0x68 },
+       /* freq_sync_range */
+       REG16(0x030c, 0x0064),
+       /* gp_reg0 */
+       { 0x0387, 0x00 }
+};
+
+static int si2165_set_frontend_dvbt(struct dvb_frontend *fe)
 {
        int ret;
        struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct si2165_state *state = fe->demodulator_priv;
-       u8 val[3];
-       u32 IF;
        u32 dvb_rate = 0;
        u16 bw10k;
 
        dprintk("%s: called\n", __func__);
 
-       if (!fe->ops.tuner_ops.get_if_frequency) {
-               dev_err(&state->i2c->dev,
-                       "%s: Error: get_if_frequency() not defined at tuner. Can't work without it!\n",
-                       KBUILD_MODNAME);
-               return -EINVAL;
-       }
-
        if (!state->has_dvbt)
                return -EINVAL;
 
@@ -788,34 +839,10 @@ static int si2165_set_parameters(struct dvb_frontend *fe)
                bw10k = 800;
        }
 
-       /* standard = DVB-T */
-       ret = si2165_writereg8(state, 0x00ec, 0x01);
-       if (ret < 0)
-               return ret;
        ret = si2165_adjust_pll_divl(state, 12);
        if (ret < 0)
                return ret;
 
-       fe->ops.tuner_ops.get_if_frequency(fe, &IF);
-       ret = si2165_set_if_freq_shift(state, IF);
-       if (ret < 0)
-               return ret;
-       ret = si2165_writereg8(state, 0x08f8, 0x00);
-       if (ret < 0)
-               return ret;
-       /* ts output config */
-       ret = si2165_writereg8(state, 0x04e4, 0x20);
-       if (ret < 0)
-               return ret;
-       ret = si2165_writereg16(state, 0x04ef, 0x00fe);
-       if (ret < 0)
-               return ret;
-       ret = si2165_writereg24(state, 0x04f4, 0x555555);
-       if (ret < 0)
-               return ret;
-       ret = si2165_writereg8(state, 0x04e5, 0x01);
-       if (ret < 0)
-               return ret;
        /* bandwidth in 10KHz steps */
        ret = si2165_writereg16(state, 0x0308, bw10k);
        if (ret < 0)
@@ -823,48 +850,115 @@ static int si2165_set_parameters(struct dvb_frontend *fe)
        ret = si2165_set_oversamp(state, dvb_rate);
        if (ret < 0)
                return ret;
-       /* impulsive_noise_remover */
-       ret = si2165_writereg8(state, 0x031c, 0x01);
-       if (ret < 0)
-               return ret;
-       ret = si2165_writereg8(state, 0x00cb, 0x00);
+
+       ret = si2165_write_reg_list(state, dvbt_regs, ARRAY_SIZE(dvbt_regs));
        if (ret < 0)
                return ret;
+
+       return 0;
+}
+
+static const struct si2165_reg_value_pair dvbc_regs[] = {
+       /* standard = DVB-C */
+       { 0x00ec, 0x05 },
+       { 0x08f8, 0x00 },
+
        /* agc2 */
-       ret = si2165_writereg8(state, 0x016e, 0x41);
-       if (ret < 0)
-               return ret;
-       ret = si2165_writereg8(state, 0x016c, 0x0e);
-       if (ret < 0)
-               return ret;
-       ret = si2165_writereg8(state, 0x016d, 0x10);
-       if (ret < 0)
-               return ret;
+       { 0x016e, 0x50 },
+       { 0x016c, 0x0e },
+       { 0x016d, 0x10 },
        /* agc */
-       ret = si2165_writereg8(state, 0x015b, 0x03);
-       if (ret < 0)
-               return ret;
-       ret = si2165_writereg8(state, 0x0150, 0x78);
-       if (ret < 0)
-               return ret;
+       { 0x015b, 0x03 },
+       { 0x0150, 0x68 },
        /* agc */
-       ret = si2165_writereg8(state, 0x01a0, 0x78);
+       { 0x01a0, 0x68 },
+       { 0x01c8, 0x50 },
+
+       { 0x0278, 0x0d },
+
+       { 0x023a, 0x05 },
+       { 0x0261, 0x09 },
+       REG16(0x0350, 0x3e80),
+       { 0x02f4, 0x00 },
+
+       { 0x00cb, 0x01 },
+       REG16(0x024c, 0x0000),
+       REG16(0x027c, 0x0000),
+       { 0x0232, 0x03 },
+       { 0x02f4, 0x0b },
+       { 0x018b, 0x00 },
+};
+
+static int si2165_set_frontend_dvbc(struct dvb_frontend *fe)
+{
+       struct si2165_state *state = fe->demodulator_priv;
+       int ret;
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+       const u32 dvb_rate = p->symbol_rate;
+       const u32 bw_hz = p->bandwidth_hz;
+
+       if (!state->has_dvbc)
+               return -EINVAL;
+
+       if (dvb_rate == 0)
+               return -EINVAL;
+
+       ret = si2165_adjust_pll_divl(state, 14);
        if (ret < 0)
                return ret;
-       ret = si2165_writereg8(state, 0x01c8, 0x68);
+
+       /* Oversampling */
+       ret = si2165_set_oversamp(state, dvb_rate);
        if (ret < 0)
                return ret;
-       /* freq_sync_range */
-       ret = si2165_writereg16(state, 0x030c, 0x0064);
+
+       ret = si2165_writereg32(state, 0x00c4, bw_hz);
        if (ret < 0)
                return ret;
-       /* gp_reg0 */
-       ret = si2165_readreg8(state, 0x0387, val);
+
+       ret = si2165_write_reg_list(state, dvbc_regs, ARRAY_SIZE(dvbc_regs));
        if (ret < 0)
                return ret;
-       ret = si2165_writereg8(state, 0x0387, 0x00);
+
+       return 0;
+}
+
+static const struct si2165_reg_value_pair agc_rewrite[] = {
+       { 0x012a, 0x46 },
+       { 0x012c, 0x00 },
+       { 0x012e, 0x0a },
+       { 0x012f, 0xff },
+       { 0x0123, 0x70 }
+};
+
+static int si2165_set_frontend(struct dvb_frontend *fe)
+{
+       struct si2165_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+       u32 delsys = p->delivery_system;
+       int ret;
+       u8 val[3];
+
+       /* initial setting of if freq shift */
+       ret = si2165_set_if_freq_shift(state);
        if (ret < 0)
                return ret;
+
+       switch (delsys) {
+       case SYS_DVBT:
+               ret = si2165_set_frontend_dvbt(fe);
+               if (ret < 0)
+                       return ret;
+               break;
+       case SYS_DVBC_ANNEX_A:
+               ret = si2165_set_frontend_dvbc(fe);
+               if (ret < 0)
+                       return ret;
+               break;
+       default:
+               return -EINVAL;
+       }
+
        /* dsp_addr_jump */
        ret = si2165_writereg32(state, 0x0348, 0xf4000000);
        if (ret < 0)
@@ -874,8 +968,7 @@ static int si2165_set_parameters(struct dvb_frontend *fe)
                fe->ops.tuner_ops.set_params(fe);
 
        /* recalc if_freq_shift if IF might has changed */
-       fe->ops.tuner_ops.get_if_frequency(fe, &IF);
-       ret = si2165_set_if_freq_shift(state, IF);
+       ret = si2165_set_if_freq_shift(state);
        if (ret < 0)
                return ret;
 
@@ -886,6 +979,7 @@ static int si2165_set_parameters(struct dvb_frontend *fe)
        ret = si2165_writereg8(state, 0x0341, 0x00);
        if (ret < 0)
                return ret;
+
        /* reset all */
        ret = si2165_writereg8(state, 0x00c0, 0x00);
        if (ret < 0)
@@ -894,6 +988,13 @@ static int si2165_set_parameters(struct dvb_frontend *fe)
        ret = si2165_writereg32(state, 0x0384, 0x00000000);
        if (ret < 0)
                return ret;
+
+       /* write adc values after each reset*/
+       ret = si2165_write_reg_list(state, agc_rewrite,
+                                   ARRAY_SIZE(agc_rewrite));
+       if (ret < 0)
+               return ret;
+
        /* start_synchro */
        ret = si2165_writereg8(state, 0x02e0, 0x01);
        if (ret < 0)
@@ -917,7 +1018,12 @@ static void si2165_release(struct dvb_frontend *fe)
 static struct dvb_frontend_ops si2165_ops = {
        .info = {
                .name = "Silicon Labs ",
-               .caps = FE_CAN_FEC_1_2 |
+                /* For DVB-C */
+               .symbol_rate_min = 1000000,
+               .symbol_rate_max = 7200000,
+               /* For DVB-T */
+               .frequency_stepsize = 166667,
+               .caps = FE_CAN_FEC_1_2 |
                        FE_CAN_FEC_2_3 |
                        FE_CAN_FEC_3_4 |
                        FE_CAN_FEC_5_6 |
@@ -930,7 +1036,6 @@ static struct dvb_frontend_ops si2165_ops = {
                        FE_CAN_QAM_128 |
                        FE_CAN_QAM_256 |
                        FE_CAN_QAM_AUTO |
-                       FE_CAN_TRANSMISSION_MODE_AUTO |
                        FE_CAN_GUARD_INTERVAL_AUTO |
                        FE_CAN_HIERARCHY_AUTO |
                        FE_CAN_MUTE_TS |
@@ -943,7 +1048,7 @@ static struct dvb_frontend_ops si2165_ops = {
        .init = si2165_init,
        .sleep = si2165_sleep,
 
-       .set_frontend      = si2165_set_parameters,
+       .set_frontend      = si2165_set_frontend,
        .read_status       = si2165_read_status,
 
        .release = si2165_release,
@@ -979,9 +1084,9 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config,
        }
 
        /* create dvb_frontend */
-       memcpy(&state->frontend.ops, &si2165_ops,
+       memcpy(&state->fe.ops, &si2165_ops,
                sizeof(struct dvb_frontend_ops));
-       state->frontend.demodulator_priv = state;
+       state->fe.demodulator_priv = state;
 
        /* powerup */
        io_ret = si2165_writereg8(state, 0x0000, state->config.chip_mode);
@@ -1033,20 +1138,22 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config,
                KBUILD_MODNAME, chip_name, rev_char, state->chip_type,
                state->chip_revcode);
 
-       strlcat(state->frontend.ops.info.name, chip_name,
-                       sizeof(state->frontend.ops.info.name));
+       strlcat(state->fe.ops.info.name, chip_name,
+                       sizeof(state->fe.ops.info.name));
 
        n = 0;
        if (state->has_dvbt) {
-               state->frontend.ops.delsys[n++] = SYS_DVBT;
-               strlcat(state->frontend.ops.info.name, " DVB-T",
-                       sizeof(state->frontend.ops.info.name));
+               state->fe.ops.delsys[n++] = SYS_DVBT;
+               strlcat(state->fe.ops.info.name, " DVB-T",
+                       sizeof(state->fe.ops.info.name));
+       }
+       if (state->has_dvbc) {
+               state->fe.ops.delsys[n++] = SYS_DVBC_ANNEX_A;
+               strlcat(state->fe.ops.info.name, " DVB-C",
+                       sizeof(state->fe.ops.info.name));
        }
-       if (state->has_dvbc)
-               dev_warn(&state->i2c->dev, "%s: DVB-C is not yet supported.\n",
-                      KBUILD_MODNAME);
 
-       return &state->frontend;
+       return &state->fe;
 
 error:
        kfree(state);
index 4ef8a5c7003e907c2836e3ad77f6306fbafe1576..c978c801c7aa5b561009d16aaff4480e1451e246 100644 (file)
@@ -252,6 +252,7 @@ static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
 {
        int rc;
        u8 f;
+       u32 bw;
        struct stb6100_state *state = fe->tuner_priv;
 
        rc = stb6100_read_reg(state, STB6100_F);
@@ -259,9 +260,9 @@ static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
                return rc;
        f = rc & STB6100_F_F;
 
-       state->status.bandwidth = (f + 5) * 2000;       /* x2 for ZIF   */
+       bw = (f + 5) * 2000;    /* x2 for ZIF   */
 
-       *bandwidth = state->bandwidth = state->status.bandwidth * 1000;
+       *bandwidth = state->bandwidth = bw * 1000;
        dprintk(verbose, FE_DEBUG, 1, "bandwidth = %u Hz", state->bandwidth);
        return 0;
 }
@@ -495,68 +496,28 @@ static int stb6100_sleep(struct dvb_frontend *fe)
 static int stb6100_init(struct dvb_frontend *fe)
 {
        struct stb6100_state *state = fe->tuner_priv;
-       struct tuner_state *status = &state->status;
+       int refclk = 27000000; /* Hz */
 
-       status->tunerstep       = 125000;
-       status->ifreq           = 0;
-       status->refclock        = 27000000;     /* Hz   */
-       status->iqsense         = 1;
-       status->bandwidth       = 36000;        /* kHz  */
-       state->bandwidth        = status->bandwidth * 1000;     /* Hz   */
-       state->reference        = status->refclock / 1000;      /* kHz  */
+       /*
+        * iqsense = 1
+        * tunerstep = 125000
+        */
+       state->bandwidth        = 36000000;             /* Hz   */
+       state->reference        = refclk / 1000;        /* kHz  */
 
        /* Set default bandwidth. Modified, PN 13-May-10        */
        return 0;
 }
 
-static int stb6100_get_state(struct dvb_frontend *fe,
-                            enum tuner_param param,
-                            struct tuner_state *state)
+static int stb6100_set_params(struct dvb_frontend *fe)
 {
-       switch (param) {
-       case DVBFE_TUNER_FREQUENCY:
-               stb6100_get_frequency(fe, &state->frequency);
-               break;
-       case DVBFE_TUNER_TUNERSTEP:
-               break;
-       case DVBFE_TUNER_IFFREQ:
-               break;
-       case DVBFE_TUNER_BANDWIDTH:
-               stb6100_get_bandwidth(fe, &state->bandwidth);
-               break;
-       case DVBFE_TUNER_REFCLOCK:
-               break;
-       default:
-               break;
-       }
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 
-       return 0;
-}
+       if (c->frequency > 0)
+               stb6100_set_frequency(fe, c->frequency);
 
-static int stb6100_set_state(struct dvb_frontend *fe,
-                            enum tuner_param param,
-                            struct tuner_state *state)
-{
-       struct stb6100_state *tstate = fe->tuner_priv;
-
-       switch (param) {
-       case DVBFE_TUNER_FREQUENCY:
-               stb6100_set_frequency(fe, state->frequency);
-               tstate->frequency = state->frequency;
-               break;
-       case DVBFE_TUNER_TUNERSTEP:
-               break;
-       case DVBFE_TUNER_IFFREQ:
-               break;
-       case DVBFE_TUNER_BANDWIDTH:
-               stb6100_set_bandwidth(fe, state->bandwidth);
-               tstate->bandwidth = state->bandwidth;
-               break;
-       case DVBFE_TUNER_REFCLOCK:
-               break;
-       default:
-               break;
-       }
+       if (c->bandwidth_hz > 0)
+               stb6100_set_bandwidth(fe, c->bandwidth_hz);
 
        return 0;
 }
@@ -572,8 +533,9 @@ static struct dvb_tuner_ops stb6100_ops = {
        .init           = stb6100_init,
        .sleep          = stb6100_sleep,
        .get_status     = stb6100_get_status,
-       .get_state      = stb6100_get_state,
-       .set_state      = stb6100_set_state,
+       .set_params     = stb6100_set_params,
+       .get_frequency  = stb6100_get_frequency,
+       .get_bandwidth  = stb6100_get_bandwidth,
        .release        = stb6100_release
 };
 
index 218c8188865d160577d820c73b21f87fa27c4876..f7b468b6dc2634a188435464fec23275d35ba4e2 100644 (file)
@@ -86,7 +86,6 @@ struct stb6100_state {
        const struct stb6100_config     *config;
        struct dvb_tuner_ops            ops;
        struct dvb_frontend             *frontend;
-       struct tuner_state              status;
 
        u32 frequency;
        u32 srate;
index 6edc15365847ac8edcb28470b336efa987e4ae32..2ef67aa768b97ea1a054467ab0d889beca839389 100644 (file)
        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
 static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
        struct dvb_frontend_ops *frontend_ops = &fe->ops;
        struct dvb_tuner_ops    *tuner_ops = &frontend_ops->tuner_ops;
-       struct tuner_state      t_state;
        int err = 0;
 
-       if (tuner_ops->get_state) {
-               err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state);
+       if (tuner_ops->get_frequency) {
+               err = tuner_ops->get_frequency(fe, frequency);
                if (err < 0) {
                        printk("%s: Invalid parameter\n", __func__);
                        return err;
                }
-               *frequency = t_state.frequency;
        }
        return 0;
 }
@@ -41,13 +42,16 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
 {
        struct dvb_frontend_ops *frontend_ops = &fe->ops;
        struct dvb_tuner_ops    *tuner_ops = &frontend_ops->tuner_ops;
-       struct tuner_state      t_state;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u32 bw = c->bandwidth_hz;
        int err = 0;
 
-       t_state.frequency = frequency;
+       c->frequency = frequency;
+       c->bandwidth_hz = 0;            /* Don't adjust the bandwidth */
 
-       if (tuner_ops->set_state) {
-               err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state);
+       if (tuner_ops->set_params) {
+               err = tuner_ops->set_params(fe);
+               c->bandwidth_hz = bw;
                if (err < 0) {
                        printk("%s: Invalid parameter\n", __func__);
                        return err;
@@ -60,16 +64,14 @@ static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
 {
        struct dvb_frontend_ops *frontend_ops = &fe->ops;
        struct dvb_tuner_ops    *tuner_ops = &frontend_ops->tuner_ops;
-       struct tuner_state      t_state;
        int err = 0;
 
-       if (tuner_ops->get_state) {
-               err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state);
+       if (tuner_ops->get_bandwidth) {
+               err = tuner_ops->get_bandwidth(fe, bandwidth);
                if (err < 0) {
                        printk("%s: Invalid parameter\n", __func__);
                        return err;
                }
-               *bandwidth = t_state.bandwidth;
        }
        return 0;
 }
@@ -78,13 +80,16 @@ static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
 {
        struct dvb_frontend_ops *frontend_ops = &fe->ops;
        struct dvb_tuner_ops    *tuner_ops = &frontend_ops->tuner_ops;
-       struct tuner_state      t_state;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u32 freq = c->frequency;
        int err = 0;
 
-       t_state.bandwidth = bandwidth;
+       c->bandwidth_hz = bandwidth;
+       c->frequency = 0;               /* Don't adjust the frequency */
 
-       if (tuner_ops->set_state) {
-               err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state);
+       if (tuner_ops->set_params) {
+               err = tuner_ops->set_params(fe);
+               c->frequency = freq;
                if (err < 0) {
                        printk("%s: Invalid parameter\n", __func__);
                        return err;
index bd8a0ec9e2cce19cb35813f761c1c03a7fa338ed..50ffa21e387116976874b20a2c7befe9f9472da6 100644 (file)
        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
 static int stb6100_get_freq(struct dvb_frontend *fe, u32 *frequency)
 {
        struct dvb_frontend_ops *frontend_ops = &fe->ops;
        struct dvb_tuner_ops    *tuner_ops = &frontend_ops->tuner_ops;
-       struct tuner_state      state;
        int err = 0;
 
-       if (tuner_ops->get_state) {
+       if (tuner_ops->get_frequency) {
                if (frontend_ops->i2c_gate_ctrl)
                        frontend_ops->i2c_gate_ctrl(fe, 1);
 
-               err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &state);
+               err = tuner_ops->get_frequency(fe, frequency);
                if (err < 0) {
-                       printk(KERN_ERR "%s: Invalid parameter\n", __func__);
+                       printk("%s: Invalid parameter\n", __func__);
                        return err;
                }
 
                if (frontend_ops->i2c_gate_ctrl)
                        frontend_ops->i2c_gate_ctrl(fe, 0);
-
-               *frequency = state.frequency;
        }
 
        return 0;
@@ -47,18 +47,21 @@ static int stb6100_set_freq(struct dvb_frontend *fe, u32 frequency)
 {
        struct dvb_frontend_ops *frontend_ops = &fe->ops;
        struct dvb_tuner_ops    *tuner_ops = &frontend_ops->tuner_ops;
-       struct tuner_state      state;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u32 bw = c->bandwidth_hz;
        int err = 0;
 
-       state.frequency = frequency;
+       c->frequency = frequency;
+       c->bandwidth_hz = 0;            /* Don't adjust the bandwidth */
 
-       if (tuner_ops->set_state) {
+       if (tuner_ops->set_params) {
                if (frontend_ops->i2c_gate_ctrl)
                        frontend_ops->i2c_gate_ctrl(fe, 1);
 
-               err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &state);
+               err = tuner_ops->set_params(fe);
+               c->bandwidth_hz = bw;
                if (err < 0) {
-                       printk(KERN_ERR "%s: Invalid parameter\n", __func__);
+                       printk("%s: Invalid parameter\n", __func__);
                        return err;
                }
 
@@ -74,14 +77,13 @@ static int stb6100_get_bandw(struct dvb_frontend *fe, u32 *bandwidth)
 {
        struct dvb_frontend_ops *frontend_ops = &fe->ops;
        struct dvb_tuner_ops    *tuner_ops = &frontend_ops->tuner_ops;
-       struct tuner_state      state;
        int err = 0;
 
-       if (tuner_ops->get_state) {
+       if (tuner_ops->get_bandwidth) {
                if (frontend_ops->i2c_gate_ctrl)
                        frontend_ops->i2c_gate_ctrl(fe, 1);
 
-               err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &state);
+               err = tuner_ops->get_bandwidth(fe, bandwidth);
                if (err < 0) {
                        printk(KERN_ERR "%s: Invalid parameter\n", __func__);
                        return err;
@@ -89,8 +91,6 @@ static int stb6100_get_bandw(struct dvb_frontend *fe, u32 *bandwidth)
 
                if (frontend_ops->i2c_gate_ctrl)
                        frontend_ops->i2c_gate_ctrl(fe, 0);
-
-               *bandwidth = state.bandwidth;
        }
 
        return 0;
@@ -100,16 +100,19 @@ static int stb6100_set_bandw(struct dvb_frontend *fe, u32 bandwidth)
 {
        struct dvb_frontend_ops *frontend_ops = &fe->ops;
        struct dvb_tuner_ops    *tuner_ops = &frontend_ops->tuner_ops;
-       struct tuner_state      state;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u32 freq = c->frequency;
        int err = 0;
 
-       state.bandwidth = bandwidth;
+       c->bandwidth_hz = bandwidth;
+       c->frequency = 0;               /* Don't adjust the frequency */
 
-       if (tuner_ops->set_state) {
+       if (tuner_ops->set_params) {
                if (frontend_ops->i2c_gate_ctrl)
                        frontend_ops->i2c_gate_ctrl(fe, 1);
 
-               err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &state);
+               err = tuner_ops->set_params(fe);
+               c->frequency = freq;
                if (err < 0) {
                        printk(KERN_ERR "%s: Invalid parameter\n", __func__);
                        return err;
index 63cc12378d9aac4cfc7c2ad23be3e851ce9e361e..82f8cc534f3399633a0c19a170046c989e061913 100644 (file)
@@ -66,26 +66,13 @@ exit:
        return err;
 }
 
-static int tda665x_get_state(struct dvb_frontend *fe,
-                            enum tuner_param param,
-                            struct tuner_state *tstate)
+static int tda665x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
        struct tda665x_state *state = fe->tuner_priv;
-       int err = 0;
 
-       switch (param) {
-       case DVBFE_TUNER_FREQUENCY:
-               tstate->frequency = state->frequency;
-               break;
-       case DVBFE_TUNER_BANDWIDTH:
-               break;
-       default:
-               printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param);
-               err = -EINVAL;
-               break;
-       }
+       *frequency = state->frequency;
 
-       return err;
+       return 0;
 }
 
 static int tda665x_get_status(struct dvb_frontend *fe, u32 *status)
@@ -111,9 +98,8 @@ exit:
        return err;
 }
 
-static int tda665x_set_state(struct dvb_frontend *fe,
-                            enum tuner_param param,
-                            struct tuner_state *tstate)
+static int tda665x_set_frequency(struct dvb_frontend *fe,
+                                u32 new_frequency)
 {
        struct tda665x_state *state = fe->tuner_priv;
        const struct tda665x_config *config = state->config;
@@ -121,88 +107,96 @@ static int tda665x_set_state(struct dvb_frontend *fe,
        u8 buf[4];
        int err = 0;
 
-       if (param & DVBFE_TUNER_FREQUENCY) {
-
-               frequency = tstate->frequency;
-               if ((frequency < config->frequency_max) || (frequency > config->frequency_min)) {
-                       printk(KERN_ERR "%s: Frequency beyond limits, frequency=%d\n", __func__, frequency);
-                       return -EINVAL;
-               }
-
-               frequency += config->frequency_offst;
-               frequency *= config->ref_multiplier;
-               frequency += config->ref_divider >> 1;
-               frequency /= config->ref_divider;
-
-               buf[0] = (u8) ((frequency & 0x7f00) >> 8);
-               buf[1] = (u8) (frequency & 0x00ff) >> 0;
-               buf[2] = 0x80 | 0x40 | 0x02;
-               buf[3] = 0x00;
-
-               /* restore frequency */
-               frequency = tstate->frequency;
-
-               if (frequency < 153000000) {
-                       /* VHF-L */
-                       buf[3] |= 0x01; /* fc, Low Band, 47 - 153 MHz */
-                       if (frequency < 68000000)
-                               buf[3] |= 0x40; /* 83uA */
-                       if (frequency < 1040000000)
-                               buf[3] |= 0x60; /* 122uA */
-                       if (frequency < 1250000000)
-                               buf[3] |= 0x80; /* 163uA */
-                       else
-                               buf[3] |= 0xa0; /* 254uA */
-               } else if (frequency < 438000000) {
-                       /* VHF-H */
-                       buf[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */
-                       if (frequency < 230000000)
-                               buf[3] |= 0x40;
-                       if (frequency < 300000000)
-                               buf[3] |= 0x60;
-                       else
-                               buf[3] |= 0x80;
-               } else {
-                       /* UHF */
-                       buf[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */
-                       if (frequency < 470000000)
-                               buf[3] |= 0x60;
-                       if (frequency < 526000000)
-                               buf[3] |= 0x80;
-                       else
-                               buf[3] |= 0xa0;
-               }
-
-               /* Set params */
-               err = tda665x_write(state, buf, 5);
-               if (err < 0)
-                       goto exit;
-
-               /* sleep for some time */
-               printk(KERN_DEBUG "%s: Waiting to Phase LOCK\n", __func__);
-               msleep(20);
-               /* check status */
-               err = tda665x_get_status(fe, &status);
-               if (err < 0)
-                       goto exit;
-
-               if (status == 1) {
-                       printk(KERN_DEBUG "%s: Tuner Phase locked: status=%d\n", __func__, status);
-                       state->frequency = frequency; /* cache successful state */
-               } else {
-                       printk(KERN_ERR "%s: No Phase lock: status=%d\n", __func__, status);
-               }
-       } else {
-               printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param);
+       if ((new_frequency < config->frequency_max)
+           || (new_frequency > config->frequency_min)) {
+               printk(KERN_ERR "%s: Frequency beyond limits, frequency=%d\n",
+                      __func__, new_frequency);
                return -EINVAL;
        }
 
+       frequency = new_frequency;
+
+       frequency += config->frequency_offst;
+       frequency *= config->ref_multiplier;
+       frequency += config->ref_divider >> 1;
+       frequency /= config->ref_divider;
+
+       buf[0] = (u8) ((frequency & 0x7f00) >> 8);
+       buf[1] = (u8) (frequency & 0x00ff) >> 0;
+       buf[2] = 0x80 | 0x40 | 0x02;
+       buf[3] = 0x00;
+
+       /* restore frequency */
+       frequency = new_frequency;
+
+       if (frequency < 153000000) {
+               /* VHF-L */
+               buf[3] |= 0x01; /* fc, Low Band, 47 - 153 MHz */
+               if (frequency < 68000000)
+                       buf[3] |= 0x40; /* 83uA */
+               if (frequency < 1040000000)
+                       buf[3] |= 0x60; /* 122uA */
+               if (frequency < 1250000000)
+                       buf[3] |= 0x80; /* 163uA */
+               else
+                       buf[3] |= 0xa0; /* 254uA */
+       } else if (frequency < 438000000) {
+               /* VHF-H */
+               buf[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */
+               if (frequency < 230000000)
+                       buf[3] |= 0x40;
+               if (frequency < 300000000)
+                       buf[3] |= 0x60;
+               else
+                       buf[3] |= 0x80;
+       } else {
+               /* UHF */
+               buf[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */
+               if (frequency < 470000000)
+                       buf[3] |= 0x60;
+               if (frequency < 526000000)
+                       buf[3] |= 0x80;
+               else
+                       buf[3] |= 0xa0;
+       }
+
+       /* Set params */
+       err = tda665x_write(state, buf, 5);
+       if (err < 0)
+               goto exit;
+
+       /* sleep for some time */
+       printk(KERN_DEBUG "%s: Waiting to Phase LOCK\n", __func__);
+       msleep(20);
+       /* check status */
+       err = tda665x_get_status(fe, &status);
+       if (err < 0)
+               goto exit;
+
+       if (status == 1) {
+               printk(KERN_DEBUG "%s: Tuner Phase locked: status=%d\n",
+                      __func__, status);
+               state->frequency = frequency; /* cache successful state */
+       } else {
+               printk(KERN_ERR "%s: No Phase lock: status=%d\n",
+                      __func__, status);
+       }
+
        return 0;
 exit:
        printk(KERN_ERR "%s: I/O Error\n", __func__);
        return err;
 }
 
+static int tda665x_set_params(struct dvb_frontend *fe)
+{
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+       tda665x_set_frequency(fe, c->frequency);
+
+       return 0;
+}
+
 static int tda665x_release(struct dvb_frontend *fe)
 {
        struct tda665x_state *state = fe->tuner_priv;
@@ -213,10 +207,9 @@ static int tda665x_release(struct dvb_frontend *fe)
 }
 
 static struct dvb_tuner_ops tda665x_ops = {
-
-       .set_state      = tda665x_set_state,
-       .get_state      = tda665x_get_state,
        .get_status     = tda665x_get_status,
+       .set_params     = tda665x_set_params,
+       .get_frequency  = tda665x_get_frequency,
        .release        = tda665x_release
 };
 
index 19c488814e5c78e5b7e87e78419190d8e40faa11..3285b1bc46427476dff902d0113a83ff4ef0098d 100644 (file)
@@ -83,88 +83,71 @@ static int tda8261_get_status(struct dvb_frontend *fe, u32 *status)
 static const u32 div_tab[] = { 2000, 1000,  500,  250,  125 }; /* kHz */
 static const u8  ref_div[] = { 0x00, 0x01, 0x02, 0x05, 0x07 };
 
-static int tda8261_get_state(struct dvb_frontend *fe,
-                            enum tuner_param param,
-                            struct tuner_state *tstate)
+static int tda8261_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
        struct tda8261_state *state = fe->tuner_priv;
-       int err = 0;
 
-       switch (param) {
-       case DVBFE_TUNER_FREQUENCY:
-               tstate->frequency = state->frequency;
-               break;
-       case DVBFE_TUNER_BANDWIDTH:
-               tstate->bandwidth = 40000000; /* FIXME! need to calculate Bandwidth */
-               break;
-       default:
-               pr_err("%s: Unknown parameter (param=%d)\n", __func__, param);
-               err = -EINVAL;
-               break;
-       }
+       *frequency = state->frequency;
 
-       return err;
+       return 0;
 }
 
-static int tda8261_set_state(struct dvb_frontend *fe,
-                            enum tuner_param param,
-                            struct tuner_state *tstate)
+static int tda8261_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct tda8261_state *state = fe->tuner_priv;
        const struct tda8261_config *config = state->config;
        u32 frequency, N, status = 0;
        u8 buf[4];
        int err = 0;
 
-       if (param & DVBFE_TUNER_FREQUENCY) {
-               /**
-                * N = Max VCO Frequency / Channel Spacing
-                * Max VCO Frequency = VCO frequency + (channel spacing - 1)
-                * (to account for half channel spacing on either side)
-                */
-               frequency = tstate->frequency;
-               if ((frequency < 950000) || (frequency > 2150000)) {
-                       pr_warn("%s: Frequency beyond limits, frequency=%d\n", __func__, frequency);
-                       return -EINVAL;
-               }
-               N = (frequency + (div_tab[config->step_size] - 1)) / div_tab[config->step_size];
-               pr_debug("%s: Step size=%d, Divider=%d, PG=0x%02x (%d)\n",
-                       __func__, config->step_size, div_tab[config->step_size], N, N);
-
-               buf[0] = (N >> 8) & 0xff;
-               buf[1] = N & 0xff;
-               buf[2] = (0x01 << 7) | ((ref_div[config->step_size] & 0x07) << 1);
-
-               if (frequency < 1450000)
-                       buf[3] = 0x00;
-               else if (frequency < 2000000)
-                       buf[3] = 0x40;
-               else if (frequency < 2150000)
-                       buf[3] = 0x80;
-
-               /* Set params */
-               if ((err = tda8261_write(state, buf)) < 0) {
-                       pr_err("%s: I/O Error\n", __func__);
-                       return err;
-               }
-               /* sleep for some time */
-               pr_debug("%s: Waiting to Phase LOCK\n", __func__);
-               msleep(20);
-               /* check status */
-               if ((err = tda8261_get_status(fe, &status)) < 0) {
-                       pr_err("%s: I/O Error\n", __func__);
-                       return err;
-               }
-               if (status == 1) {
-                       pr_debug("%s: Tuner Phase locked: status=%d\n", __func__, status);
-                       state->frequency = frequency; /* cache successful state */
-               } else {
-                       pr_debug("%s: No Phase lock: status=%d\n", __func__, status);
-               }
-       } else {
-               pr_err("%s: Unknown parameter (param=%d)\n", __func__, param);
+       /*
+        * N = Max VCO Frequency / Channel Spacing
+        * Max VCO Frequency = VCO frequency + (channel spacing - 1)
+        * (to account for half channel spacing on either side)
+        */
+       frequency = c->frequency;
+       if ((frequency < 950000) || (frequency > 2150000)) {
+               pr_warn("%s: Frequency beyond limits, frequency=%d\n",
+                       __func__, frequency);
                return -EINVAL;
        }
+       N = (frequency + (div_tab[config->step_size] - 1)) / div_tab[config->step_size];
+       pr_debug("%s: Step size=%d, Divider=%d, PG=0x%02x (%d)\n",
+               __func__, config->step_size, div_tab[config->step_size], N, N);
+
+       buf[0] = (N >> 8) & 0xff;
+       buf[1] = N & 0xff;
+       buf[2] = (0x01 << 7) | ((ref_div[config->step_size] & 0x07) << 1);
+
+       if (frequency < 1450000)
+               buf[3] = 0x00;
+       else if (frequency < 2000000)
+               buf[3] = 0x40;
+       else if (frequency < 2150000)
+               buf[3] = 0x80;
+
+       /* Set params */
+       err = tda8261_write(state, buf);
+       if (err < 0) {
+               pr_err("%s: I/O Error\n", __func__);
+               return err;
+       }
+       /* sleep for some time */
+       pr_debug("%s: Waiting to Phase LOCK\n", __func__);
+       msleep(20);
+       /* check status */
+       if ((err = tda8261_get_status(fe, &status)) < 0) {
+               pr_err("%s: I/O Error\n", __func__);
+               return err;
+       }
+       if (status == 1) {
+               pr_debug("%s: Tuner Phase locked: status=%d\n", __func__,
+                        status);
+               state->frequency = frequency; /* cache successful state */
+       } else {
+               pr_debug("%s: No Phase lock: status=%d\n", __func__, status);
+       }
 
        return 0;
 }
@@ -182,14 +165,13 @@ static struct dvb_tuner_ops tda8261_ops = {
 
        .info = {
                .name           = "TDA8261",
-//             .tuner_name     = NULL,
                .frequency_min  =  950000,
                .frequency_max  = 2150000,
                .frequency_step = 0
        },
 
-       .set_state      = tda8261_set_state,
-       .get_state      = tda8261_get_state,
+       .set_params     = tda8261_set_params,
+       .get_frequency  = tda8261_get_frequency,
        .get_status     = tda8261_get_status,
        .release        = tda8261_release
 };
@@ -210,10 +192,7 @@ struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
        fe->ops.tuner_ops       = tda8261_ops;
 
        fe->ops.tuner_ops.info.frequency_step = div_tab[config->step_size];
-//     fe->ops.tuner_ops.tuner_name     = &config->buf;
 
-//     printk("%s: Attaching %s TDA8261 8PSK/QPSK tuner\n",
-//             __func__, fe->ops.tuner_ops.tuner_name);
        pr_info("%s: Attaching TDA8261 8PSK/QPSK tuner\n", __func__);
 
        return fe;
index 04a19e14ee5a41e82dd22e9c2ae07978d142cecc..fe527ff84df481fa7a7658191a5ccd1d2b33183f 100644 (file)
@@ -21,17 +21,15 @@ static int tda8261_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
        struct dvb_frontend_ops *frontend_ops = &fe->ops;
        struct dvb_tuner_ops    *tuner_ops = &frontend_ops->tuner_ops;
-       struct tuner_state      t_state;
        int err = 0;
 
-       if (tuner_ops->get_state) {
-               err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state);
+       if (tuner_ops->get_frequency) {
+               err = tuner_ops->get_frequency(fe, frequency);
                if (err < 0) {
-                       printk("%s: Invalid parameter\n", __func__);
+                       pr_err("%s: Invalid parameter\n", __func__);
                        return err;
                }
-               *frequency = t_state.frequency;
-               printk("%s: Frequency=%d\n", __func__, t_state.frequency);
+               pr_debug("%s: Frequency=%d\n", __func__, *frequency);
        }
        return 0;
 }
@@ -40,37 +38,24 @@ static int tda8261_set_frequency(struct dvb_frontend *fe, u32 frequency)
 {
        struct dvb_frontend_ops *frontend_ops = &fe->ops;
        struct dvb_tuner_ops    *tuner_ops = &frontend_ops->tuner_ops;
-       struct tuner_state      t_state;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int err = 0;
 
-       t_state.frequency = frequency;
-
-       if (tuner_ops->set_state) {
-               err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state);
+       if (tuner_ops->set_params) {
+               err = tuner_ops->set_params(fe);
                if (err < 0) {
-                       printk("%s: Invalid parameter\n", __func__);
+                       pr_err("%s: Invalid parameter\n", __func__);
                        return err;
                }
        }
-       printk("%s: Frequency=%d\n", __func__, t_state.frequency);
+       pr_debug("%s: Frequency=%d\n", __func__, c->frequency);
        return 0;
 }
 
 static int tda8261_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
 {
-       struct dvb_frontend_ops *frontend_ops = &fe->ops;
-       struct dvb_tuner_ops    *tuner_ops = &frontend_ops->tuner_ops;
-       struct tuner_state      t_state;
-       int err = 0;
+       /* FIXME! need to calculate Bandwidth */
+       *bandwidth = 40000000;
 
-       if (tuner_ops->get_state) {
-               err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state);
-               if (err < 0) {
-                       printk("%s: Invalid parameter\n", __func__);
-                       return err;
-               }
-               *bandwidth = t_state.bandwidth;
-               printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
-       }
        return 0;
 }
index 17750985db0cacfc15af5ccec345a8b4ee91dede..2b9e8732c8024d30fe263bbe7e82ed1fb1f141cb 100644 (file)
@@ -20,7 +20,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * The project's page is at http://www.linuxtv.org
+ * The project's page is at https://linuxtv.org
  */
 
 #ifndef TDHD1_H
index 521bbf1b29bc574350320a20113a2d40d8d1a455..993dc50c12db487a50566c700b058b0b47ca50f3 100644 (file)
@@ -83,6 +83,16 @@ config VIDEO_MSP3400
          To compile this driver as a module, choose M here: the
          module will be called msp3400.
 
+config VIDEO_CS3308
+       tristate "Cirrus Logic CS3308 audio ADC"
+       depends on VIDEO_V4L2 && I2C
+       ---help---
+         Support for the Cirrus Logic CS3308 High Performance 8-Channel
+         Analog Volume Control
+
+         To compile this driver as a module, choose M here: the
+         module will be called cs3308.
+
 config VIDEO_CS5345
        tristate "Cirrus Logic CS5345 audio ADC"
        depends on VIDEO_V4L2 && I2C
index 07db257abfc1aa7ad4796afdbeac170321894e32..94f2c99e890da8f23b7638d821e98b321280bcd5 100644 (file)
@@ -43,6 +43,7 @@ obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o
 obj-$(CONFIG_VIDEO_TW2804) += tw2804.o
 obj-$(CONFIG_VIDEO_TW9903) += tw9903.o
 obj-$(CONFIG_VIDEO_TW9906) += tw9906.o
+obj-$(CONFIG_VIDEO_CS3308) += cs3308.o
 obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
 obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
 obj-$(CONFIG_VIDEO_M52790) += m52790.o
index 69094ab047b1d955040f6f6e2a7afd10287fec6c..0494a7896aa21916bb28ac98988371cc3c46b92e 100644 (file)
@@ -35,7 +35,7 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-dv-timings.h>
 #include <media/v4l2-ctrls.h>
-#include <media/ad9389b.h>
+#include <media/i2c/ad9389b.h>
 
 static int debug;
 module_param(debug, int, 0644);
index 5dd39775d6ca5c449c1b496c90a275ba6ba9118a..f00745bbe471fe0019552c2b54622530af50c12b 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/gpio/consumer.h>
-#include <media/adp1653.h>
+#include <media/i2c/adp1653.h>
 #include <media/v4l2-device.h>
 
 #define TIMEOUT_MAX            820000
index f82c8aa164fa8266a73a647820a02a9ab56fc964..3c3c4bfe386644a7afda9d1ecebd1b891737d202 100644 (file)
@@ -1112,7 +1112,7 @@ static int init_device(struct adv7180_state *state)
        mutex_lock(&state->mutex);
 
        adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES);
-       usleep_range(2000, 10000);
+       usleep_range(5000, 10000);
 
        ret = state->chip_info->init(state);
        if (ret)
index e2dd1617662fb0042f4820cdf95022b371bff786..2bec737881e9fbbfaa54a20cd62e4cf9a54f22d4 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/types.h>
 #include <linux/videodev2.h>
 
-#include <media/adv7183.h>
+#include <media/i2c/adv7183.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 
index f89d0afcd964046b6238c41e1a139011cdbd2a50..11f9029433cf00d95855760567353f5d779229b2 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/of.h>
 #include <linux/of_graph.h>
 
-#include <media/adv7343.h>
+#include <media/i2c/adv7343.h>
 #include <media/v4l2-async.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
index 0215f95c22454b5a830c4519a01a4e63e0b8ff76..76d987476e355b896913c3ebbbd4f9960cdcdbac 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/videodev2.h>
 #include <linux/uaccess.h>
 
-#include <media/adv7393.h>
+#include <media/i2c/adv7393.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
 
index e4900df1140b9b10a729570aa075943e4beccee3..eeb2cd823c4d1fe0d40aa7c5e57c08bab3f56cec 100644 (file)
@@ -32,7 +32,7 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-dv-timings.h>
-#include <media/adv7511.h>
+#include <media/i2c/adv7511.h>
 
 static int debug;
 module_param(debug, int, 0644);
@@ -1116,7 +1116,7 @@ static int adv7511_set_fmt(struct v4l2_subdev *sd,
        adv7511_wr_and_or(sd, 0x55, 0x9f, y << 5);
        adv7511_wr_and_or(sd, 0x56, 0x3f, c << 6);
        adv7511_wr_and_or(sd, 0x57, 0x83, (ec << 4) | (q << 2));
-       adv7511_wr_and_or(sd, 0x59, 0x0f, yq << 4);
+       adv7511_wr_and_or(sd, 0x59, 0x3f, yq << 6);
        adv7511_wr_and_or(sd, 0x4a, 0xff, 1);
 
        return 0;
index 5631ec004eedb8a5c91a758d20ab1c9351e512bf..7452862256558765e2ff5865593471bc3f07aea6 100644 (file)
@@ -39,7 +39,7 @@
 #include <linux/workqueue.h>
 #include <linux/regmap.h>
 
-#include <media/adv7604.h>
+#include <media/i2c/adv7604.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-event.h>
@@ -905,7 +905,7 @@ static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd,
 
        for (i = 0; predef_vid_timings[i].timings.bt.width; i++) {
                if (!v4l2_match_dv_timings(timings, &predef_vid_timings[i].timings,
-                                       is_digital_input(sd) ? 250000 : 1000000))
+                               is_digital_input(sd) ? 250000 : 1000000, false))
                        continue;
                io_write(sd, 0x00, predef_vid_timings[i].vid_std); /* video std */
                io_write(sd, 0x01, (predef_vid_timings[i].v_freq << 4) +
@@ -1479,7 +1479,7 @@ static void adv76xx_fill_optional_dv_timings_fields(struct v4l2_subdev *sd,
 
        for (i = 0; adv76xx_timings[i].bt.width; i++) {
                if (v4l2_match_dv_timings(timings, &adv76xx_timings[i],
-                                       is_digital_input(sd) ? 250000 : 1000000)) {
+                               is_digital_input(sd) ? 250000 : 1000000, false)) {
                        *timings = adv76xx_timings[i];
                        break;
                }
@@ -1644,7 +1644,7 @@ static int adv76xx_s_dv_timings(struct v4l2_subdev *sd,
        if (!timings)
                return -EINVAL;
 
-       if (v4l2_match_dv_timings(&state->timings, timings, 0)) {
+       if (v4l2_match_dv_timings(&state->timings, timings, 0, false)) {
                v4l2_dbg(1, debug, sd, "%s: no change\n", __func__);
                return 0;
        }
index b7269b8f040d741f93fa218a6fbe1634cd7c5be9..69378e4914b62068fbcca3919200f83768b35ada 100644 (file)
@@ -43,7 +43,7 @@
 #include <media/v4l2-event.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-dv-timings.h>
-#include <media/adv7842.h>
+#include <media/i2c/adv7842.h>
 
 static int debug;
 module_param(debug, int, 0644);
@@ -155,7 +155,7 @@ static bool adv7842_check_dv_timings(const struct v4l2_dv_timings *t, void *hdl)
        int i;
 
        for (i = 0; adv7842_timings_exceptions[i].bt.width; i++)
-               if (v4l2_match_dv_timings(t, adv7842_timings_exceptions + i, 0))
+               if (v4l2_match_dv_timings(t, adv7842_timings_exceptions + i, 0, false))
                        return false;
        return true;
 }
@@ -1008,7 +1008,7 @@ static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd,
 
        for (i = 0; predef_vid_timings[i].timings.bt.width; i++) {
                if (!v4l2_match_dv_timings(timings, &predef_vid_timings[i].timings,
-                                         is_digital_input(sd) ? 250000 : 1000000))
+                                 is_digital_input(sd) ? 250000 : 1000000, false))
                        continue;
                /* video std */
                io_write(sd, 0x00, predef_vid_timings[i].vid_std);
@@ -1659,7 +1659,7 @@ static int adv7842_s_dv_timings(struct v4l2_subdev *sd,
        if (state->mode == ADV7842_MODE_SDP)
                return -ENODATA;
 
-       if (v4l2_match_dv_timings(&state->timings, timings, 0)) {
+       if (v4l2_match_dv_timings(&state->timings, timings, 0, false)) {
                v4l2_dbg(1, debug, sd, "%s: no change\n", __func__);
                return 0;
        }
index d3b965ec3bbc5597245a9df0eb9d415bb376993e..d9f2b6b76d5950896bbd87c7d024b1029cd0376b 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/videodev2.h>
 #include <linux/module.h>
 
-#include <media/ak881x.h>
+#include <media/i2c/ak881x.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
 
index 301084b07887e9e13fa11b7772ff81dd85ed553e..29a2e7034aa60a8816314ef4f4db92181746d6c3 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/mutex.h>
 #include <linux/slab.h>
 
-#include <media/as3645a.h>
+#include <media/i2c/as3645a.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 
index e00e3104d4483339bcf2b70dca81c87fddc6e1e4..7907bcfbaed33a020cddf349106b0aba6071a3a7 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
-#include <media/bt819.h>
+#include <media/i2c/bt819.h>
 
 MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
 MODULE_AUTHOR("Mike Bernson & Dave Perks");
diff --git a/drivers/media/i2c/cs3308.c b/drivers/media/i2c/cs3308.c
new file mode 100644 (file)
index 0000000..d28b4f3
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Cirrus Logic cs3308 8-Channel Analog Volume Control
+ *
+ * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
+ * Copyright (C) 2012 Steven Toth <stoth@kernellabs.com>
+ *
+ * Derived from cs5345.c Copyright (C) 2007 Hans Verkuil
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+
+MODULE_DESCRIPTION("i2c device driver for cs3308 8-channel volume control");
+MODULE_AUTHOR("Devin Heitmueller");
+MODULE_LICENSE("GPL");
+
+static inline int cs3308_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static inline int cs3308_read(struct v4l2_subdev *sd, u8 reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return i2c_smbus_read_byte_data(client, reg);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int cs3308_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+       reg->val = cs3308_read(sd, reg->reg & 0xffff);
+       reg->size = 1;
+       return 0;
+}
+
+static int cs3308_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
+{
+       cs3308_write(sd, reg->reg & 0xffff, reg->val & 0xff);
+       return 0;
+}
+#endif
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops cs3308_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = cs3308_g_register,
+       .s_register = cs3308_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_ops cs3308_ops = {
+       .core = &cs3308_core_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int cs3308_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct v4l2_subdev *sd;
+       unsigned i;
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EIO;
+
+       if ((i2c_smbus_read_byte_data(client, 0x1c) & 0xf0) != 0xe0)
+               return -ENODEV;
+
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                client->addr << 1, client->adapter->name);
+
+       sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+       if (sd == NULL)
+               return -ENOMEM;
+
+       v4l2_i2c_subdev_init(sd, client, &cs3308_ops);
+
+       /* Set some reasonable defaults */
+       cs3308_write(sd, 0x0d, 0x00); /* Power up all channels */
+       cs3308_write(sd, 0x0e, 0x00); /* Master Power */
+       cs3308_write(sd, 0x0b, 0x00); /* Device Configuration */
+       /* Set volume for each channel */
+       for (i = 1; i <= 8; i++)
+               cs3308_write(sd, i, 0xd2);
+       cs3308_write(sd, 0x0a, 0x00); /* Unmute all channels */
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int cs3308_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(sd);
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id cs3308_id[] = {
+       { "cs3308", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, cs3308_id);
+
+static struct i2c_driver cs3308_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "cs3308",
+       },
+       .probe          = cs3308_probe,
+       .remove         = cs3308_remove,
+       .id_table       = cs3308_id,
+};
+
+module_i2c_driver(cs3308_driver);
index 34b96c7cfd620007b88a7082166413c284ac7a0e..baf3d9c8710e3066acc3b75ba4b2660b0b7ebd56 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
 #include <media/v4l2-common.h>
-#include <media/cx25840.h>
+#include <media/drv-intf/cx25840.h>
 
 #include "cx25840-core.h"
 
index fe6eb78b6914ee1915f426673d0ffeca79ce53d4..f2e2c34ddbbd25d105d72847b061276c8833914f 100644 (file)
@@ -45,7 +45,7 @@
 #include <linux/delay.h>
 #include <linux/math64.h>
 #include <media/v4l2-common.h>
-#include <media/cx25840.h>
+#include <media/drv-intf/cx25840.h>
 
 #include "cx25840-core.h"
 
@@ -559,7 +559,10 @@ static void cx23885_initialize(struct i2c_client *client)
        cx25840_write4(client, 0x414, 0x00107d12);
 
        /* Chroma */
-       cx25840_write4(client, 0x420, 0x3d008282);
+       if (is_cx23888(state))
+               cx25840_write4(client, 0x418, 0x1d008282);
+       else
+               cx25840_write4(client, 0x420, 0x3d008282);
 
        /*
         * Aux PLL
@@ -666,14 +669,17 @@ static void cx23885_initialize(struct i2c_client *client)
        cx25840_write4(client, 0x404, 0x0010253e);
 
        /* CC on  - Undocumented Register */
-       cx25840_write(client, 0x42f, 0x66);
+       cx25840_write(client, state->vbi_regs_offset + 0x42f, 0x66);
 
        /* HVR-1250 / HVR1850 DIF related */
        /* Power everything up */
        cx25840_write4(client, 0x130, 0x0);
 
        /* Undocumented */
-       cx25840_write4(client, 0x478, 0x6628021F);
+       if (is_cx23888(state))
+               cx25840_write4(client, 0x454, 0x6628021F);
+       else
+               cx25840_write4(client, 0x478, 0x6628021F);
 
        /* AFE_CLK_OUT_CTRL - Select the clock output source as output */
        cx25840_write4(client, 0x144, 0x5);
@@ -1106,31 +1112,15 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
                        cx25840_write4(client, 0x410, 0xffff0dbf);
                        cx25840_write4(client, 0x414, 0x00137d03);
 
-                       /* on the 887, 0x418 is HSCALE_CTRL, on the 888 it is 
-                          CHROMA_CTRL */
-                       if (is_cx23888(state))
-                               cx25840_write4(client, 0x418, 0x01008080);
-                       else
-                               cx25840_write4(client, 0x418, 0x01000000);
+                       cx25840_write4(client, state->vbi_regs_offset + 0x42c, 0x42600000);
+                       cx25840_write4(client, state->vbi_regs_offset + 0x430, 0x0000039b);
+                       cx25840_write4(client, state->vbi_regs_offset + 0x438, 0x00000000);
 
-                       cx25840_write4(client, 0x41c, 0x00000000);
-
-                       /* on the 887, 0x420 is CHROMA_CTRL, on the 888 it is 
-                          CRUSH_CTRL */
-                       if (is_cx23888(state))
-                               cx25840_write4(client, 0x420, 0x001c3e0f);
-                       else
-                               cx25840_write4(client, 0x420, 0x001c8282);
-
-                       cx25840_write4(client, 0x42c, 0x42600000);
-                       cx25840_write4(client, 0x430, 0x0000039b);
-                       cx25840_write4(client, 0x438, 0x00000000);
-
-                       cx25840_write4(client, 0x440, 0xF8E3E824);
-                       cx25840_write4(client, 0x444, 0x401040dc);
-                       cx25840_write4(client, 0x448, 0xcd3f02a0);
-                       cx25840_write4(client, 0x44c, 0x161f1000);
-                       cx25840_write4(client, 0x450, 0x00000802);
+                       cx25840_write4(client, state->vbi_regs_offset + 0x440, 0xF8E3E824);
+                       cx25840_write4(client, state->vbi_regs_offset + 0x444, 0x401040dc);
+                       cx25840_write4(client, state->vbi_regs_offset + 0x448, 0xcd3f02a0);
+                       cx25840_write4(client, state->vbi_regs_offset + 0x44c, 0x161f1000);
+                       cx25840_write4(client, state->vbi_regs_offset + 0x450, 0x00000802);
 
                        cx25840_write4(client, 0x91c, 0x01000000);
                        cx25840_write4(client, 0x8e0, 0x03063870);
@@ -1400,8 +1390,14 @@ static int cx25840_set_fmt(struct v4l2_subdev *sd,
 
        Vlines = fmt->height + (is_50Hz ? 4 : 7);
 
+       /*
+        * We keep 1 margin for the Vsrc < Vlines check since the
+        * cx23888 reports a Vsrc of 486 instead of 487 for the NTSC
+        * height. Without that margin the cx23885 fails in this
+        * check.
+        */
        if ((fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) ||
-                       (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
+                       (Vlines * 8 < Vsrc) || (Vsrc + 1 < Vlines)) {
                v4l_err(client, "%dx%d is not a valid size!\n",
                                fmt->width, fmt->height);
                return -ERANGE;
@@ -1426,14 +1422,20 @@ static int cx25840_set_fmt(struct v4l2_subdev *sd,
                        fmt->width, fmt->height, HSC, VSC);
 
        /* HSCALE=HSC */
-       cx25840_write(client, 0x418, HSC & 0xff);
-       cx25840_write(client, 0x419, (HSC >> 8) & 0xff);
-       cx25840_write(client, 0x41a, HSC >> 16);
-       /* VSCALE=VSC */
-       cx25840_write(client, 0x41c, VSC & 0xff);
-       cx25840_write(client, 0x41d, VSC >> 8);
-       /* VS_INTRLACE=1 VFILT=filter */
-       cx25840_write(client, 0x41e, 0x8 | filter);
+       if (is_cx23888(state)) {
+               cx25840_write4(client, 0x434, HSC | (1 << 24));
+               /* VSCALE=VSC VS_INTRLACE=1 VFILT=filter */
+               cx25840_write4(client, 0x438, VSC | (1 << 19) | (filter << 16));
+       } else {
+               cx25840_write(client, 0x418, HSC & 0xff);
+               cx25840_write(client, 0x419, (HSC >> 8) & 0xff);
+               cx25840_write(client, 0x41a, HSC >> 16);
+               /* VSCALE=VSC */
+               cx25840_write(client, 0x41c, VSC & 0xff);
+               cx25840_write(client, 0x41d, VSC >> 8);
+               /* VS_INTRLACE=1 VFILT=filter */
+               cx25840_write(client, 0x41e, 0x8 | filter);
+       }
        return 0;
 }
 
@@ -1714,26 +1716,27 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
 
        v4l_dbg(1, cx25840_debug, client, "%s video output\n",
                        enable ? "enable" : "disable");
+
+       /*
+        * It's not clear what should be done for these devices.
+        * The original code used the same addresses as for the cx25840, but
+        * those addresses do something else entirely on the cx2388x and
+        * cx231xx. Since it never did anything in the first place, just do
+        * nothing.
+        */
+       if (is_cx2388x(state) || is_cx231xx(state))
+               return 0;
+
        if (enable) {
-               if (is_cx2388x(state) || is_cx231xx(state)) {
-                       v = cx25840_read(client, 0x421) | 0x0b;
-                       cx25840_write(client, 0x421, v);
-               } else {
-                       v = cx25840_read(client, 0x115) | 0x0c;
-                       cx25840_write(client, 0x115, v);
-                       v = cx25840_read(client, 0x116) | 0x04;
-                       cx25840_write(client, 0x116, v);
-               }
+               v = cx25840_read(client, 0x115) | 0x0c;
+               cx25840_write(client, 0x115, v);
+               v = cx25840_read(client, 0x116) | 0x04;
+               cx25840_write(client, 0x116, v);
        } else {
-               if (is_cx2388x(state) || is_cx231xx(state)) {
-                       v = cx25840_read(client, 0x421) & ~(0x0b);
-                       cx25840_write(client, 0x421, v);
-               } else {
-                       v = cx25840_read(client, 0x115) & ~(0x0c);
-                       cx25840_write(client, 0x115, v);
-                       v = cx25840_read(client, 0x116) & ~(0x04);
-                       cx25840_write(client, 0x116, v);
-               }
+               v = cx25840_read(client, 0x115) & ~(0x0c);
+               cx25840_write(client, 0x115, v);
+               v = cx25840_read(client, 0x116) & ~(0x04);
+               cx25840_write(client, 0x116, v);
        }
        return 0;
 }
@@ -4974,7 +4977,7 @@ static void cx23888_std_setup(struct i2c_client *client)
        cx25840_write4(client, 0x4b4, 0x20524030);
        cx25840_write4(client, 0x47c, 0x010a8263);
 
-       if (std & V4L2_STD_NTSC) {
+       if (std & V4L2_STD_525_60) {
                v4l_dbg(1, cx25840_debug, client, "%s() Selecting NTSC",
                        __func__);
 
@@ -5264,6 +5267,8 @@ static int cx25840_probe(struct i2c_client *client,
        state->vbi_line_offset = 8;
        state->id = id;
        state->rev = device_id;
+       state->vbi_regs_offset = id == CX23888_AV ? 0x500 - 0x424 : 0;
+       state->std = V4L2_STD_NTSC_M;
        v4l2_ctrl_handler_init(&state->hdl, 9);
        v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
                        V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
index fdea48ce0c036253c9e3a443a361fdcc36e0b076..254ef45ce41a8fb0138a1deafbabed0cd6fa1e7b 100644 (file)
@@ -69,6 +69,7 @@ struct cx25840_state {
        enum cx25840_model id;
        u32 rev;
        int is_initialized;
+       unsigned vbi_regs_offset;
        wait_queue_head_t fw_wait;    /* wake up when the fw load is finished */
        struct work_struct fw_work;   /* work entry for fw load */
        struct cx25840_ir_state *ir_state;
index 9bbb31adc29da3b2ea371169a7d4ade88d84392d..37e052923a877d0097f23017acbc54824b58204f 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/i2c.h>
 #include <linux/firmware.h>
 #include <media/v4l2-common.h>
-#include <media/cx25840.h>
+#include <media/drv-intf/cx25840.h>
 
 #include "cx25840-core.h"
 
index 4cf8f18bf097bc3bb4ff7795fe77a608fade090b..4b782012cadc0ff3a090e2f9bf90a0e02722e527 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/slab.h>
 #include <linux/kfifo.h>
 #include <linux/module.h>
-#include <media/cx25840.h>
+#include <media/drv-intf/cx25840.h>
 #include <media/rc-core.h>
 
 #include "cx25840-core.h"
index c39e91dc113794b936fd484da0686a635724ff01..0470bb6128e1f320be078dbc70e303c6f0148a25 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
 #include <media/v4l2-common.h>
-#include <media/cx25840.h>
+#include <media/drv-intf/cx25840.h>
 
 #include "cx25840-core.h"
 
@@ -104,7 +104,8 @@ int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *
 
        if (is_pal) {
                for (i = 7; i <= 23; i++) {
-                       u8 v = cx25840_read(client, 0x424 + i - 7);
+                       u8 v = cx25840_read(client,
+                                state->vbi_regs_offset + 0x424 + i - 7);
 
                        svbi->service_lines[0][i] = lcr2vbi[v >> 4];
                        svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
@@ -113,7 +114,8 @@ int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *
                }
        } else {
                for (i = 10; i <= 21; i++) {
-                       u8 v = cx25840_read(client, 0x424 + i - 10);
+                       u8 v = cx25840_read(client,
+                               state->vbi_regs_offset + 0x424 + i - 10);
 
                        svbi->service_lines[0][i] = lcr2vbi[v >> 4];
                        svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
@@ -135,7 +137,10 @@ int cx25840_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
        cx25840_std_setup(client);
 
        /* VBI Offset */
-       cx25840_write(client, 0x47f, vbi_offset);
+       if (is_cx23888(state))
+               cx25840_write(client, 0x54f, vbi_offset);
+       else
+               cx25840_write(client, 0x47f, vbi_offset);
        cx25840_write(client, 0x404, 0x2e);
        return 0;
 }
@@ -158,7 +163,10 @@ int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *
        /* Sliced VBI */
        cx25840_write(client, 0x404, 0x32);     /* Ancillary data */
        cx25840_write(client, 0x406, 0x13);
-       cx25840_write(client, 0x47f, vbi_offset);
+       if (is_cx23888(state))
+               cx25840_write(client, 0x54f, vbi_offset);
+       else
+               cx25840_write(client, 0x47f, vbi_offset);
 
        if (is_pal) {
                for (i = 0; i <= 6; i++)
@@ -194,17 +202,23 @@ int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *
        }
 
        if (is_pal) {
-               for (x = 1, i = 0x424; i <= 0x434; i++, x++)
+               for (x = 1, i = state->vbi_regs_offset + 0x424;
+                    i <= state->vbi_regs_offset + 0x434; i++, x++)
                        cx25840_write(client, i, lcr[6 + x]);
        } else {
-               for (x = 1, i = 0x424; i <= 0x430; i++, x++)
+               for (x = 1, i = state->vbi_regs_offset + 0x424;
+                    i <= state->vbi_regs_offset + 0x430; i++, x++)
                        cx25840_write(client, i, lcr[9 + x]);
-               for (i = 0x431; i <= 0x434; i++)
+               for (i = state->vbi_regs_offset + 0x431;
+                    i <= state->vbi_regs_offset + 0x434; i++)
                        cx25840_write(client, i, 0);
        }
 
-       cx25840_write(client, 0x43c, 0x16);
-       cx25840_write(client, 0x474, is_pal ? 0x2a : 0x22);
+       cx25840_write(client, state->vbi_regs_offset + 0x43c, 0x16);
+       if (is_cx23888(state))
+               cx25840_write(client, 0x428, is_pal ? 0x2a : 0x22);
+       else
+               cx25840_write(client, 0x474, is_pal ? 0x2a : 0x22);
        return 0;
 }
 
index 728d2cc8a3e7dc3ebb09ab03e873d03885b23f4f..830491960add2d239d817e46db7c4f0d2dc8d00a 100644 (file)
@@ -47,7 +47,7 @@
 #include <linux/workqueue.h>
 
 #include <media/rc-core.h>
-#include <media/ir-kbd-i2c.h>
+#include <media/i2c/ir-kbd-i2c.h>
 
 /* ----------------------------------------------------------------------- */
 /* insmod parameters                                                       */
index d9ece4b2d047067dc19921e1e79a52fd80ad130e..19ecb88010647d95b7a22b739d54b4720eda162f 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/mutex.h>
 #include <linux/regmap.h>
 #include <linux/videodev2.h>
-#include <media/lm3560.h>
+#include <media/i2c/lm3560.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 
index 626fb4679c02f9669f77e84caa68f2451d062455..7fbe6ff1c4f4f74c96f0901a32f9a2a450960d3f 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/slab.h>
 #include <linux/regmap.h>
 #include <linux/videodev2.h>
-#include <media/lm3646.h>
+#include <media/i2c/lm3646.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 
index 77eb07eb667ee3ff237fd694226356c0ba8cd1f1..81171d8e1c2ccee651472024c78dc8ffe3e583d3 100644 (file)
@@ -27,7 +27,7 @@
 #include <asm/uaccess.h>
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
-#include <media/m52790.h>
+#include <media/i2c/m52790.h>
 #include <media/v4l2-device.h>
 
 MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch");
index 1a03d02bd4d1ab4ce9d1327e129a299eb49a4e22..a0cd6dc32eb0d75e55c58866686db9af87f31cf0 100644 (file)
@@ -25,8 +25,8 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-subdev.h>
-#include <media/m5mols.h>
-#include <media/exynos-fimc.h>
+#include <media/i2c/m5mols.h>
+#include <media/drv-intf/exynos-fimc.h>
 
 #include "m5mols.h"
 #include "m5mols_reg.h"
index 6404c0d93e7af9d95602bca1a2349faa355b674d..f8993933416e793954a175c7b648a6a290f4ead6 100644 (file)
@@ -25,7 +25,7 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-subdev.h>
-#include <media/m5mols.h>
+#include <media/i2c/m5mols.h>
 
 #include "m5mols.h"
 #include "m5mols_reg.h"
index bdb94000ba5a6c363779c2f069aae0d7f3dc01d6..a84561d0d4a809c761c5ed51d58af93aa7737dd7 100644 (file)
@@ -56,8 +56,8 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
-#include <media/msp3400.h>
-#include <media/tvaudio.h>
+#include <media/drv-intf/msp3400.h>
+#include <media/i2c/tvaudio.h>
 #include "msp3400-driver.h"
 
 /* ---------------------------------------------------------------------- */
index fbe5e0715f9309d0c76fce2ed61fb16d5614a512..6cae21366ed5e6b4ab7003dee04ba6504be05652 100644 (file)
@@ -4,7 +4,7 @@
 #ifndef MSP3400_DRIVER_H
 #define MSP3400_DRIVER_H
 
-#include <media/msp3400.h>
+#include <media/drv-intf/msp3400.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
 
index f8b51714f2f9ba7838a8cba3d039bf26a77b037e..17120804fab7376f4261235867bf9cea09702850 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/freezer.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
-#include <media/msp3400.h>
+#include <media/drv-intf/msp3400.h>
 #include <linux/kthread.h>
 #include <linux/suspend.h>
 #include "msp3400-driver.h"
index c7747bd0cabbcd9a53dfb754f5af626f916dc618..101cb26f9330e73e0e69fd16e782bb9d3b407e6d 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/v4l2-mediabus.h>
 
 #include <media/media-entity.h>
-#include <media/mt9m032.h>
+#include <media/i2c/mt9m032.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-subdev.h>
@@ -671,7 +671,7 @@ static int mt9m032_set_ctrl(struct v4l2_ctrl *ctrl)
        return 0;
 }
 
-static struct v4l2_ctrl_ops mt9m032_ctrl_ops = {
+static const struct v4l2_ctrl_ops mt9m032_ctrl_ops = {
        .s_ctrl = mt9m032_set_ctrl,
        .try_ctrl = mt9m032_try_ctrl,
 };
index 0db15f528ac1c252d5199b33db41d38c2535175d..a3da0e977d0b3590442d9be8dcd2384a4783c475 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 
-#include <media/mt9p031.h>
+#include <media/i2c/mt9p031.h>
 #include <media/v4l2-async.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
@@ -817,7 +817,7 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
        return 0;
 }
 
-static struct v4l2_ctrl_ops mt9p031_ctrl_ops = {
+static const struct v4l2_ctrl_ops mt9p031_ctrl_ops = {
        .s_ctrl = mt9p031_s_ctrl,
 };
 
index 8ae99f7f254caef7b16a792558d4299e5934e152..b28fdff1d3107d399ef6e0dce1e77875bead0183 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/videodev2.h>
 #include <linux/v4l2-mediabus.h>
 
-#include <media/mt9t001.h>
+#include <media/i2c/mt9t001.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-subdev.h>
@@ -626,7 +626,7 @@ static int mt9t001_s_ctrl(struct v4l2_ctrl *ctrl)
        return 0;
 }
 
-static struct v4l2_ctrl_ops mt9t001_ctrl_ops = {
+static const struct v4l2_ctrl_ops mt9t001_ctrl_ops = {
        .s_ctrl = mt9t001_s_ctrl,
 };
 
index a4a5c39b599bff3cf96d9f75aaeee1d7c66ccb6b..b9fea11d6b0b0e08ff2c4440f976a97a077aaa99 100644 (file)
@@ -13,7 +13,7 @@
 #include <asm/div64.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
-#include <media/mt9v011.h>
+#include <media/i2c/mt9v011.h>
 
 MODULE_DESCRIPTION("Micron mt9v011 sensor driver");
 MODULE_AUTHOR("Mauro Carvalho Chehab");
@@ -454,7 +454,7 @@ static int mt9v011_s_ctrl(struct v4l2_ctrl *ctrl)
        return 0;
 }
 
-static struct v4l2_ctrl_ops mt9v011_ctrl_ops = {
+static const struct v4l2_ctrl_ops mt9v011_ctrl_ops = {
        .s_ctrl = mt9v011_s_ctrl,
 };
 
index a68ce94ee097604a26f6b3dca6664ab977e66759..1dbbd23fdfb039f2b26b4fc9c20fee6a39e5c265 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/v4l2-mediabus.h>
 #include <linux/module.h>
 
-#include <media/mt9v032.h>
+#include <media/i2c/mt9v032.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-of.h>
@@ -703,7 +703,7 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
        return 0;
 }
 
-static struct v4l2_ctrl_ops mt9v032_ctrl_ops = {
+static const struct v4l2_ctrl_ops mt9v032_ctrl_ops = {
        .s_ctrl = mt9v032_s_ctrl,
 };
 
index f197b6cbd4075431d3921b838edb80eac25c358e..69e4f3031d8b93cfd5f563ff6566c48605cf7c07 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/i2c.h>
 #include <linux/slab.h>
 #include <linux/regulator/consumer.h>
-#include <media/noon010pc30.h>
+#include <media/i2c/noon010pc30.h>
 #include <linux/videodev2.h>
 #include <linux/module.h>
 #include <media/v4l2-ctrls.h>
index 49109f4f5bb4a14ec471b4915606439a57f3495e..82c7ac1cc88e89d022c4850ae9e2c008cb880e8b 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/videodev2.h>
 
 #include <media/media-entity.h>
-#include <media/ov2659.h>
+#include <media/i2c/ov2659.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
@@ -1249,7 +1249,7 @@ static int ov2659_s_ctrl(struct v4l2_ctrl *ctrl)
        return 0;
 }
 
-static struct v4l2_ctrl_ops ov2659_ctrl_ops = {
+static const struct v4l2_ctrl_ops ov2659_ctrl_ops = {
        .s_ctrl = ov2659_s_ctrl,
 };
 
index e1b5dc84c14e86be96b998f847c0b7dfe1951975..56cfb5ca9c953a5ae813c36daff25a3463cea61f 100644 (file)
@@ -20,7 +20,7 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-mediabus.h>
 #include <media/v4l2-image-sizes.h>
-#include <media/ov7670.h>
+#include <media/i2c/ov7670.h>
 
 MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
 MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors");
index 1ee6a5527c384676333587115a18565ba76f0519..9fe9006474b2b58962667fe0da23f414810f5fc6 100644 (file)
@@ -29,7 +29,7 @@
 #include <media/v4l2-image-sizes.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-mediabus.h>
-#include <media/ov9650.h>
+#include <media/i2c/ov9650.h>
 
 static int debug;
 module_param(debug, int, 0644);
index 51b26010403c1be42126ad481fd3b6b465cd2fbc..25f5e79dc9bc5af61f984e6f2595cf91780d0285 100644 (file)
@@ -34,7 +34,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-mediabus.h>
-#include <media/s5c73m3.h>
+#include <media/i2c/s5c73m3.h>
 #include <media/v4l2-of.h>
 
 #include "s5c73m3.h"
index 8001cde1db1efc14eff2adbd7d18c05356626d33..0a060339e51667b4ded02b180bc5d8fa7f0f877a 100644 (file)
@@ -32,7 +32,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-mediabus.h>
-#include <media/s5c73m3.h>
+#include <media/i2c/s5c73m3.h>
 
 #include "s5c73m3.h"
 
index 72ef9f936e6ceb13ad7b94e5c998ffa9543700e8..7d65b36434b1f3ccfccf25a7ff2071821080ff4b 100644 (file)
@@ -37,6 +37,7 @@ enum spi_direction {
        SPI_DIR_RX,
        SPI_DIR_TX
 };
+MODULE_DEVICE_TABLE(of, s5c73m3_spi_ids);
 
 static int spi_xmit(struct spi_device *spi_dev, void *addr, const int len,
                                                        enum spi_direction dir)
index 13aed59f0f5dac48f2c5788a7df1366f222c5fc6..653f68e7ea07b5ec9841f2d24eb3e414e179ed61 100644 (file)
@@ -23,7 +23,7 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-subdev.h>
-#include <media/s5c73m3.h>
+#include <media/i2c/s5c73m3.h>
 
 #define DRIVER_NAME                    "S5C73M3"
 
index 97084237275dcafcc2b3edcd01ccaa4b6831cec6..6757aca2cdabe000febe423d5e6cb21b0bab8949 100644 (file)
@@ -27,7 +27,7 @@
 #include <asm/unaligned.h>
 
 #include <media/media-entity.h>
-#include <media/s5k4ecgx.h>
+#include <media/i2c/s5k4ecgx.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-mediabus.h>
index d0ad6a25bdabf2e602bdf4b8dd9ab7db384a4f4a..60aaff7190d24ee7e4ceaf589f7ea390c167c7b1 100644 (file)
@@ -28,7 +28,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-mediabus.h>
-#include <media/s5k6aa.h>
+#include <media/i2c/s5k6aa.h>
 
 static int debug;
 module_param(debug, int, 0644);
index 37e65f661d7a19823ed17568e9be546612e459d4..89e458c23983051c436fe1141ad8292022c29bbe 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/wait.h>
 #include <asm/uaccess.h>
 
-#include <media/saa6588.h>
+#include <media/i2c/saa6588.h>
 #include <media/v4l2-device.h>
 
 
index 91e75222c5379e9f441dba06143b28e98b69ed4e..24d2b76dbe97e7a24d762b2bc58a6ba2bc2c6051 100644 (file)
@@ -46,7 +46,7 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
 #include <asm/div64.h>
 
 #define VRES_60HZ      (480+16)
index a43d96da101781d27c94d95b61f22f3e35a1cadb..8d94dcbf4366466c87067d61c16aa78be7f76470 100644 (file)
@@ -54,7 +54,7 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/saa7127.h>
+#include <media/i2c/saa7127.h>
 
 static int debug;
 static int test_image;
index ed010a8a49d717b7c19e3ec97b8a7c2d2466659b..f6af0cc4a256fc0f83d3771e560ee0b6cd148dbd 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/mutex.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-subdev.h>
-#include <media/smiapp.h>
+#include <media/i2c/smiapp.h>
 
 #include "smiapp-pll.h"
 #include "smiapp-reg.h"
index 4fbdd1e9f7ee0e85538174151114623f08030413..2e14e52ba2e056a071d0f1e4e02538569e446af5 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/module.h>
 
 #include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
 #include <media/v4l2-clk.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-ctrls.h>
index 2f35d31ca58eda6c49fb2634a049455dd50df3a8..6a1b2a9f9a0914f88b5b35b2d6fff9829c4045d9 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/v4l2-mediabus.h>
 #include <linux/videodev2.h>
 
-#include <media/mt9t112.h>
+#include <media/i2c/mt9t112.h>
 #include <media/soc_camera.h>
 #include <media/v4l2-clk.h>
 #include <media/v4l2-common.h>
index f31377408550ba0f289f08df6432fd300f6bdd17..c2ba1fb3694dfe78a874186d50b042c60bdde7dd 100644 (file)
@@ -15,9 +15,9 @@
 #include <linux/log2.h>
 #include <linux/module.h>
 
-#include <media/mt9v022.h>
+#include <media/i2c/mt9v022.h>
 #include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-clk.h>
 #include <media/v4l2-ctrls.h>
index f150a8bd94dc8d70ab780b8900248ddc55e979bb..a43410c1e254f93d1922211b480ac08837a30061 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/v4l2-mediabus.h>
 #include <linux/videodev2.h>
 
-#include <media/ov772x.h>
+#include <media/i2c/ov772x.h>
 #include <media/soc_camera.h>
 #include <media/v4l2-clk.h>
 #include <media/v4l2-ctrls.h>
index c769cf663f8423bc38f78b2a9309b183b16d3f8f..aa7bfbb4ad71d8bd04cebe137e1666f0df3ee4f0 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/videodev2.h>
 #include <linux/module.h>
 
-#include <media/rj54n1cb0c.h>
+#include <media/i2c/rj54n1cb0c.h>
 #include <media/soc_camera.h>
 #include <media/v4l2-clk.h>
 #include <media/v4l2-subdev.h>
index e939c24bfd3c2eaf56fa75cc326590fd0511ad28..06aff81787a7bf43c5373395e0921e2c42f5de4b 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/videodev2.h>
 
 #include <media/soc_camera.h>
-#include <media/tw9910.h>
+#include <media/i2c/tw9910.h>
 #include <media/v4l2-clk.h>
 #include <media/v4l2-subdev.h>
 
index b04c09dd4bfb39768c1345423692d34c56e257f2..0bf031b7e4fa932d462f45421f805b4a0578d69c 100644 (file)
@@ -24,7 +24,7 @@
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-mediabus.h>
 #include <media/v4l2-ctrls.h>
-#include <media/sr030pc30.h>
+#include <media/i2c/sr030pc30.h>
 
 static int debug;
 module_param(debug, int, 0644);
index 9ef5baaf86465a05327b791dcd61df3e0d8f2e42..77b801152ea590fb800cbe3f978f4f13f8f63ac8 100644 (file)
@@ -42,7 +42,7 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-event.h>
 #include <media/v4l2-of.h>
-#include <media/tc358743.h>
+#include <media/i2c/tc358743.h>
 
 #include "tc358743_regs.h"
 
@@ -862,7 +862,7 @@ static void tc358743_format_change(struct v4l2_subdev *sd)
                v4l2_dbg(1, debug, sd, "%s: Format changed. No signal\n",
                                __func__);
        } else {
-               if (!v4l2_match_dv_timings(&state->timings, &timings, 0))
+               if (!v4l2_match_dv_timings(&state->timings, &timings, 0, false))
                        enable_stream(sd, false);
 
                v4l2_print_dv_timings(sd->name,
@@ -1366,7 +1366,7 @@ static int tc358743_s_dv_timings(struct v4l2_subdev *sd,
                v4l2_print_dv_timings(sd->name, "tc358743_s_dv_timings: ",
                                timings, false);
 
-       if (v4l2_match_dv_timings(&state->timings, timings, 0)) {
+       if (v4l2_match_dv_timings(&state->timings, timings, 0, false)) {
                v4l2_dbg(1, debug, sd, "%s: no change\n", __func__);
                return 0;
        }
index bda3a6540a604ac80de453154a362232d89060e5..5bbfcab01c7536d3692f9b53f7b97da3426d3a52 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 
-#include <media/ths7303.h>
+#include <media/i2c/ths7303.h>
 #include <media/v4l2-device.h>
 
 #define THS7303_CHANNEL_1      1
index 2a8114a676fd9a237ececa8cf1fdfb33f72e2ddc..fece2a4339a1a0046f89ef06321d31778b280cff 100644 (file)
@@ -36,7 +36,7 @@
 #include <linux/kthread.h>
 #include <linux/freezer.h>
 
-#include <media/tvaudio.h>
+#include <media/i2c/tvaudio.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
 
index a93985a9b07031252eea2e0a0c08e0ac9268d1f1..b5dba5b7ce3a6670b7c5d1a471a7bed175b546c1 100644 (file)
@@ -44,7 +44,7 @@
 #include <media/v4l2-mediabus.h>
 #include <media/v4l2-of.h>
 #include <media/v4l2-ctrls.h>
-#include <media/tvp514x.h>
+#include <media/i2c/tvp514x.h>
 #include <media/media-entity.h>
 
 #include "tvp514x_regs.h"
index 3c5fb2509c475dc00ebff10315e1bc8ae5452b47..6c3769d44b75ccf6cc113dece96d2ab2e6244b2b 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/module.h>
 #include <media/v4l2-async.h>
 #include <media/v4l2-device.h>
-#include <media/tvp5150.h>
+#include <media/i2c/tvp5150.h>
 #include <media/v4l2-ctrls.h>
 
 #include "tvp5150_reg.h"
index f617d8b745eec5960ee8c6b096cb678d2ec1efbd..772a3043ae3b9897a9380e2a7110487a95f192d3 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/of.h>
 #include <linux/of_graph.h>
 #include <linux/v4l2-dv-timings.h>
-#include <media/tvp7002.h>
+#include <media/i2c/tvp7002.h>
 #include <media/v4l2-async.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-common.h>
index 081786d176d097327d5e5fa54553087ae7eea92f..8e17a83920d4355038673410459af1011d69e00e 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/uda1342.h>
+#include <media/i2c/uda1342.h>
 #include <linux/slab.h>
 
 static int write_reg(struct i2c_client *client, int reg, int value)
index 2c0f955abc72ca2c4b3b4b46ad73245dfa5228ec..c03567e993cd3c7645e010314211354ff170f511 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/videodev2.h>
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
-#include <media/upd64031a.h>
+#include <media/i2c/upd64031a.h>
 
 /* --------------------- read registers functions define -------------------- */
 
index f2057a4340608b8861d1d211d578cdcdd19fa23b..77f122f2e3c99af0390a64c30a2cf7c14efa82dd 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/videodev2.h>
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
-#include <media/upd64083.h>
+#include <media/i2c/upd64083.h>
 
 MODULE_DESCRIPTION("uPD64083 driver");
 MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil");
index d33d2cd6d03415ba46c355a2a278db64903e4c10..6e00f145b9485953586b244df73274d31348c62b 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
-#include <media/wm8775.h>
+#include <media/i2c/wm8775.h>
 
 MODULE_DESCRIPTION("wm8775 driver");
 MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
index 4654fb65ca21b2d27f61c9b8cb1c5c755fc3afa1..8a17cc0bfa0737ec80818aaa9a3bcbae05feedca 100644 (file)
@@ -41,7 +41,7 @@
 
 #include "bttvp.h"
 #include <media/v4l2-common.h>
-#include <media/tvaudio.h>
+#include <media/i2c/tvaudio.h>
 #include "bttv-audio-hook.h"
 
 /* fwd decl */
@@ -3808,7 +3808,7 @@ static void bttv_tea575x_set_direction(struct snd_tea575x *tea, bool output)
                gpio_inout(mask, (1 << gpio.clk) | (1 << gpio.wren));
 }
 
-static struct snd_tea575x_ops bttv_tea_ops = {
+static const struct snd_tea575x_ops bttv_tea_ops = {
        .set_pins = bttv_tea575x_set_pins,
        .get_pins = bttv_tea575x_get_pins,
        .set_direction = bttv_tea575x_set_direction,
index 15a4ebc2844d4f5882ea31cdf80c0f648b04a751..9400e996087b6a5eb5076cd7e0ab399f2bed0e9e 100644 (file)
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-event.h>
-#include <media/tvaudio.h>
-#include <media/msp3400.h>
+#include <media/i2c/tvaudio.h>
+#include <media/drv-intf/msp3400.h>
 
 #include <linux/dma-mapping.h>
 
 #include <asm/io.h>
 #include <asm/byteorder.h>
 
-#include <media/saa6588.h>
+#include <media/i2c/saa6588.h>
 
 #define BTTV_VERSION "0.9.19"
 
index 31bf79d3b0d263e312c1849d8eb9c49a7d48f819..b1e0023f923c95429f5ea58ec2b61ff07969309e 100644 (file)
@@ -41,8 +41,8 @@
 #include <media/videobuf-dma-sg.h>
 #include <media/tveeprom.h>
 #include <media/rc-core.h>
-#include <media/ir-kbd-i2c.h>
-#include <media/tea575x.h>
+#include <media/i2c/ir-kbd-i2c.h>
+#include <media/drv-intf/tea575x.h>
 
 #include "bt848.h"
 #include "bttv.h"
index 8fed61ec712ef01440461eafb6ecd07b3aafa486..8d6f04fc8013bf0d8e0675f343ce49bcc0e5f417 100644 (file)
@@ -21,9 +21,9 @@
  */
 
 #include <linux/delay.h>
-#include <media/adv7604.h>
-#include <media/adv7842.h>
-#include <media/adv7511.h>
+#include <media/i2c/adv7604.h>
+#include <media/i2c/adv7842.h>
+#include <media/i2c/adv7511.h>
 #include <media/v4l2-event.h>
 #include <media/v4l2-ctrls.h>
 
index 3de26d0714b57aa16c8495c21d1e05091db697a1..b190d4f81c6ea36c5f64014a05afeb42e173675a 100644 (file)
@@ -18,7 +18,7 @@
  *  SOFTWARE.
  */
 
-#include <media/adv7604.h>
+#include <media/i2c/adv7604.h>
 
 #include "cobalt-driver.h"
 #include "cobalt-irq.h"
@@ -134,7 +134,7 @@ done:
                skip = true;
                s->skip_first_frames--;
        }
-       v4l2_get_timestamp(&cb->vb.timestamp);
+       cb->vb.vb2_buf.timestamp = ktime_get_ns();
        /* TODO: the sequence number should be read from the FPGA so we
           also know about dropped frames. */
        cb->vb.sequence = s->sequence++;
index ff46e424262f04d5c6aca7a55ccda9743b803483..c0ba458f6cf3781a05839d2b47a36711ad6daa3d 100644 (file)
@@ -29,8 +29,8 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-event.h>
 #include <media/v4l2-dv-timings.h>
-#include <media/adv7604.h>
-#include <media/adv7842.h>
+#include <media/i2c/adv7604.h>
+#include <media/i2c/adv7842.h>
 
 #include "cobalt-alsa.h"
 #include "cobalt-cpld.h"
@@ -43,11 +43,10 @@ static const struct v4l2_dv_timings cea1080p60 = V4L2_DV_BT_CEA_1920X1080P60;
 
 /* vb2 DMA streaming ops */
 
-static int cobalt_queue_setup(struct vb2_queue *q, const void *parg,
+static int cobalt_queue_setup(struct vb2_queue *q,
                        unsigned int *num_buffers, unsigned int *num_planes,
                        unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct cobalt_stream *s = q->drv_priv;
        unsigned size = s->stride * s->height;
 
@@ -55,14 +54,11 @@ static int cobalt_queue_setup(struct vb2_queue *q, const void *parg,
                *num_buffers = 3;
        if (*num_buffers > NR_BUFS)
                *num_buffers = NR_BUFS;
+       alloc_ctxs[0] = s->cobalt->alloc_ctx;
+       if (*num_planes)
+               return sizes[0] < size ? -EINVAL : 0;
        *num_planes = 1;
-       if (fmt) {
-               if (fmt->fmt.pix.sizeimage < size)
-                       return -EINVAL;
-               size = fmt->fmt.pix.sizeimage;
-       }
        sizes[0] = size;
-       alloc_ctxs[0] = s->cobalt->alloc_ctx;
        return 0;
 }
 
@@ -649,7 +645,7 @@ static int cobalt_s_dv_timings(struct file *file, void *priv_fh,
                return 0;
        }
 
-       if (v4l2_match_dv_timings(timings, &s->timings, 0))
+       if (v4l2_match_dv_timings(timings, &s->timings, 0, false))
                return 0;
 
        if (vb2_is_busy(&s->q))
index c07c849b1aaf561bad3448ef88821acbefe83af8..5e01ea441dc4d59d77558087bddbce11e024a7d9 100644 (file)
@@ -26,7 +26,7 @@
 #include "cx18-cards.h"
 #include "cx18-av-core.h"
 #include "cx18-i2c.h"
-#include <media/cs5345.h>
+#include <media/i2c/cs5345.h>
 
 #define V4L2_STD_PAL_SECAM (V4L2_STD_PAL|V4L2_STD_SECAM)
 
index 71227a155cba5c03830635fef8368997c4e0cb97..adb5a8c72c06d888052cd98e65947175d6860106 100644 (file)
@@ -126,7 +126,7 @@ static int cx18_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val)
        return 0;
 }
 
-struct cx2341x_handler_ops cx18_cxhdl_ops = {
+const struct cx2341x_handler_ops cx18_cxhdl_ops = {
        .s_audio_mode = cx18_s_audio_mode,
        .s_audio_sampling_freq = cx18_s_audio_sampling_freq,
        .s_video_encoding = cx18_s_video_encoding,
index cb5dfc7b20546969a1cdd06f23467cba229901a7..326794887863225fcc93d4231eef1dbe385261a2 100644 (file)
@@ -21,4 +21,4 @@
  *  02111-1307  USA
  */
 
-extern struct cx2341x_handler_ops cx18_cxhdl_ops;
+extern const struct cx2341x_handler_ops cx18_cxhdl_ops;
index b15beed2dc143f6f3fabcbcadc34be76165ea2be..7e31f2a2e085b51f078eb127c72a2e84d6afd7a8 100644 (file)
@@ -49,7 +49,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-fh.h>
 #include <media/tuner.h>
-#include <media/ir-kbd-i2c.h>
+#include <media/i2c/ir-kbd-i2c.h>
 #include "cx18-mailbox.h"
 #include "cx18-av-core.h"
 #include "cx23418.h"
index 55525af1f4826d617f12a4c74ae5b4af68fd61d7..eeb741c7db1b2fe2e724a6c60f7202a94feedfc2 100644 (file)
@@ -453,8 +453,8 @@ static int cx18_cropcap(struct file *file, void *fh,
 
        if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
-       cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10;
-       cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11;
+       cropcap->pixelaspect.numerator = cx->is_50hz ? 54 : 11;
+       cropcap->pixelaspect.denominator = cx->is_50hz ? 59 : 10;
        return 0;
 }
 
index 767a8d23e3f27a301de5e0d11c8fde58548cbb70..67ffe65b56a35fdcb64776c417195d806a3603fc 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef CX23418_H
 #define CX23418_H
 
-#include <media/cx2341x.h>
+#include <media/drv-intf/cx2341x.h>
 
 #define MGR_CMD_MASK                           0x40000000
 /* The MSB of the command code indicates that this is the completion of a
index 2e1b88ccdbf23d16c9adac53812d210c89f9cc35..3435bbaa3167fe416f06319294fd3e8148dfb9b4 100644 (file)
@@ -10,6 +10,7 @@ config VIDEO_CX23885
        select VIDEOBUF2_DMA_SG
        select VIDEO_CX25840
        select VIDEO_CX2341X
+       select VIDEO_CS3308
        select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT
        select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT
        select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT
index 88a3afb66d10bde76002c2da4ee16493bb10f2bd..bd333875a1f708c5fa05f8fadeb6ef4d851b3d68 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/slab.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
-#include <media/cx2341x.h>
+#include <media/drv-intf/cx2341x.h>
 
 #include "cx23885.h"
 #include "cx23885-ioctl.h"
@@ -1138,7 +1138,7 @@ static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder)
 
 /* ------------------------------------------------------------------ */
 
-static int queue_setup(struct vb2_queue *q, const void *parg,
+static int queue_setup(struct vb2_queue *q,
                           unsigned int *num_buffers, unsigned int *num_planes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
index f384f295676ec217b069383d286fc65545f15b02..310ee769aed49bf066338022779cddde24615231 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <media/cx25840.h>
+#include <media/drv-intf/cx25840.h>
 #include <linux/firmware.h>
 #include <misc/altera.h>
 
@@ -715,6 +715,56 @@ struct cx23885_board cx23885_boards[] = {
                .portb          = CX23885_MPEG_DVB,
                .portc          = CX23885_MPEG_DVB,
        },
+       [CX23885_BOARD_VIEWCAST_260E] = {
+               .name           = "ViewCast 260e",
+               .porta          = CX23885_ANALOG_VIDEO,
+               .force_bff      = 1,
+               .input          = {{
+                       .type   = CX23885_VMUX_COMPOSITE1,
+                       .vmux   = CX25840_VIN6_CH1,
+                       .amux   = CX25840_AUDIO7,
+               }, {
+                       .type   = CX23885_VMUX_SVIDEO,
+                       .vmux   = CX25840_VIN7_CH3 |
+                                       CX25840_VIN5_CH1 |
+                                       CX25840_SVIDEO_ON,
+                       .amux   = CX25840_AUDIO7,
+               }, {
+                       .type   = CX23885_VMUX_COMPONENT,
+                       .vmux   = CX25840_VIN7_CH3 |
+                                       CX25840_VIN6_CH2 |
+                                       CX25840_VIN5_CH1 |
+                                       CX25840_COMPONENT_ON,
+                       .amux   = CX25840_AUDIO7,
+               } },
+       },
+       [CX23885_BOARD_VIEWCAST_460E] = {
+               .name           = "ViewCast 460e",
+               .porta          = CX23885_ANALOG_VIDEO,
+               .force_bff      = 1,
+               .input          = {{
+                       .type   = CX23885_VMUX_COMPOSITE1,
+                       .vmux   = CX25840_VIN4_CH1,
+                       .amux   = CX25840_AUDIO7,
+               }, {
+                       .type   = CX23885_VMUX_SVIDEO,
+                       .vmux   = CX25840_VIN7_CH3 |
+                                       CX25840_VIN6_CH1 |
+                                       CX25840_SVIDEO_ON,
+                       .amux   = CX25840_AUDIO7,
+               }, {
+                       .type   = CX23885_VMUX_COMPONENT,
+                       .vmux   = CX25840_VIN7_CH3 |
+                                       CX25840_VIN6_CH1 |
+                                       CX25840_VIN5_CH2 |
+                                       CX25840_COMPONENT_ON,
+                       .amux   = CX25840_AUDIO7,
+               }, {
+                       .type   = CX23885_VMUX_COMPOSITE2,
+                       .vmux   = CX25840_VIN6_CH1,
+                       .amux   = CX25840_AUDIO7,
+               } },
+       },
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -1002,6 +1052,14 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x0070,
                .subdevice = 0xf038,
                .card      = CX23885_BOARD_HAUPPAUGE_HVR5525,
+       }, {
+               .subvendor = 0x1576,
+               .subdevice = 0x0260,
+               .card      = CX23885_BOARD_VIEWCAST_260E,
+       }, {
+               .subvendor = 0x1576,
+               .subdevice = 0x0460,
+               .card      = CX23885_BOARD_VIEWCAST_460E,
        },
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -1034,6 +1092,28 @@ void cx23885_card_list(struct cx23885_dev *dev)
                       dev->name, i, cx23885_boards[i].name);
 }
 
+static void viewcast_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
+{
+       u32 sn;
+
+       /* The serial number record begins with tag 0x59 */
+       if (*(eeprom_data + 0x00) != 0x59) {
+               pr_info("%s() eeprom records are undefined, no serial number\n",
+                       __func__);
+               return;
+       }
+
+       sn =    (*(eeprom_data + 0x06) << 24) |
+               (*(eeprom_data + 0x05) << 16) |
+               (*(eeprom_data + 0x04) << 8) |
+               (*(eeprom_data + 0x03));
+
+       pr_info("%s: card '%s' sn# MM%d\n",
+               dev->name,
+               cx23885_boards[dev->board].name,
+               sn);
+}
+
 static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
 {
        struct tveeprom tv;
@@ -1671,6 +1751,12 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
                cx23885_gpio_set(dev, GPIO_8 | GPIO_9);
                msleep(100);
                break;
+       case CX23885_BOARD_VIEWCAST_260E:
+       case CX23885_BOARD_VIEWCAST_460E:
+               /* For documentation purposes, it's worth noting that this
+                * card does not have any GPIO's connected to subcomponents.
+                */
+               break;
        }
 }
 
@@ -1917,6 +2003,14 @@ void cx23885_card_setup(struct cx23885_dev *dev)
                if (dev->i2c_bus[0].i2c_rc == 0)
                        hauppauge_eeprom(dev, eeprom+0xc0);
                break;
+       case CX23885_BOARD_VIEWCAST_260E:
+       case CX23885_BOARD_VIEWCAST_460E:
+               dev->i2c_bus[1].i2c_client.addr = 0xa0 >> 1;
+               tveeprom_read(&dev->i2c_bus[1].i2c_client,
+                             eeprom, sizeof(eeprom));
+               if (dev->i2c_bus[0].i2c_rc == 0)
+                       viewcast_eeprom(dev, eeprom);
+               break;
        }
 
        switch (dev->board) {
@@ -2120,6 +2214,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_DVBSKY_S950:
        case CX23885_BOARD_DVBSKY_S952:
        case CX23885_BOARD_DVBSKY_T982:
+       case CX23885_BOARD_VIEWCAST_260E:
+       case CX23885_BOARD_VIEWCAST_460E:
                dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
                                &dev->i2c_bus[2].i2c_adap,
                                "cx25840", 0x88 >> 1, NULL);
@@ -2130,6 +2226,24 @@ void cx23885_card_setup(struct cx23885_dev *dev)
                break;
        }
 
+       switch (dev->board) {
+       case CX23885_BOARD_VIEWCAST_260E:
+               v4l2_i2c_new_subdev(&dev->v4l2_dev,
+                               &dev->i2c_bus[0].i2c_adap,
+                               "cs3308", 0x82 >> 1, NULL);
+               break;
+       case CX23885_BOARD_VIEWCAST_460E:
+               /* This cs3308 controls the audio from the breakout cable */
+               v4l2_i2c_new_subdev(&dev->v4l2_dev,
+                               &dev->i2c_bus[0].i2c_adap,
+                               "cs3308", 0x80 >> 1, NULL);
+               /* This cs3308 controls the audio from the onboard header */
+               v4l2_i2c_new_subdev(&dev->v4l2_dev,
+                               &dev->i2c_bus[0].i2c_adap,
+                               "cs3308", 0x82 >> 1, NULL);
+               break;
+       }
+
        /* AUX-PLL 27MHz CLK */
        switch (dev->board) {
        case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
index e8f847226a199f308394302b1f24dacf186b6226..813c217b5e1a5803d42c64c18dd5245746531fe1 100644 (file)
@@ -427,7 +427,7 @@ static void cx23885_wakeup(struct cx23885_tsport *port,
        buf = list_entry(q->active.next,
                         struct cx23885_buffer, queue);
 
-       v4l2_get_timestamp(&buf->vb.timestamp);
+       buf->vb.vb2_buf.timestamp = ktime_get_ns();
        buf->vb.sequence = q->count++;
        dprintk(1, "[%p/%d] wakeup reg=%d buf=%d\n", buf,
                buf->vb.vb2_buf.index,
@@ -968,6 +968,16 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
        call_all(dev, core, s_power, 0);
        cx23885_ir_init(dev);
 
+       if (dev->board == CX23885_BOARD_VIEWCAST_460E) {
+               /*
+                * GPIOs 9/8 are input detection bits for the breakout video
+                * (gpio 8) and audio (gpio 9) cables. When they're attached,
+                * this gpios are pulled high. Make sure these GPIOs are marked
+                * as inputs.
+                */
+               cx23885_gpio_enable(dev, 0x300, 0);
+       }
+
        if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) {
                if (cx23885_video_register(dev) < 0) {
                        printk(KERN_ERR "%s() Failed to register analog "
index c4307ad8594c577e074aab2cb2728f3c42db01a8..80319bb73d94dc25545e33c8ccefab9ed6f26497 100644 (file)
@@ -92,7 +92,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 /* ------------------------------------------------------------------ */
 
-static int queue_setup(struct vb2_queue *q, const void *parg,
+static int queue_setup(struct vb2_queue *q,
                           unsigned int *num_buffers, unsigned int *num_planes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
@@ -2168,11 +2168,12 @@ static int dvb_register(struct cx23885_tsport *port)
                }
                port->i2c_client_tuner = client_tuner;
                break;
-       case CX23885_BOARD_HAUPPAUGE_HVR5525:
-               switch (port->nr) {
+       case CX23885_BOARD_HAUPPAUGE_HVR5525: {
                struct m88rs6000t_config m88rs6000t_config;
                struct a8293_platform_data a8293_pdata = {};
 
+               switch (port->nr) {
+
                /* port b - satellite */
                case 1:
                        /* attach frontend */
@@ -2267,6 +2268,7 @@ static int dvb_register(struct cx23885_tsport *port)
                        break;
                }
                break;
+       }
        default:
                printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
                        " isn't supported yet\n",
index 1135ea3f6ce52297caa4f7fc4f974a72ab4376cb..ae061b3585917c4f937a75cbfb4f1f21e770be95 100644 (file)
@@ -279,6 +279,8 @@ static char *i2c_devs[128] = {
        [0x10 >> 1] = "tda10048",
        [0x12 >> 1] = "dib7000pc",
        [0x1c >> 1] = "lgdt3303",
+       [0x80 >> 1] = "cs3308",
+       [0x82 >> 1] = "cs3308",
        [0x86 >> 1] = "tda9887",
        [0x32 >> 1] = "cx24227",
        [0x88 >> 1] = "cx25837",
index 088799c3b49bd2c019023f09d11ed50b13506aca..64328d08ac2fc12410956cc579bc7d3f8cd1583f 100644 (file)
@@ -268,7 +268,7 @@ int cx23885_input_init(struct cx23885_dev *dev)
        struct rc_dev *rc;
        char *rc_map;
        enum rc_driver_type driver_type;
-       unsigned long allowed_protos;
+       u64 allowed_protos;
 
        int ret;
 
index cf3cb1324c55ad7c60d02878ff86f59f87ee1620..39750ebcc04cf4d1970b2ccff42dc57f969cea85 100644 (file)
@@ -83,7 +83,7 @@ int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status)
        if (status & VID_BC_MSK_VBI_RISCI1) {
                dprintk(1, "%s() VID_BC_MSK_VBI_RISCI1\n", __func__);
                spin_lock(&dev->slock);
-               count = cx_read(VID_A_GPCNT);
+               count = cx_read(VBI_A_GPCNT);
                cx23885_video_wakeup(dev, &dev->vbiq, count);
                spin_unlock(&dev->slock);
                handled++;
@@ -103,7 +103,6 @@ static int cx23885_start_vbi_dma(struct cx23885_dev    *dev,
                                VBI_LINE_LENGTH, buf->risc.dma);
 
        /* reset counter */
-       cx_write(VID_A_GPCNT_CTL, 3);
        cx_write(VID_A_VBI_CTRL, 3);
        cx_write(VBI_A_GPCNT_CTL, 3);
        q->count = 0;
@@ -121,7 +120,7 @@ static int cx23885_start_vbi_dma(struct cx23885_dev    *dev,
 
 /* ------------------------------------------------------------------ */
 
-static int queue_setup(struct vb2_queue *q, const void *parg,
+static int queue_setup(struct vb2_queue *q,
                           unsigned int *num_buffers, unsigned int *num_planes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
index 71a80e2b842ca9c395cb4a000f77ae482fb57dbc..e1d7d08471672d6376e759ee7be11e7eb961e00e 100644 (file)
@@ -35,7 +35,7 @@
 #include "cx23885-ioctl.h"
 #include "tuner-xc2028.h"
 
-#include <media/cx25840.h>
+#include <media/drv-intf/cx25840.h>
 
 MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards");
 MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
@@ -105,7 +105,7 @@ void cx23885_video_wakeup(struct cx23885_dev *dev,
                        struct cx23885_buffer, queue);
 
        buf->vb.sequence = q->count++;
-       v4l2_get_timestamp(&buf->vb.timestamp);
+       buf->vb.vb2_buf.timestamp = ktime_get_ns();
        dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf,
                        buf->vb.vb2_buf.index, count, q->count);
        list_del(&buf->queue);
@@ -114,11 +114,19 @@ void cx23885_video_wakeup(struct cx23885_dev *dev,
 
 int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
 {
+       struct v4l2_subdev_format format = {
+               .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+               .format.code = MEDIA_BUS_FMT_FIXED,
+       };
+
        dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
                __func__,
                (unsigned int)norm,
                v4l2_norm_to_name(norm));
 
+       if (dev->tvnorm == norm)
+               return 0;
+
        if (dev->tvnorm != norm) {
                if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq) ||
                    vb2_is_busy(&dev->vb2_mpegq))
@@ -126,9 +134,17 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
        }
 
        dev->tvnorm = norm;
+       dev->width = 720;
+       dev->height = norm_maxh(norm);
+       dev->field = V4L2_FIELD_INTERLACED;
 
        call_all(dev, video, s_std, norm);
 
+       format.format.width = dev->width;
+       format.format.height = dev->height;
+       format.format.field = dev->field;
+       call_all(dev, pad, set_fmt, NULL, &format);
+
        return 0;
 }
 
@@ -247,7 +263,9 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
                (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) ||
                (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) ||
                (dev->board == CX23885_BOARD_MYGICA_X8507) ||
-               (dev->board == CX23885_BOARD_AVERMEDIA_HC81R)) {
+               (dev->board == CX23885_BOARD_AVERMEDIA_HC81R) ||
+               (dev->board == CX23885_BOARD_VIEWCAST_260E) ||
+               (dev->board == CX23885_BOARD_VIEWCAST_460E)) {
                /* Configure audio routing */
                v4l2_subdev_call(dev->sd_cx25840, audio, s_routing,
                        INPUT(input)->amux, 0, 0);
@@ -315,7 +333,7 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev,
        return 0;
 }
 
-static int queue_setup(struct vb2_queue *q, const void *parg,
+static int queue_setup(struct vb2_queue *q,
                           unsigned int *num_buffers, unsigned int *num_planes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
@@ -545,7 +563,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                return -EINVAL;
 
        field = f->fmt.pix.field;
-       maxw  = norm_maxw(dev->tvnorm);
+       maxw  = 720;
        maxh  = norm_maxh(dev->tvnorm);
 
        if (V4L2_FIELD_ANY == field) {
@@ -648,6 +666,26 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
        return 0;
 }
 
+static int vidioc_cropcap(struct file *file, void *priv,
+                         struct v4l2_cropcap *cc)
+{
+       struct cx23885_dev *dev = video_drvdata(file);
+       bool is_50hz = dev->tvnorm & V4L2_STD_625_50;
+
+       if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       cc->bounds.left = 0;
+       cc->bounds.top = 0;
+       cc->bounds.width = 720;
+       cc->bounds.height = norm_maxh(dev->tvnorm);
+       cc->defrect = cc->bounds;
+       cc->pixelaspect.numerator = is_50hz ? 54 : 11;
+       cc->pixelaspect.denominator = is_50hz ? 59 : 10;
+
+       return 0;
+}
+
 static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
 {
        struct cx23885_dev *dev = video_drvdata(file);
@@ -1082,6 +1120,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_dqbuf         = vb2_ioctl_dqbuf,
        .vidioc_streamon      = vb2_ioctl_streamon,
        .vidioc_streamoff     = vb2_ioctl_streamoff,
+       .vidioc_cropcap       = vidioc_cropcap,
        .vidioc_s_std         = vidioc_s_std,
        .vidioc_g_std         = vidioc_g_std,
        .vidioc_enum_input    = vidioc_enum_input,
index c5ba0833f47a69803ccb51d200738b88d432eb18..b1a5409408c7a60cd8dc3e777e77af7db0379089 100644 (file)
@@ -30,7 +30,7 @@
 #include <media/rc-core.h>
 
 #include "cx23885-reg.h"
-#include "media/cx2341x.h"
+#include "media/drv-intf/cx2341x.h"
 
 #include <linux/mutex.h>
 
 #define CX23885_BOARD_DVBSKY_T982              51
 #define CX23885_BOARD_HAUPPAUGE_HVR5525        52
 #define CX23885_BOARD_HAUPPAUGE_STARBURST      53
+#define CX23885_BOARD_VIEWCAST_260E            54
+#define CX23885_BOARD_VIEWCAST_460E            55
 
 #define GPIO_0 0x00000001
 #define GPIO_1 0x00000002
@@ -627,11 +629,6 @@ extern int cx23885_risc_databuffer(struct pci_dev *pci,
 /* ----------------------------------------------------------- */
 /* tv norms                                                    */
 
-static inline unsigned int norm_maxw(v4l2_std_id norm)
-{
-       return (norm & V4L2_STD_525_60) ? 720 : 768;
-}
-
 static inline unsigned int norm_maxh(v4l2_std_id norm)
 {
        return (norm & V4L2_STD_525_60) ? 480 : 576;
index 26e3e296d615afdc87d0b49253f3b56772c7f3cd..c48bba9daf1f8e55b36709aa973dffc19477011c 100644 (file)
@@ -130,7 +130,7 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
                        buf = list_entry(dmaq->active.next,
                                         struct cx25821_buffer, queue);
 
-                       v4l2_get_timestamp(&buf->vb.timestamp);
+                       buf->vb.vb2_buf.timestamp = ktime_get_ns();
                        buf->vb.sequence = dmaq->count++;
                        list_del(&buf->queue);
                        vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
@@ -141,20 +141,20 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
        return handled;
 }
 
-static int cx25821_queue_setup(struct vb2_queue *q, const void *parg,
+static int cx25821_queue_setup(struct vb2_queue *q,
                           unsigned int *num_buffers, unsigned int *num_planes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct cx25821_channel *chan = q->drv_priv;
        unsigned size = (chan->fmt->depth * chan->width * chan->height) >> 3;
 
-       if (fmt && fmt->fmt.pix.sizeimage < size)
-               return -EINVAL;
+       alloc_ctxs[0] = chan->dev->alloc_ctx;
+
+       if (*num_planes)
+               return sizes[0] < size ? -EINVAL : 0;
 
        *num_planes = 1;
-       sizes[0] = fmt ? fmt->fmt.pix.sizeimage : size;
-       alloc_ctxs[0] = chan->dev->alloc_ctx;
+       sizes[0] = size;
        return 0;
 }
 
index 1b5268f9bb248f5b0787d16e707c25b84ffbe150..e158a1da1d41010e782fe04ab509dad28e60f6b1 100644 (file)
@@ -40,7 +40,7 @@
 #include <sound/control.h>
 #include <sound/initval.h>
 #include <sound/tlv.h>
-#include <media/wm8775.h>
+#include <media/i2c/wm8775.h>
 
 #include "cx88.h"
 #include "cx88-reg.h"
index 8b889135be8a3ede1d026bbb6379b78fbabaad57..3233d45d1e5baa108a9b6e706f73956a859f1dce 100644 (file)
@@ -36,7 +36,7 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-event.h>
-#include <media/cx2341x.h>
+#include <media/drv-intf/cx2341x.h>
 
 #include "cx88.h"
 
@@ -637,7 +637,7 @@ static int blackbird_stop_codec(struct cx8802_dev *dev)
 
 /* ------------------------------------------------------------------ */
 
-static int queue_setup(struct vb2_queue *q, const void *parg,
+static int queue_setup(struct vb2_queue *q,
                           unsigned int *num_buffers, unsigned int *num_planes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
index 9a43c7826b603e2c535b952addaad0a6e4c2636d..46fe8c1eb9d4323dc66c2177f1167c35914bceae 100644 (file)
@@ -518,7 +518,7 @@ void cx88_wakeup(struct cx88_core *core,
 
        buf = list_entry(q->active.next,
                         struct cx88_buffer, list);
-       v4l2_get_timestamp(&buf->vb.timestamp);
+       buf->vb.vb2_buf.timestamp = ktime_get_ns();
        buf->vb.field = core->field;
        buf->vb.sequence = q->count++;
        list_del(&buf->list);
index f04835073844be588918f94eb4022bf62567eb44..afb20756d7a56ef54ed49c6b3eaf3d78878f7888 100644 (file)
@@ -82,7 +82,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 /* ------------------------------------------------------------------ */
 
-static int queue_setup(struct vb2_queue *q, const void *parg,
+static int queue_setup(struct vb2_queue *q,
                           unsigned int *num_buffers, unsigned int *num_planes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
index 007a5eee8e5ed50db347e4f984785f4c5b4e54b4..ccc646d819f285bba6a17c95b82fd56335d149ec 100644 (file)
@@ -107,7 +107,7 @@ int cx8800_restart_vbi_queue(struct cx8800_dev    *dev,
 
 /* ------------------------------------------------------------------ */
 
-static int queue_setup(struct vb2_queue *q, const void *parg,
+static int queue_setup(struct vb2_queue *q,
                           unsigned int *num_buffers, unsigned int *num_planes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
index aef9acf351f6379017f967538a87d103fc7b7a94..5f331df65fb9717471b7cd6cbdcf220caf5a7c12 100644 (file)
@@ -41,7 +41,7 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-event.h>
-#include <media/wm8775.h>
+#include <media/i2c/wm8775.h>
 
 MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -429,7 +429,7 @@ static int restart_video_queue(struct cx8800_dev    *dev,
 
 /* ------------------------------------------------------------------ */
 
-static int queue_setup(struct vb2_queue *q, const void *parg,
+static int queue_setup(struct vb2_queue *q,
                           unsigned int *num_buffers, unsigned int *num_planes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
index 2996eb3ea1fc87db583dfbc80a5fd417de70da45..78f817ee7e41360e6f3ec32a2983b0743b53faf6 100644 (file)
 #include <media/tuner.h>
 #include <media/tveeprom.h>
 #include <media/videobuf2-dma-sg.h>
-#include <media/cx2341x.h>
+#include <media/drv-intf/cx2341x.h>
 #include <media/videobuf2-dvb.h>
-#include <media/ir-kbd-i2c.h>
-#include <media/wm8775.h>
+#include <media/i2c/ir-kbd-i2c.h>
+#include <media/i2c/wm8775.h>
 
 #include "cx88-reg.h"
 #include "tuner-xc2028.h"
index 0ac2dd35fe506480d5e99475bc9200fa26147408..fba5b40a869c50a705d74f5831436f139d08c27e 100644 (file)
@@ -81,13 +81,13 @@ static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
 static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
 {
        struct ddb *dev = i2c->dev;
-       int stat;
+       long stat;
        u32 val;
 
        i2c->done = 0;
        ddbwritel((adr << 9) | cmd, i2c->regs + I2C_COMMAND);
        stat = wait_event_timeout(i2c->wq, i2c->done == 1, HZ);
-       if (stat <= 0) {
+       if (stat == 0) {
                printk(KERN_ERR "I2C timeout\n");
                { /* MSI debugging*/
                        u32 istat = ddbreadl(INTERRUPT_STATUS);
index 88915fb87e80d7dc5a3b6cd193d36cdcee409ce1..5dd504741b12c9f33959185eb340cfa305d7cba1 100644 (file)
@@ -1206,7 +1206,6 @@ static void dm1105_remove(struct pci_dev *pdev)
        i2c_del_adapter(&dev->i2c_adap);
 
        dm1105_hw_exit(dev);
-       synchronize_irq(pdev->irq);
        free_irq(pdev->irq, dev);
        pci_iounmap(pdev, dev->io_mem);
        pci_release_regions(pdev);
index d84abde5ea295ddb0963b86364933a53c944bc22..568c0c8fb2dc83dea3d9628f511c661db4ca89e4 100644 (file)
@@ -131,22 +131,21 @@ static int wait_i2c_reg(void __iomem *addr)
 }
 
 static int
-dt3155_queue_setup(struct vb2_queue *vq, const void *parg,
+dt3155_queue_setup(struct vb2_queue *vq,
                unsigned int *nbuffers, unsigned int *num_planes,
                unsigned int sizes[], void *alloc_ctxs[])
 
 {
-       const struct v4l2_format *fmt = parg;
        struct dt3155_priv *pd = vb2_get_drv_priv(vq);
        unsigned size = pd->width * pd->height;
 
        if (vq->num_buffers + *nbuffers < 2)
                *nbuffers = 2 - vq->num_buffers;
-       if (fmt && fmt->fmt.pix.sizeimage < size)
-               return -EINVAL;
-       *num_planes = 1;
-       sizes[0] = fmt ? fmt->fmt.pix.sizeimage : size;
        alloc_ctxs[0] = pd->alloc_ctx;
+       if (*num_planes)
+               return sizes[0] < size ? -EINVAL : 0;
+       *num_planes = 1;
+       sizes[0] = size;
        return 0;
 }
 
@@ -271,7 +270,7 @@ static irqreturn_t dt3155_irq_handler_even(int irq, void *dev_id)
 
        spin_lock(&ipd->lock);
        if (ipd->curr_buf && !list_empty(&ipd->dmaq)) {
-               v4l2_get_timestamp(&ipd->curr_buf->timestamp);
+               ipd->curr_buf->vb2_buf.timestamp = ktime_get_ns();
                ipd->curr_buf->sequence = ipd->sequence++;
                ipd->curr_buf->field = V4L2_FIELD_NONE;
                vb2_buffer_done(&ipd->curr_buf->vb2_buf, VB2_BUF_STATE_DONE);
index 145e4749a69d7837f6803c1a4fe96173f3042338..410d97bdf541d6ec34095840e70f64e293975aee 100644 (file)
 #include "ivtv-cards.h"
 #include "ivtv-i2c.h"
 
-#include <media/msp3400.h>
-#include <media/m52790.h>
-#include <media/wm8775.h>
-#include <media/cs53l32a.h>
-#include <media/cx25840.h>
-#include <media/upd64031a.h>
+#include <media/drv-intf/msp3400.h>
+#include <media/i2c/m52790.h>
+#include <media/i2c/wm8775.h>
+#include <media/i2c/cs53l32a.h>
+#include <media/drv-intf/cx25840.h>
+#include <media/i2c/upd64031a.h>
 
 #define MSP_TUNER  MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, \
                                MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER)
index 8a55ccb8f0c97e2595b3b253736628d6e50f4001..9666ca01549c4d25ded2bd4fd4acd9dec7d480ca 100644 (file)
@@ -96,7 +96,7 @@ static int ivtv_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val)
        return 0;
 }
 
-struct cx2341x_handler_ops ivtv_cxhdl_ops = {
+const struct cx2341x_handler_ops ivtv_cxhdl_ops = {
        .s_audio_mode = ivtv_s_audio_mode,
        .s_audio_sampling_freq = ivtv_s_audio_sampling_freq,
        .s_video_encoding = ivtv_s_video_encoding,
index 3999e63583120b133ea779ac149e05749c4132b1..ea397ba837e3d7cd730318a0e81c24522dce88c8 100644 (file)
@@ -21,7 +21,7 @@
 #ifndef IVTV_CONTROLS_H
 #define IVTV_CONTROLS_H
 
-extern struct cx2341x_handler_ops ivtv_cxhdl_ops;
+extern const struct cx2341x_handler_ops ivtv_cxhdl_ops;
 extern const struct v4l2_ctrl_ops ivtv_hdl_out_ops;
 int ivtv_g_pts_frame(struct ivtv *itv, s64 *pts, s64 *frame);
 
index c2e60b4f292d1d8d9791b5c44b0fa76c0ffd854b..374033a5bdaf5384afd22f3415f7c5add20d25ee 100644 (file)
@@ -57,7 +57,7 @@
 #include "ivtv-gpio.h"
 #include <linux/dma-mapping.h>
 #include <media/tveeprom.h>
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
 #include "tuner-xc2028.h"
 
 /* If you have already X v4l cards, then set this to X. This way
@@ -826,7 +826,7 @@ static void ivtv_init_struct2(struct ivtv *itv)
                                IVTV_CARD_INPUT_VID_TUNER)
                        break;
        }
-       if (i == itv->nof_inputs)
+       if (i >= itv->nof_inputs)
                i = 0;
        itv->active_input = i;
        itv->audio_input = itv->card->video_inputs[i].audio_index;
index ee0ef6e48c7d28e314c78f001c85e5a3a1cafffb..6c08dae67a737a7000038007c275dd568d96999b 100644 (file)
@@ -64,8 +64,8 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-fh.h>
 #include <media/tuner.h>
-#include <media/cx2341x.h>
-#include <media/ir-kbd-i2c.h>
+#include <media/drv-intf/cx2341x.h>
+#include <media/i2c/ir-kbd-i2c.h>
 
 #include <linux/ivtv.h>
 
index 605d280d8a5f00f2f142498532eb2c53f40be8fa..c9bd018e53de607f63cfe1367404be228ec90806 100644 (file)
@@ -34,7 +34,7 @@
 #include "ivtv-cards.h"
 #include "ivtv-firmware.h"
 #include <media/v4l2-event.h>
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
 
 /* This function tries to claim the stream for a specific file descriptor.
    If no one else is using this stream then the stream is claimed and
index 4b0e758a7bce38d68deab9d55a1445e21fee201e..5b3095f65dce5ee38bfaa306930b6b826ea057f7 100644 (file)
@@ -26,7 +26,7 @@
 #include "ivtv-ioctl.h"
 #include "ivtv-cards.h"
 #include <linux/firmware.h>
-#include <media/saa7127.h>
+#include <media/i2c/saa7127.h>
 
 #define IVTV_MASK_SPU_ENABLE           0xFFFFFFFE
 #define IVTV_MASK_VPU_ENABLE15                 0xFFFFFFF6
index 1a41ba5c7d3063577806d5d3f44f92c728312d01..bccbf2d18e307d5bd37088ffa2576ad4aaf3094d 100644 (file)
@@ -63,7 +63,7 @@
 #include "ivtv-cards.h"
 #include "ivtv-gpio.h"
 #include "ivtv-i2c.h"
-#include <media/cx25840.h>
+#include <media/drv-intf/cx25840.h>
 
 /* i2c implementation for cx23415/6 chip, ivtv project.
  * Author: Kevin Thayer (nufan_wfk at yahoo.com)
index 9a21c17fc3767fc84e27e76b51c6600becf6293c..2dc4b20f3ac0a80773167a6a8ef52d5a042581c5 100644 (file)
@@ -32,7 +32,7 @@
 #include "ivtv-gpio.h"
 #include "ivtv-controls.h"
 #include "ivtv-cards.h"
-#include <media/saa7127.h>
+#include <media/i2c/saa7127.h>
 #include <media/tveeprom.h>
 #include <media/v4l2-event.h>
 #include <linux/dvb/audio.h>
@@ -831,11 +831,11 @@ static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropca
        struct ivtv *itv = id->itv;
 
        if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
-               cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
+               cropcap->pixelaspect.numerator = itv->is_50hz ? 54 : 11;
+               cropcap->pixelaspect.denominator = itv->is_50hz ? 59 : 10;
        } else if (cropcap->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-               cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
-               cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
+               cropcap->pixelaspect.numerator = itv->is_out_50hz ? 54 : 11;
+               cropcap->pixelaspect.denominator = itv->is_out_50hz ? 59 : 10;
        } else {
                return -EINVAL;
        }
index 8898c569a1c90adab6cbc13e2b0a1afd6b1684d3..0c168f2389049863fd0f2ebb0906a46c1de4cef5 100644 (file)
 #include "ivtv-gpio.h"
 #include "ivtv-routing.h"
 
-#include <media/msp3400.h>
-#include <media/m52790.h>
-#include <media/upd64031a.h>
-#include <media/upd64083.h>
+#include <media/drv-intf/msp3400.h>
+#include <media/i2c/m52790.h>
+#include <media/i2c/upd64031a.h>
+#include <media/i2c/upd64083.h>
 
 /* Selects the audio input and output according to the current
    settings. */
index 3fdbd81b558060c1029c6bf621a45d2aa9fd9016..81e1a5e26efb62b50cf1c6e77d20ec653d36729f 100644 (file)
@@ -277,7 +277,6 @@ static irqreturn_t netup_unidvb_isr(int irq, void *dev_id)
 }
 
 static int netup_unidvb_queue_setup(struct vb2_queue *vq,
-                                   const void *parg,
                                    unsigned int *nbuffers,
                                    unsigned int *nplanes,
                                    unsigned int sizes[],
@@ -580,7 +579,7 @@ static void netup_unidvb_dma_worker(struct work_struct *work)
                        dev_dbg(&ndev->pci_dev->dev,
                                "%s(): buffer %p done, size %d\n",
                                __func__, buf, buf->size);
-                       v4l2_get_timestamp(&buf->vb.timestamp);
+                       buf->vb.vb2_buf.timestamp = ktime_get_ns();
                        vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size);
                        vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
                }
index f720cea80e28ae553183c16a56d2620dd70ab303..e227b02cc1225dedca42ea3effaa356f44e55275 100644 (file)
@@ -309,7 +309,7 @@ void saa7134_buffer_finish(struct saa7134_dev *dev,
        core_dbg("buffer_finish %p\n", q->curr);
 
        /* finish current buffer */
-       v4l2_get_timestamp(&q->curr->vb2.timestamp);
+       q->curr->vb2.vb2_buf.timestamp = ktime_get_ns();
        q->curr->vb2.sequence = q->seq_nr++;
        vb2_buffer_done(&q->curr->vb2.vb2_buf, state);
        q->curr = NULL;
index 7fb5ee7e20acfe37cd4e6df68f7800ef203f2d5c..0584a2adbe9904486b3c4b8e97d658fb123ad600 100644 (file)
@@ -116,7 +116,7 @@ int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2)
 }
 EXPORT_SYMBOL_GPL(saa7134_ts_buffer_prepare);
 
-int saa7134_ts_queue_setup(struct vb2_queue *q, const void *parg,
+int saa7134_ts_queue_setup(struct vb2_queue *q,
                           unsigned int *nbuffers, unsigned int *nplanes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
index 6271b0eb02653a11290b2e35909d3834385f8f25..e76da37c4a8a25810f87679d9cce24aadf8aafb1 100644 (file)
@@ -138,7 +138,7 @@ static int buffer_prepare(struct vb2_buffer *vb2)
                                    saa7134_buffer_startpage(buf));
 }
 
-static int queue_setup(struct vb2_queue *q, const void *parg,
+static int queue_setup(struct vb2_queue *q,
                           unsigned int *nbuffers, unsigned int *nplanes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
index 518086c7aed5cb2bc26e0c873231327e14018ca2..a63c1366a64efad4ad837a5ae927a3417b39d580 100644 (file)
@@ -32,7 +32,7 @@
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-event.h>
-#include <media/saa6588.h>
+#include <media/i2c/saa6588.h>
 
 /* ------------------------------------------------------------------ */
 
@@ -904,7 +904,7 @@ static int buffer_prepare(struct vb2_buffer *vb2)
                                    saa7134_buffer_startpage(buf));
 }
 
-static int queue_setup(struct vb2_queue *q, const void *parg,
+static int queue_setup(struct vb2_queue *q,
                           unsigned int *nbuffers, unsigned int *nplanes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
index 6b6d234f5cab213f4a40c65ed481e168447cdaaf..5938bc7819998dfa6b741822143801f327662d33 100644 (file)
@@ -42,7 +42,7 @@
 #include <media/v4l2-ctrls.h>
 #include <media/tuner.h>
 #include <media/rc-core.h>
-#include <media/ir-kbd-i2c.h>
+#include <media/i2c/ir-kbd-i2c.h>
 #include <media/videobuf2-dma-sg.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -820,7 +820,7 @@ void saa7134_video_fini(struct saa7134_dev *dev);
 
 int saa7134_ts_buffer_init(struct vb2_buffer *vb2);
 int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2);
-int saa7134_ts_queue_setup(struct vb2_queue *q, const void *parg,
+int saa7134_ts_queue_setup(struct vb2_queue *q,
                           unsigned int *nbuffers, unsigned int *nplanes,
                           unsigned int sizes[], void *alloc_ctxs[]);
 int saa7134_ts_start_streaming(struct vb2_queue *vq, unsigned int count);
index 03cbcd2095c6e18848cdb47ce399843fb9406f78..c889ec9f8a5a01c06e5b28324aa506f73df56995 100644 (file)
@@ -25,7 +25,7 @@
 
 #define DEBUG_VARIABLE debug
 
-#include <media/saa7146_vv.h>
+#include <media/drv-intf/saa7146_vv.h>
 #include <linux/module.h>
 
 static int debug;
index 15f0d66ff78a237a85101c7ee04bd50d6830a9ab..c306a92e8909576e41a8aa1bf46ba68a550aa682 100644 (file)
@@ -25,7 +25,7 @@
 
 #define DEBUG_VARIABLE debug
 
-#include <media/saa7146_vv.h>
+#include <media/drv-intf/saa7146_vv.h>
 #include <linux/module.h>
 
 static int debug;
index 0ca1e07ae7837f7cfe6acb239f30186dc8698a2d..504d788076392900bf997feb455efbf37f557fd4 100644 (file)
 
 #define DEBUG_VARIABLE debug
 
-#include <media/saa7146_vv.h>
+#include <media/drv-intf/saa7146_vv.h>
 #include <media/tuner.h>
 #include <media/v4l2-common.h>
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
 #include <linux/module.h>
 
 #include "tea6415c.h"
index 4432fd69b7cbf86db946fb9aa6bfa753cb21434c..67a14c41c227ac3e44643202982eb1c6bf543ef3 100644 (file)
@@ -531,8 +531,7 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc,
 
        if (!ret) {
                vbuf->sequence = solo_enc->sequence++;
-               vbuf->timestamp.tv_sec = vop_sec(vh);
-               vbuf->timestamp.tv_usec = vop_usec(vh);
+               vb->timestamp = ktime_get_ns();
 
                /* Check for motion flags */
                if (solo_is_motion_on(solo_enc) && enc_buf->motion) {
@@ -663,7 +662,6 @@ static int solo_ring_thread(void *data)
 }
 
 static int solo_enc_queue_setup(struct vb2_queue *q,
-                               const void *parg,
                                unsigned int *num_buffers,
                                unsigned int *num_planes, unsigned int sizes[],
                                void *alloc_ctxs[])
index f7ce493b1feed72c27dd4f9d58e1ebe15bec5708..721ff5320de7ffb5bd0ef3aa80dcb1aca3246c59 100644 (file)
@@ -225,7 +225,7 @@ finish_buf:
                vb2_set_plane_payload(vb, 0,
                        solo_vlines(solo_dev) * solo_bytesperline(solo_dev));
                vbuf->sequence = solo_dev->sequence++;
-               v4l2_get_timestamp(&vbuf->timestamp);
+               vb->timestamp = ktime_get_ns();
        }
 
        vb2_buffer_done(vb, error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
@@ -313,7 +313,7 @@ static void solo_stop_thread(struct solo_dev *solo_dev)
        solo_dev->kthread = NULL;
 }
 
-static int solo_queue_setup(struct vb2_queue *q, const void *parg,
+static int solo_queue_setup(struct vb2_queue *q,
                           unsigned int *num_buffers, unsigned int *num_planes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
index 6367b455a7e7ea4f2b053b222b12d6f67b1589bd..753411cbbc9a7c3053b063530726f99aa0f7bcf8 100644 (file)
@@ -265,7 +265,7 @@ static void vip_active_buf_next(struct sta2x11_vip *vip)
 
 
 /* Videobuf2 Operations */
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
                       unsigned int *nbuffers, unsigned int *nplanes,
                       unsigned int sizes[], void *alloc_ctxs[])
 {
@@ -817,7 +817,7 @@ static irqreturn_t vip_irq(int irq, struct sta2x11_vip *vip)
                /* Disable acquisition */
                reg_write(vip, DVP_CTL, reg_read(vip, DVP_CTL) & ~DVP_CTL_ENA);
                /* Remove the active buffer from the list */
-               v4l2_get_timestamp(&vip->active->vb.timestamp);
+               vip->active->vb.vb2_buf.timestamp = ktime_get_ns();
                vip->active->vb.sequence = vip->sequence++;
                vb2_buffer_done(&vip->active->vb.vb2_buf, VB2_BUF_STATE_DONE);
        }
index f89364951ebdfce98cf1f2c86be284c182316c3d..5e18b6796ed949b2db1b1bf9ce07a70ba3a8de71 100644 (file)
@@ -26,7 +26,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * the project's page is at http://www.linuxtv.org/ 
+ * the project's page is at https://linuxtv.org
  */
 
 
@@ -1537,7 +1537,7 @@ static int get_firmware(struct av7110* av7110)
                        printk(KERN_ERR "dvb-ttpci: usually this should be in "
                               "/usr/lib/hotplug/firmware or /lib/firmware\n");
                        printk(KERN_ERR "dvb-ttpci: and can be downloaded from"
-                              " http://www.linuxtv.org/download/dvb/firmware/\n");
+                              " https://linuxtv.org/download/dvb/firmware/\n");
                } else
                        printk(KERN_ERR "dvb-ttpci: cannot request firmware"
                               " (error %i)\n", ret);
@@ -2314,7 +2314,7 @@ static int frontend_init(struct av7110 *av7110)
 /* Budgetpatch note:
  * Original hardware design by Roberto Deza:
  * There is a DVB_Wiki at
- * http://www.linuxtv.org/
+ * https://linuxtv.org
  *
  * New software triggering design by Emard that works on
  * original Roberto Deza's hardware:
index 3a55927edb9544a39e65f99eb1e66604e3754b57..3707ccd0273229c13dfd01112687c339852860eb 100644 (file)
@@ -32,7 +32,7 @@
 #include "stv0297.h"
 #include "l64781.h"
 
-#include <media/saa7146_vv.h>
+#include <media/drv-intf/saa7146_vv.h>
 
 
 #define ANALOG_TUNER_VES1820 1
index 9ed1ec7d3551e668b2e066698ef63cd1120b9566..6fc748e2201736b4da5c8b11859f60712c874e1c 100644 (file)
@@ -25,7 +25,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * the project's page is at http://www.linuxtv.org/ 
+ * the project's page is at https://linuxtv.org
  */
 
 #include <linux/types.h>
@@ -280,9 +280,11 @@ int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen)
 }
 
 
-int av7110_set_volume(struct av7110 *av7110, int volleft, int volright)
+int av7110_set_volume(struct av7110 *av7110, unsigned int volleft,
+                     unsigned int volright)
 {
-       int err, vol, val, balance = 0;
+       unsigned int vol, val, balance = 0;
+       int err;
 
        dprintk(2, "av7110:%p, \n", av7110);
 
@@ -1043,6 +1045,9 @@ static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len
 
        dprintk(2, "av7110:%p, \n", av7110);
 
+       if (len == 0)
+               return 0;
+
        if (!(av7110->playing & RP_VIDEO)) {
                if (av7110_av_start_play(av7110, RP_VIDEO) < 0)
                        return -EBUSY;
index 5f02ef85e47deb28cd00fe5b5823d702a906528b..f52276f4770927f76a4583c280aa4c9729980576 100644 (file)
@@ -10,7 +10,8 @@ extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len);
 extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen);
 extern int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len);
 
-extern int av7110_set_volume(struct av7110 *av7110, int volleft, int volright);
+extern int av7110_set_volume(struct av7110 *av7110, unsigned int volleft,
+                            unsigned int volright);
 extern int av7110_av_stop(struct av7110 *av7110, int av);
 extern int av7110_av_start_record(struct av7110 *av7110, int av,
                          struct dvb_demux_feed *dvbdmxfeed);
index a6079b90252a9f4e65e2514e86f54b84dd5ba226..bc4c65ffd4b9872ed25895300d9dc716a52bee2c 100644 (file)
@@ -25,7 +25,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * the project's page is at http://www.linuxtv.org/ 
+ * the project's page is at https://linuxtv.org
  */
 
 #include <linux/kernel.h>
index 300bd3c9473876fb7b2751da7ab91532397621c2..0583d56ef5ef4fb66ed7350c2331eecdc8c18bbb 100644 (file)
@@ -22,7 +22,7 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
- * the project's page is at http://www.linuxtv.org/
+ * the project's page is at https://linuxtv.org
  */
 
 /* for debugging ARM communication: */
index 6c4076acb1316bbb190566ce95c06495e44183d5..479aff02db81b72e93fda83896b2b6c2be19b4d9 100644 (file)
@@ -22,7 +22,7 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
- * the project's page is at http://www.linuxtv.org/ 
+ * the project's page is at https://linuxtv.org
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 3e469d4e0c8728a908d6d2756a7554b2c76e337e..6f0d0161970e67ce2f988a93e2e04f319b43a3dc 100644 (file)
@@ -30,7 +30,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * the project's page is at http://www.linuxtv.org/ 
+ * the project's page is at https://linuxtv.org
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -46,7 +46,7 @@
 #include "tda1004x.h"
 #include "tua6100.h"
 #include "dvb-pll.h"
-#include <media/saa7146_vv.h>
+#include <media/drv-intf/saa7146_vv.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
index 1feeeff3681b18da4a29d2d2469fe5fdb3a5b2e1..7b27af4d9658aff6b121b466d8b600595821803f 100644 (file)
@@ -26,7 +26,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * the project's page is at http://www.linuxtv.org/
+ * the project's page is at https://linuxtv.org
  */
 
 #include <linux/module.h>
index e9674b40007c17098b3607282017bea2ef1aba3f..6d42dcfd4825bd85348260de5ea3b0a85cfec758 100644 (file)
@@ -31,7 +31,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * the project's page is at http://www.linuxtv.org/ 
+ * the project's page is at https://linuxtv.org
  */
 
 
index b5b65962ce8fc76bd250d804f082a8d0a33d45dd..591dbdfa2a139e8e400aebdabbbcf006832c9a60 100644 (file)
@@ -27,7 +27,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * the project's page is at http://www.linuxtv.org/ 
+ * the project's page is at https://linuxtv.org
  */
 
 #include "av7110.h"
index 99972beca262174fee1066af37912d0d6dcb6503..de54310a26603b23a152b174b3d04c2ce7cd58df 100644 (file)
@@ -31,7 +31,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * the project's page is at http://www.linuxtv.org/ 
+ * the project's page is at https://linuxtv.org
  */
 
 #include "budget.h"
index 1ccbe1a49a4b5d3101d261a98c0ecf3206165727..655eef5236ca5a5266b3432437518959c27deaa4 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 
-#include <media/saa7146.h>
+#include <media/drv-intf/saa7146.h>
 
 extern int budget_debug;
 
index 46642ef9151b644413c3de4e33ee5e9279d2107d..07116a87a57b081033b93d8b76196b2e05518a97 100644 (file)
@@ -376,28 +376,28 @@ static int tw68_buffer_count(unsigned int size, unsigned int count)
 /* ------------------------------------------------------------- */
 /* vb2 queue operations                                          */
 
-static int tw68_queue_setup(struct vb2_queue *q, const void *parg,
+static int tw68_queue_setup(struct vb2_queue *q,
                           unsigned int *num_buffers, unsigned int *num_planes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct tw68_dev *dev = vb2_get_drv_priv(q);
        unsigned tot_bufs = q->num_buffers + *num_buffers;
+       unsigned size = (dev->fmt->depth * dev->width * dev->height) >> 3;
 
-       sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3;
+       if (tot_bufs < 2)
+               tot_bufs = 2;
+       tot_bufs = tw68_buffer_count(size, tot_bufs);
+       *num_buffers = tot_bufs - q->num_buffers;
        alloc_ctxs[0] = dev->alloc_ctx;
        /*
-        * We allow create_bufs, but only if the sizeimage is the same as the
+        * We allow create_bufs, but only if the sizeimage is >= as the
         * current sizeimage. The tw68_buffer_count calculation becomes quite
         * difficult otherwise.
         */
-       if (fmt && fmt->fmt.pix.sizeimage < sizes[0])
-               return -EINVAL;
+       if (*num_planes)
+               return sizes[0] < size ? -EINVAL : 0;
        *num_planes = 1;
-       if (tot_bufs < 2)
-               tot_bufs = 2;
-       tot_bufs = tw68_buffer_count(sizes[0], tot_bufs);
-       *num_buffers = tot_bufs - q->num_buffers;
+       sizes[0] = size;
 
        return 0;
 }
@@ -1016,7 +1016,7 @@ void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status)
                buf = list_entry(dev->active.next, struct tw68_buf, list);
                list_del(&buf->list);
                spin_unlock(&dev->slock);
-               v4l2_get_timestamp(&buf->vb.timestamp);
+               buf->vb.vb2_buf.timestamp = ktime_get_ns();
                buf->vb.field = dev->field;
                buf->vb.sequence = dev->seqnr++;
                vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
index 1136d92af6421bd3333c41579999170cd821ffaf..9d2697f5b455d261b0bdc9447cf13e764a398e14 100644 (file)
@@ -50,7 +50,7 @@
 #include <linux/mutex.h>
 #include <linux/io.h>
 #include <media/v4l2-common.h>
-#include <media/bt819.h>
+#include <media/i2c/bt819.h>
 
 #include "videocodec.h"
 #include "zoran.h"
index ccbc9742cb7aeca46b22edb65eaaae69ce00aa17..0c53805dff0e328e03e624732a78856166164ae5 100644 (file)
@@ -38,7 +38,7 @@ config VIDEO_SH_VOU
        depends on MEDIA_CAMERA_SUPPORT
        depends on VIDEO_DEV && I2C && HAS_DMA
        depends on ARCH_SHMOBILE || COMPILE_TEST
-       select VIDEOBUF_DMA_CONTIG
+       select VIDEOBUF2_DMA_CONTIG
        help
          Support for the Video Output Unit (VOU) on SuperH SoCs.
 
index f0480d687f174b259affc527713a394187e069ee..de32e3a3d4d1ff67d227264ee7f7746bae0c42eb 100644 (file)
@@ -1281,7 +1281,7 @@ static inline void vpfe_schedule_bottom_field(struct vpfe_device *vpfe)
  */
 static inline void vpfe_process_buffer_complete(struct vpfe_device *vpfe)
 {
-       v4l2_get_timestamp(&vpfe->cur_frm->vb.timestamp);
+       vpfe->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns();
        vpfe->cur_frm->vb.field = vpfe->fmt.fmt.pix.field;
        vpfe->cur_frm->vb.sequence = vpfe->sequence++;
        vb2_buffer_done(&vpfe->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE);
@@ -1898,7 +1898,6 @@ static void vpfe_calculate_offsets(struct vpfe_device *vpfe)
 /*
  * vpfe_queue_setup - Callback function for buffer setup.
  * @vq: vb2_queue ptr
- * @fmt: v4l2 format
  * @nbuffers: ptr to number of buffers requested by application
  * @nplanes:: contains number of distinct video planes needed to hold a frame
  * @sizes[]: contains the size (in bytes) of each plane.
@@ -1908,22 +1907,24 @@ static void vpfe_calculate_offsets(struct vpfe_device *vpfe)
  * the buffer count and buffer size
  */
 static int vpfe_queue_setup(struct vb2_queue *vq,
-                           const void *parg,
                            unsigned int *nbuffers, unsigned int *nplanes,
                            unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct vpfe_device *vpfe = vb2_get_drv_priv(vq);
-
-       if (fmt && fmt->fmt.pix.sizeimage < vpfe->fmt.fmt.pix.sizeimage)
-               return -EINVAL;
+       unsigned size = vpfe->fmt.fmt.pix.sizeimage;
 
        if (vq->num_buffers + *nbuffers < 3)
                *nbuffers = 3 - vq->num_buffers;
+       alloc_ctxs[0] = vpfe->alloc_ctx;
+
+       if (*nplanes) {
+               if (sizes[0] < size)
+                       return -EINVAL;
+               size = sizes[0];
+       }
 
        *nplanes = 1;
-       sizes[0] = fmt ? fmt->fmt.pix.sizeimage : vpfe->fmt.fmt.pix.sizeimage;
-       alloc_ctxs[0] = vpfe->alloc_ctx;
+       sizes[0] = size;
 
        vpfe_dbg(1, vpfe,
                "nbuffers=%d, size=%u\n", *nbuffers, sizes[0]);
index 7764b9c482ef9f2af8e1f2b84fd1ebd4454f1d29..d0092dae7a57e6ab391ccf1021eebd4591e28787 100644 (file)
@@ -202,22 +202,20 @@ static void bcap_free_sensor_formats(struct bcap_device *bcap_dev)
 }
 
 static int bcap_queue_setup(struct vb2_queue *vq,
-                               const void *parg,
                                unsigned int *nbuffers, unsigned int *nplanes,
                                unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
 
-       if (fmt && fmt->fmt.pix.sizeimage < bcap_dev->fmt.sizeimage)
-               return -EINVAL;
-
        if (vq->num_buffers + *nbuffers < 2)
                *nbuffers = 2;
+       alloc_ctxs[0] = bcap_dev->alloc_ctx;
+
+       if (*nplanes)
+               return sizes[0] < bcap_dev->fmt.sizeimage ? -EINVAL : 0;
 
        *nplanes = 1;
-       sizes[0] = fmt ? fmt->fmt.pix.sizeimage : bcap_dev->fmt.sizeimage;
-       alloc_ctxs[0] = bcap_dev->alloc_ctx;
+       sizes[0] = bcap_dev->fmt.sizeimage;
 
        return 0;
 }
@@ -406,7 +404,7 @@ static irqreturn_t bcap_isr(int irq, void *dev_id)
        spin_lock(&bcap_dev->lock);
 
        if (!list_empty(&bcap_dev->dma_queue)) {
-               v4l2_get_timestamp(&vbuf->timestamp);
+               vb->timestamp = ktime_get_ns();
                if (ppi->err) {
                        vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
                        ppi->err = false;
index 654e964f84a2f4eac941a204b03de0ace256b2f4..7d28899f89ce16c00cd9f00f424a948fa57e2ae8 100644 (file)
@@ -246,7 +246,7 @@ void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming)
 
                /* Drop frames that do not start/end with a SOI/EOI markers */
                if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG &&
-                   !coda_jpeg_check_buffer(ctx, src_buf)) {
+                   !coda_jpeg_check_buffer(ctx, &src_buf->vb2_buf)) {
                        v4l2_err(&ctx->dev->v4l2_dev,
                                 "dropping invalid JPEG frame %d\n",
                                 ctx->qsequence);
@@ -279,7 +279,7 @@ void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming)
                        if (meta) {
                                meta->sequence = src_buf->sequence;
                                meta->timecode = src_buf->timecode;
-                               meta->timestamp = src_buf->timestamp;
+                               meta->timestamp = src_buf->vb2_buf.timestamp;
                                meta->start = start;
                                meta->end = ctx->bitstream_fifo.kfifo.in &
                                            ctx->bitstream_fifo.kfifo.mask;
@@ -1364,7 +1364,7 @@ static void coda_finish_encode(struct coda_ctx *ctx)
                dst_buf->flags &= ~V4L2_BUF_FLAG_KEYFRAME;
        }
 
-       dst_buf->timestamp = src_buf->timestamp;
+       dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
        dst_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
        dst_buf->flags |=
                src_buf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
@@ -2040,7 +2040,7 @@ static void coda_finish_decode(struct coda_ctx *ctx)
                dst_buf->flags |= ctx->frame_types[ctx->display_idx];
                meta = &ctx->frame_metas[ctx->display_idx];
                dst_buf->timecode = meta->timecode;
-               dst_buf->timestamp = meta->timestamp;
+               dst_buf->vb2_buf.timestamp = meta->timestamp;
 
                trace_coda_dec_rot_done(ctx, dst_buf, meta);
 
index 15516a6e3a3916c090762d360ee10fdaeba0efbc..2d782ce94a67bfec8be38d254559adebecad9c6b 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <linux/of.h>
-#include <linux/platform_data/coda.h>
+#include <linux/platform_data/media/coda.h>
 #include <linux/reset.h>
 
 #include <media/v4l2-ctrls.h>
@@ -131,6 +131,7 @@ static const struct coda_codec coda7_codecs[] = {
        CODA_CODEC(CODA7_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4,  1280, 720),
        CODA_CODEC(CODA7_MODE_ENCODE_MJPG, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_JPEG,   8192, 8192),
        CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264,   V4L2_PIX_FMT_YUV420, 1920, 1088),
+       CODA_CODEC(CODA7_MODE_DECODE_MP2,  V4L2_PIX_FMT_MPEG2,  V4L2_PIX_FMT_YUV420, 1920, 1088),
        CODA_CODEC(CODA7_MODE_DECODE_MP4,  V4L2_PIX_FMT_MPEG4,  V4L2_PIX_FMT_YUV420, 1920, 1088),
        CODA_CODEC(CODA7_MODE_DECODE_MJPG, V4L2_PIX_FMT_JPEG,   V4L2_PIX_FMT_YUV420, 8192, 8192),
 };
@@ -139,6 +140,7 @@ static const struct coda_codec coda9_codecs[] = {
        CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,   1920, 1088),
        CODA_CODEC(CODA9_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4,  1920, 1088),
        CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264,   V4L2_PIX_FMT_YUV420, 1920, 1088),
+       CODA_CODEC(CODA9_MODE_DECODE_MP2,  V4L2_PIX_FMT_MPEG2,  V4L2_PIX_FMT_YUV420, 1920, 1088),
        CODA_CODEC(CODA9_MODE_DECODE_MP4,  V4L2_PIX_FMT_MPEG4,  V4L2_PIX_FMT_YUV420, 1920, 1088),
 };
 
@@ -187,6 +189,7 @@ static const struct coda_video_device coda_bit_decoder = {
        .ops = &coda_bit_decode_ops,
        .src_formats = {
                V4L2_PIX_FMT_H264,
+               V4L2_PIX_FMT_MPEG2,
                V4L2_PIX_FMT_MPEG4,
        },
        .dst_formats = {
@@ -293,7 +296,8 @@ static void coda_get_max_dimensions(struct coda_dev *dev,
                *max_h = h;
 }
 
-const struct coda_video_device *to_coda_video_device(struct video_device *vdev)
+static const struct coda_video_device *to_coda_video_device(struct video_device
+                                                           *vdev)
 {
        struct coda_dev *dev = video_get_drvdata(vdev);
        unsigned int i = vdev - dev->vfd;
@@ -469,6 +473,7 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec,
                /* fallthrough */
        case V4L2_PIX_FMT_H264:
        case V4L2_PIX_FMT_MPEG4:
+       case V4L2_PIX_FMT_MPEG2:
                f->fmt.pix.bytesperline = 0;
                f->fmt.pix.sizeimage = coda_estimate_sizeimage(ctx,
                                                        f->fmt.pix.sizeimage,
@@ -920,6 +925,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = {
        .vidioc_expbuf          = v4l2_m2m_ioctl_expbuf,
        .vidioc_dqbuf           = v4l2_m2m_ioctl_dqbuf,
        .vidioc_create_bufs     = v4l2_m2m_ioctl_create_bufs,
+       .vidioc_prepare_buf     = v4l2_m2m_ioctl_prepare_buf,
 
        .vidioc_streamon        = v4l2_m2m_ioctl_streamon,
        .vidioc_streamoff       = v4l2_m2m_ioctl_streamoff,
@@ -1131,7 +1137,7 @@ static void set_default_params(struct coda_ctx *ctx)
 /*
  * Queue operations
  */
-static int coda_queue_setup(struct vb2_queue *vq, const void *parg,
+static int coda_queue_setup(struct vb2_queue *vq,
                                unsigned int *nbuffers, unsigned int *nplanes,
                                unsigned int sizes[], void *alloc_ctxs[])
 {
@@ -1250,6 +1256,9 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
        struct vb2_v4l2_buffer *buf;
        int ret = 0;
 
+       if (count < 1)
+               return -EINVAL;
+
        q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
        if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
                if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) {
@@ -1262,20 +1271,10 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
                                ret = -EINVAL;
                                goto err;
                        }
-               } else {
-                       if (count < 1) {
-                               ret = -EINVAL;
-                               goto err;
-                       }
                }
 
                ctx->streamon_out = 1;
        } else {
-               if (count < 1) {
-                       ret = -EINVAL;
-                       goto err;
-               }
-
                ctx->streamon_cap = 1;
        }
 
index 96cd42a0baaf6fd3087d82b256697f6890ffdcd8..9f899a6cefed1addb3091e0ebd343d7ba0c1a3a0 100644 (file)
@@ -178,14 +178,28 @@ int coda_jpeg_write_tables(struct coda_ctx *ctx)
        return 0;
 }
 
-bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_v4l2_buffer *vb)
+bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb)
 {
-       void *vaddr = vb2_plane_vaddr(&vb->vb2_buf, 0);
-       u16 soi = be16_to_cpup((__be16 *)vaddr);
-       u16 eoi = be16_to_cpup((__be16 *)(vaddr +
-                         vb2_get_plane_payload(&vb->vb2_buf, 0) - 2));
+       void *vaddr = vb2_plane_vaddr(vb, 0);
+       u16 soi, eoi;
+       int len, i;
+
+       soi = be16_to_cpup((__be16 *)vaddr);
+       if (soi != SOI_MARKER)
+               return false;
+
+       len = vb2_get_plane_payload(vb, 0);
+       vaddr += len - 2;
+       for (i = 0; i < 32; i++) {
+               eoi = be16_to_cpup((__be16 *)(vaddr - i));
+               if (eoi == EOI_MARKER) {
+                       if (i > 0)
+                               vb2_set_plane_payload(vb, 0, len - i);
+                       return true;
+               }
+       }
 
-       return soi == SOI_MARKER && eoi == EOI_MARKER;
+       return false;
 }
 
 /*
index 96532b06bd9e1c840769ce63d3dff5f942aec343..d08e9843e9f2ad542420fb3cbe49e3b0488e48fb 100644 (file)
@@ -138,7 +138,7 @@ struct coda_buffer_meta {
        struct list_head        list;
        u32                     sequence;
        struct v4l2_timecode    timecode;
-       struct timeval          timestamp;
+       u64                     timestamp;
        u32                     start;
        u32                     end;
 };
@@ -289,7 +289,7 @@ void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf,
 
 int coda_h264_padding(int size, char *p);
 
-bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_v4l2_buffer *vb);
+bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb);
 int coda_jpeg_write_tables(struct coda_ctx *ctx);
 void coda_set_jpeg_compression_quality(struct coda_ctx *ctx, int quality);
 
index 469e9d28cec0ec052cdf2899f9b80b4e1a48c1c0..554e710de48717022c3d4d0c7ed4c8b1e6ce02ee 100644 (file)
@@ -3,6 +3,7 @@ config VIDEO_DAVINCI_VPIF_DISPLAY
        depends on VIDEO_V4L2
        depends on ARCH_DAVINCI || COMPILE_TEST
        depends on HAS_DMA
+       depends on I2C
        select VIDEOBUF2_DMA_CONTIG
        select VIDEO_ADV7343 if MEDIA_SUBDRV_AUTOSELECT
        select VIDEO_THS7303 if MEDIA_SUBDRV_AUTOSELECT
@@ -19,6 +20,7 @@ config VIDEO_DAVINCI_VPIF_CAPTURE
        depends on VIDEO_V4L2
        depends on ARCH_DAVINCI || COMPILE_TEST
        depends on HAS_DMA
+       depends on I2C
        select VIDEOBUF2_DMA_CONTIG
        help
          Enables Davinci VPIF module used for capture devices.
@@ -33,6 +35,7 @@ config VIDEO_DM6446_CCDC
        depends on VIDEO_V4L2
        depends on ARCH_DAVINCI || COMPILE_TEST
        depends on HAS_DMA
+       depends on I2C
        select VIDEOBUF_DMA_CONTIG
        help
           Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces
@@ -49,6 +52,7 @@ config VIDEO_DM355_CCDC
        depends on VIDEO_V4L2
        depends on ARCH_DAVINCI || COMPILE_TEST
        depends on HAS_DMA
+       depends on I2C
        select VIDEOBUF_DMA_CONTIG
        help
           Enables DM355 CCD hw module. DM355 CCDC hw interfaces
@@ -64,6 +68,7 @@ config VIDEO_DM365_ISIF
        tristate "TI DM365 ISIF video capture driver"
        depends on VIDEO_V4L2 && ARCH_DAVINCI
        depends on HAS_DMA
+       depends on I2C
        select VIDEOBUF_DMA_CONTIG
        help
           Enables ISIF hw module. This is the hardware module for
@@ -77,6 +82,7 @@ config VIDEO_DAVINCI_VPBE_DISPLAY
        tristate "TI DaVinci VPBE V4L2-Display driver"
        depends on VIDEO_V4L2 && ARCH_DAVINCI
        depends on HAS_DMA
+       depends on I2C
        select VIDEOBUF2_DMA_CONTIG
        help
            Enables Davinci VPBE module used for display devices.
index 6d91422c4e4c755f0b73d6806a9be31e7c00307c..0abcdfe97a6ceb1661d1262979a885a963b00460 100644 (file)
@@ -74,7 +74,7 @@ static void vpbe_isr_even_field(struct vpbe_display *disp_obj,
        if (layer->cur_frm == layer->next_frm)
                return;
 
-       v4l2_get_timestamp(&layer->cur_frm->vb.timestamp);
+       layer->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns();
        vb2_buffer_done(&layer->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE);
        /* Make cur_frm pointing to next_frm */
        layer->cur_frm = layer->next_frm;
@@ -228,28 +228,27 @@ static int vpbe_buffer_prepare(struct vb2_buffer *vb)
  * This function allocates memory for the buffers
  */
 static int
-vpbe_buffer_queue_setup(struct vb2_queue *vq, const void *parg,
+vpbe_buffer_queue_setup(struct vb2_queue *vq,
                        unsigned int *nbuffers, unsigned int *nplanes,
                        unsigned int sizes[], void *alloc_ctxs[])
 
 {
-       const struct v4l2_format *fmt = parg;
        /* Get the file handle object and layer object */
        struct vpbe_layer *layer = vb2_get_drv_priv(vq);
        struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
 
        v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_buffer_setup\n");
 
-       if (fmt && fmt->fmt.pix.sizeimage < layer->pix_fmt.sizeimage)
-               return -EINVAL;
-
        /* Store number of buffers allocated in numbuffer member */
        if (vq->num_buffers + *nbuffers < VPBE_DEFAULT_NUM_BUFS)
                *nbuffers = VPBE_DEFAULT_NUM_BUFS - vq->num_buffers;
+       alloc_ctxs[0] = layer->alloc_ctx;
+
+       if (*nplanes)
+               return sizes[0] < layer->pix_fmt.sizeimage ? -EINVAL : 0;
 
        *nplanes = 1;
-       sizes[0] = fmt ? fmt->fmt.pix.sizeimage : layer->pix_fmt.sizeimage;
-       alloc_ctxs[0] = layer->alloc_ctx;
+       sizes[0] = layer->pix_fmt.sizeimage;
 
        return 0;
 }
index c1e573b7cc6fb9ee66d6bcc05b7e977ecdc708c3..08f7028c7560af37064a9bf5875d6051534abd1b 100644 (file)
@@ -104,7 +104,6 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb)
 /**
  * vpif_buffer_queue_setup : Callback function for buffer setup.
  * @vq: vb2_queue ptr
- * @fmt: v4l2 format
  * @nbuffers: ptr to number of buffers requested by application
  * @nplanes:: contains number of distinct video planes needed to hold a frame
  * @sizes[]: contains the size (in bytes) of each plane.
@@ -114,26 +113,26 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb)
  * the buffer count and buffer size
  */
 static int vpif_buffer_queue_setup(struct vb2_queue *vq,
-                               const void *parg,
                                unsigned int *nbuffers, unsigned int *nplanes,
                                unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct channel_obj *ch = vb2_get_drv_priv(vq);
-       struct common_obj *common;
-
-       common = &ch->common[VPIF_VIDEO_INDEX];
+       struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+       unsigned size = common->fmt.fmt.pix.sizeimage;
 
        vpif_dbg(2, debug, "vpif_buffer_setup\n");
 
-       if (fmt && fmt->fmt.pix.sizeimage < common->fmt.fmt.pix.sizeimage)
-               return -EINVAL;
+       if (*nplanes) {
+               if (sizes[0] < size)
+                       return -EINVAL;
+               size = sizes[0];
+       }
 
        if (vq->num_buffers + *nbuffers < 3)
                *nbuffers = 3 - vq->num_buffers;
 
        *nplanes = 1;
-       sizes[0] = fmt ? fmt->fmt.pix.sizeimage : common->fmt.fmt.pix.sizeimage;
+       sizes[0] = size;
        alloc_ctxs[0] = common->alloc_ctx;
 
        /* Calculate the offset for Y and C data in the buffer */
@@ -331,7 +330,7 @@ static struct vb2_ops video_qops = {
  */
 static void vpif_process_buffer_complete(struct common_obj *common)
 {
-       v4l2_get_timestamp(&common->cur_frm->vb.timestamp);
+       common->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns();
        vb2_buffer_done(&common->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE);
        /* Make curFrm pointing to nextFrm */
        common->cur_frm = common->next_frm;
index fd2780306c1771eae234e74b621c0ac2920ce415..f40755cf1bf2650683583ab4c2684e72e10df175 100644 (file)
@@ -99,7 +99,6 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb)
 /**
  * vpif_buffer_queue_setup : Callback function for buffer setup.
  * @vq: vb2_queue ptr
- * @fmt: v4l2 format
  * @nbuffers: ptr to number of buffers requested by application
  * @nplanes:: contains number of distinct video planes needed to hold a frame
  * @sizes[]: contains the size (in bytes) of each plane.
@@ -109,22 +108,24 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb)
  * the buffer count and buffer size
  */
 static int vpif_buffer_queue_setup(struct vb2_queue *vq,
-                               const void *parg,
                                unsigned int *nbuffers, unsigned int *nplanes,
                                unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct channel_obj *ch = vb2_get_drv_priv(vq);
        struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+       unsigned size = common->fmt.fmt.pix.sizeimage;
 
-       if (fmt && fmt->fmt.pix.sizeimage < common->fmt.fmt.pix.sizeimage)
-               return -EINVAL;
+       if (*nplanes) {
+               if (sizes[0] < size)
+                       return -EINVAL;
+               size = sizes[0];
+       }
 
        if (vq->num_buffers + *nbuffers < 3)
                *nbuffers = 3 - vq->num_buffers;
 
        *nplanes = 1;
-       sizes[0] = fmt ? fmt->fmt.pix.sizeimage : common->fmt.fmt.pix.sizeimage;
+       sizes[0] = size;
        alloc_ctxs[0] = common->alloc_ctx;
 
        /* Calculate the offset for Y and C data  in the buffer */
@@ -330,7 +331,7 @@ static void process_interlaced_mode(int fid, struct common_obj *common)
                /* one frame is displayed If next frame is
                 *  available, release cur_frm and move on */
                /* Copy frame display time */
-               v4l2_get_timestamp(&common->cur_frm->vb.timestamp);
+               common->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns();
                /* Change status of the cur_frm */
                vb2_buffer_done(&common->cur_frm->vb.vb2_buf,
                                        VB2_BUF_STATE_DONE);
@@ -386,8 +387,8 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
                        if (!channel_first_int[i][channel_id]) {
                                /* Mark status of the cur_frm to
                                 * done and unlock semaphore on it */
-                               v4l2_get_timestamp(
-                                       &common->cur_frm->vb.timestamp);
+                               common->cur_frm->vb.vb2_buf.timestamp =
+                                               ktime_get_ns();
                                vb2_buffer_done(&common->cur_frm->vb.vb2_buf,
                                                VB2_BUF_STATE_DONE);
                                /* Make cur_frm pointing to next_frm */
index d82e717acba7b76e90254afcddd605a7b99c8ca8..93782f15b8252092ba31a81b8c135de581f8dc4a 100644 (file)
@@ -86,7 +86,7 @@ void gsc_m2m_job_finish(struct gsc_ctx *ctx, int vb_state)
        dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
 
        if (src_vb && dst_vb) {
-               dst_vb->timestamp = src_vb->timestamp;
+               dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
                dst_vb->timecode = src_vb->timecode;
                dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
                dst_vb->flags |=
@@ -125,7 +125,7 @@ static int gsc_get_bufs(struct gsc_ctx *ctx)
        if (ret)
                return ret;
 
-       dst_vb->timestamp = src_vb->timestamp;
+       dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
 
        return 0;
 }
@@ -212,7 +212,6 @@ put_device:
 }
 
 static int gsc_m2m_queue_setup(struct vb2_queue *vq,
-                       const void *parg,
                        unsigned int *num_buffers, unsigned int *num_planes,
                        unsigned int sizes[], void *allocators[])
 {
index 0eb34ecb8ee442159c5e02bc116c535bf1d7dc44..b6716c57b5db313dd7127637a5532343e9737be8 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include <linux/module.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
 #include "common.h"
 
 /* Called with the media graph mutex held or entity->stream_count > 0. */
index 99e57320e6f7b530984a6655a0152e77bb512ceb..0d549a6c8a13cac5e35fb95d6b47fb943a06f1ce 100644 (file)
@@ -193,7 +193,7 @@ void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf)
            test_bit(ST_CAPT_RUN, &fimc->state) && deq_buf) {
                v_buf = fimc_active_queue_pop(cap);
 
-               v4l2_get_timestamp(&v_buf->vb.timestamp);
+               v_buf->vb.vb2_buf.timestamp = ktime_get_ns();
                v_buf->vb.sequence = cap->frame_count++;
 
                vb2_buffer_done(&v_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
@@ -338,37 +338,36 @@ int fimc_capture_resume(struct fimc_dev *fimc)
 
 }
 
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
                       unsigned int *num_buffers, unsigned int *num_planes,
                       unsigned int sizes[], void *allocators[])
 {
-       const struct v4l2_format *pfmt = parg;
-       const struct v4l2_pix_format_mplane *pixm = NULL;
        struct fimc_ctx *ctx = vq->drv_priv;
        struct fimc_frame *frame = &ctx->d_frame;
        struct fimc_fmt *fmt = frame->fmt;
-       unsigned long wh;
+       unsigned long wh = frame->f_width * frame->f_height;
        int i;
 
-       if (pfmt) {
-               pixm = &pfmt->fmt.pix_mp;
-               fmt = fimc_find_format(&pixm->pixelformat, NULL,
-                                      FMT_FLAGS_CAM | FMT_FLAGS_M2M, -1);
-               wh = pixm->width * pixm->height;
-       } else {
-               wh = frame->f_width * frame->f_height;
-       }
-
        if (fmt == NULL)
                return -EINVAL;
 
+       if (*num_planes) {
+               if (*num_planes != fmt->memplanes)
+                       return -EINVAL;
+               for (i = 0; i < *num_planes; i++) {
+                       if (sizes[i] < (wh * fmt->depth[i]) / 8)
+                               return -EINVAL;
+                       allocators[i] = ctx->fimc_dev->alloc_ctx;
+               }
+               return 0;
+       }
+
        *num_planes = fmt->memplanes;
 
        for (i = 0; i < fmt->memplanes; i++) {
                unsigned int size = (wh * fmt->depth[i]) / 8;
-               if (pixm)
-                       sizes[i] = max(size, pixm->plane_fmt[i].sizeimage);
-               else if (fimc_fmt_is_user_defined(fmt->color))
+
+               if (fimc_fmt_is_user_defined(fmt->color))
                        sizes[i] = frame->payload[i];
                else
                        sizes[i] = max_t(u32, size, frame->payload[i]);
index d336fa2916df8541ffbe63da8a9cf83788ea4901..6b7435453d2a31e6282d17f99b7504611b154ef0 100644 (file)
@@ -27,7 +27,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-mem2mem.h>
 #include <media/v4l2-mediabus.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
 
 #define dbg(fmt, args...) \
        pr_debug("%s:%d: " fmt "\n", __func__, __LINE__, ##args)
index 6e6648446f00130217194a63a60f223d2c83360b..0dd22ec666941014eaff7dc122054dfb22e32095 100644 (file)
@@ -30,7 +30,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/videobuf2-v4l2.h>
 #include <media/videobuf2-dma-contig.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
 
 #include "common.h"
 #include "media-dev.h"
 #include "fimc-is-param.h"
 
 static int isp_video_capture_queue_setup(struct vb2_queue *vq,
-                       const void *parg,
                        unsigned int *num_buffers, unsigned int *num_planes,
                        unsigned int sizes[], void *allocators[])
 {
-       const struct v4l2_format *pfmt = parg;
        struct fimc_isp *isp = vb2_get_drv_priv(vq);
        struct v4l2_pix_format_mplane *vid_fmt = &isp->video_capture.pixfmt;
-       const struct v4l2_pix_format_mplane *pixm = NULL;
-       const struct fimc_fmt *fmt;
+       const struct fimc_fmt *fmt = isp->video_capture.format;
        unsigned int wh, i;
 
-       if (pfmt) {
-               pixm = &pfmt->fmt.pix_mp;
-               fmt = fimc_isp_find_format(&pixm->pixelformat, NULL, -1);
-               wh = pixm->width * pixm->height;
-       } else {
-               fmt = isp->video_capture.format;
-               wh = vid_fmt->width * vid_fmt->height;
-       }
+       wh = vid_fmt->width * vid_fmt->height;
 
        if (fmt == NULL)
                return -EINVAL;
 
        *num_buffers = clamp_t(u32, *num_buffers, FIMC_ISP_REQ_BUFS_MIN,
                                                FIMC_ISP_REQ_BUFS_MAX);
+       if (*num_planes) {
+               if (*num_planes != fmt->memplanes)
+                       return -EINVAL;
+               for (i = 0; i < *num_planes; i++) {
+                       if (sizes[i] < (wh * fmt->depth[i]) / 8)
+                               return -EINVAL;
+                       allocators[i] = isp->alloc_ctx;
+               }
+               return 0;
+       }
+
        *num_planes = fmt->memplanes;
 
        for (i = 0; i < fmt->memplanes; i++) {
-               unsigned int size = (wh * fmt->depth[i]) / 8;
-               if (pixm)
-                       sizes[i] = max(size, pixm->plane_fmt[i].sizeimage);
-               else
-                       sizes[i] = size;
+               sizes[i] = (wh * fmt->depth[i]) / 8;
                allocators[i] = isp->alloc_ctx;
        }
 
@@ -254,7 +251,7 @@ void fimc_isp_video_irq_handler(struct fimc_is *is)
        buf_index = (is->i2h_cmd.args[1] - 1) % video->buf_count;
        vbuf = &video->buffers[buf_index]->vb;
 
-       v4l2_get_timestamp(&vbuf->timestamp);
+       vbuf->vb2_buf.timestamp = ktime_get_ns();
        vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE);
 
        video->buf_mask &= ~BIT(buf_index);
index c2d25df85db9d157ec1baa088fba3e245336338f..e0686b5f1bf8697660e66b7d529ecc9090e7a237 100644 (file)
@@ -24,7 +24,7 @@
 #include <media/videobuf2-v4l2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-mediabus.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
 
 extern int fimc_isp_debug;
 
index 0477716a20dba4c248c3d376514e752b887b8079..f0acc550d065816cb5693a28d50bed0dc83da6a3 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/bitops.h>
 #include <linux/delay.h>
 #include <linux/io.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
 
 #include "fimc-lite-reg.h"
 #include "fimc-lite.h"
index 60660c3a5de0da466ec0f714f7a5c4a536e1bc09..639ee710499ed79838a3c121cd944dfd95033791 100644 (file)
@@ -30,7 +30,7 @@
 #include <media/v4l2-mem2mem.h>
 #include <media/videobuf2-v4l2.h>
 #include <media/videobuf2-dma-contig.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
 
 #include "common.h"
 #include "fimc-core.h"
@@ -292,7 +292,7 @@ static irqreturn_t flite_irq_handler(int irq, void *priv)
            test_bit(ST_FLITE_RUN, &fimc->state) &&
            !list_empty(&fimc->active_buf_q)) {
                vbuf = fimc_lite_active_queue_pop(fimc);
-               v4l2_get_timestamp(&vbuf->vb.timestamp);
+               vbuf->vb.vb2_buf.timestamp = ktime_get_ns();
                vbuf->vb.sequence = fimc->frame_count++;
                flite_hw_mask_dma_buffer(fimc, vbuf->index);
                vb2_buffer_done(&vbuf->vb.vb2_buf, VB2_BUF_STATE_DONE);
@@ -355,37 +355,34 @@ static void stop_streaming(struct vb2_queue *q)
        fimc_lite_stop_capture(fimc, false);
 }
 
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
                       unsigned int *num_buffers, unsigned int *num_planes,
                       unsigned int sizes[], void *allocators[])
 {
-       const struct v4l2_format *pfmt = parg;
-       const struct v4l2_pix_format_mplane *pixm = NULL;
        struct fimc_lite *fimc = vq->drv_priv;
        struct flite_frame *frame = &fimc->out_frame;
        const struct fimc_fmt *fmt = frame->fmt;
-       unsigned long wh;
+       unsigned long wh = frame->f_width * frame->f_height;
        int i;
 
-       if (pfmt) {
-               pixm = &pfmt->fmt.pix_mp;
-               fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, 0, -1);
-               wh = pixm->width * pixm->height;
-       } else {
-               wh = frame->f_width * frame->f_height;
-       }
-
        if (fmt == NULL)
                return -EINVAL;
 
+       if (*num_planes) {
+               if (*num_planes != fmt->memplanes)
+                       return -EINVAL;
+               for (i = 0; i < *num_planes; i++) {
+                       if (sizes[i] < (wh * fmt->depth[i]) / 8)
+                               return -EINVAL;
+                       allocators[i] = fimc->alloc_ctx;
+               }
+               return 0;
+       }
+
        *num_planes = fmt->memplanes;
 
        for (i = 0; i < fmt->memplanes; i++) {
-               unsigned int size = (wh * fmt->depth[i]) / 8;
-               if (pixm)
-                       sizes[i] = max(size, pixm->plane_fmt[i].sizeimage);
-               else
-                       sizes[i] = size;
+               sizes[i] = (wh * fmt->depth[i]) / 8;
                allocators[i] = fimc->alloc_ctx;
        }
 
index b302305dedbeedf16d0e35e2229162d8b396fb1e..11690d563e06b7f830bca13a26daa75e2511d6b0 100644 (file)
@@ -23,7 +23,7 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-mediabus.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
 
 #define FIMC_LITE_DRV_NAME     "exynos-fimc-lite"
 #define FLITE_CLK_NAME         "flite"
index 4d1d64a46b2155770dead95d8a23c60bd664475f..5aa857c7b631e602b4a60f961dd91d828d4468ae 100644 (file)
@@ -132,7 +132,7 @@ static void fimc_device_run(void *priv)
        if (ret)
                goto dma_unlock;
 
-       dst_vb->timestamp = src_vb->timestamp;
+       dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
        dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
        dst_vb->flags |=
                src_vb->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
@@ -176,7 +176,7 @@ static void fimc_job_abort(void *priv)
        fimc_m2m_shutdown(priv);
 }
 
-static int fimc_queue_setup(struct vb2_queue *vq, const void *parg,
+static int fimc_queue_setup(struct vb2_queue *vq,
                            unsigned int *num_buffers, unsigned int *num_planes,
                            unsigned int sizes[], void *allocators[])
 {
index df0cbcb69b6bc2eca32d097920e04194d56b6a82..0806724553a23f9a0a4f1d26a096e12fa2eafb4e 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/io.h>
 #include <linux/regmap.h>
 
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
 #include "media-dev.h"
 
 #include "fimc-reg.h"
index 4f5586a4cbffa05d8f2079696806622337fead70..9481ce3201a2c021be254fa7975f22abf997051e 100644 (file)
@@ -31,7 +31,7 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-of.h>
 #include <media/media-device.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
 
 #include "media-dev.h"
 #include "fimc-core.h"
index 03214541f1493422e57749dbf6e62af138d74c41..93a96126929b51e47eaa67210017f0e117554a92 100644 (file)
@@ -19,7 +19,7 @@
 #include <media/media-entity.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-subdev.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
 
 #include "fimc-core.h"
 #include "fimc-lite.h"
index 4b85105dc159b736f37b6c44fe769298e141140d..ff5dabf24694ae5b33ceb1ffa70a0a0d2bf43ab6 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/videodev2.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
 #include <media/v4l2-of.h>
 #include <media/v4l2-subdev.h>
 
index 29973f9bf8db5c0fa9eff5840c965b0466b3aa17..7383818c2be6cec6bf841abe2bd366f10151438a 100644 (file)
@@ -207,7 +207,7 @@ static void dma_callback(void *data)
        src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
        dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
 
-       dst_vb->timestamp = src_vb->timestamp;
+       dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
        dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
        dst_vb->flags |=
                src_vb->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
@@ -798,7 +798,6 @@ struct vb2_dc_conf {
 };
 
 static int deinterlace_queue_setup(struct vb2_queue *vq,
-                               const void *parg,
                                unsigned int *nbuffers, unsigned int *nplanes,
                                unsigned int sizes[], void *alloc_ctxs[])
 {
index aa2b44041d3fac40f6d2242c566032ec074d7338..9b878deb1437dc794f4db1ffab0a321de4e3f597 100644 (file)
@@ -25,7 +25,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-event.h>
-#include <media/ov7670.h>
+#include <media/i2c/ov7670.h>
 #include <media/videobuf2-vmalloc.h>
 #include <media/videobuf2-dma-contig.h>
 #include <media/videobuf2-dma-sg.h>
@@ -226,7 +226,7 @@ static void mcam_buffer_done(struct mcam_camera *cam, int frame,
        vbuf->vb2_buf.planes[0].bytesused = cam->pix_format.sizeimage;
        vbuf->sequence = cam->buf_seq[frame];
        vbuf->field = V4L2_FIELD_NONE;
-       v4l2_get_timestamp(&vbuf->timestamp);
+       vbuf->vb2_buf.timestamp = ktime_get_ns();
        vb2_set_plane_payload(&vbuf->vb2_buf, 0, cam->pix_format.sizeimage);
        vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE);
 }
@@ -1049,24 +1049,25 @@ static int mcam_read_setup(struct mcam_camera *cam)
  */
 
 static int mcam_vb_queue_setup(struct vb2_queue *vq,
-               const void *parg, unsigned int *nbufs,
+               unsigned int *nbufs,
                unsigned int *num_planes, unsigned int sizes[],
                void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct mcam_camera *cam = vb2_get_drv_priv(vq);
        int minbufs = (cam->buffer_mode == B_DMA_contig) ? 3 : 2;
+       unsigned size = cam->pix_format.sizeimage;
 
-       if (fmt && fmt->fmt.pix.sizeimage < cam->pix_format.sizeimage)
-               return -EINVAL;
-       sizes[0] = fmt ? fmt->fmt.pix.sizeimage : cam->pix_format.sizeimage;
-       *num_planes = 1; /* Someday we have to support planar formats... */
        if (*nbufs < minbufs)
                *nbufs = minbufs;
        if (cam->buffer_mode == B_DMA_contig)
                alloc_ctxs[0] = cam->vb_alloc_ctx;
        else if (cam->buffer_mode == B_DMA_sg)
                alloc_ctxs[0] = cam->vb_alloc_ctx_sg;
+
+       if (*num_planes)
+               return sizes[0] < size ? -EINVAL : 0;
+       sizes[0] = size;
+       *num_planes = 1; /* Someday we have to support planar formats... */
        return 0;
 }
 
index b5f165a68566e172404d4ea3b96c7dcd5f530ed7..816f4b6a7b8ee574b51688b58ac3da96cee79fe1 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/mmp-camera.h>
+#include <linux/platform_data/media/mmp-camera.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
index 03a1b606655df8cf81cafea470d600107be58e05..3c4012d42d693da1b8e9931bb4c5c67a8a7bd30f 100644 (file)
@@ -375,7 +375,7 @@ static irqreturn_t emmaprp_irq(int irq_emma, void *data)
                        src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
                        dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
 
-                       dst_vb->timestamp = src_vb->timestamp;
+                       dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
                        dst_vb->flags &=
                                ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
                        dst_vb->flags |=
@@ -689,7 +689,6 @@ static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = {
  * Queue operations
  */
 static int emmaprp_queue_setup(struct vb2_queue *vq,
-                               const void *parg,
                                unsigned int *nbuffers, unsigned int *nplanes,
                                unsigned int sizes[], void *alloc_ctxs[])
 {
index c6e252760c621d52a6f96ded885cb1a292735539..b8638e4e1627734c714aa77e073d11ddbf0b992b 100644 (file)
@@ -79,10 +79,12 @@ void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout)
        int j;
 
        for (j = 0; j < VRFB_NUM_BUFS; j++) {
-               omap_vout_free_buffer(vout->smsshado_virt_addr[j],
-                               vout->smsshado_size);
-               vout->smsshado_virt_addr[j] = 0;
-               vout->smsshado_phy_addr[j] = 0;
+               if (vout->smsshado_virt_addr[j]) {
+                       omap_vout_free_buffer(vout->smsshado_virt_addr[j],
+                                             vout->smsshado_size);
+                       vout->smsshado_virt_addr[j] = 0;
+                       vout->smsshado_phy_addr[j] = 0;
+               }
        }
 }
 
index f4f591652432df898ea924a1a8f2585b08785a1f..ecadca3e945b4449965e56bfcf5946d47ab28bb1 100644 (file)
@@ -320,7 +320,6 @@ isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh)
  */
 
 static int isp_video_queue_setup(struct vb2_queue *queue,
-                                const void *parg,
                                 unsigned int *count, unsigned int *num_planes,
                                 unsigned int sizes[], void *alloc_ctxs[])
 {
@@ -467,7 +466,7 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
        list_del(&buf->irqlist);
        spin_unlock_irqrestore(&video->irqlock, flags);
 
-       v4l2_get_timestamp(&buf->vb.timestamp);
+       buf->vb.vb2_buf.timestamp = ktime_get_ns();
 
        /* Do frame number propagation only if this is the output video node.
         * Frame number either comes from the CSI receivers or it gets
index f8e3e83c52a26328177a0d3a4895e271d2cb1c6a..485f5259acb082d4e71484c12ad730c0142dc77c 100644 (file)
@@ -1015,28 +1015,33 @@ error_free:
  * ============================================================================
  */
 static int jpu_queue_setup(struct vb2_queue *vq,
-                          const void *parg,
                           unsigned int *nbuffers, unsigned int *nplanes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct jpu_ctx *ctx = vb2_get_drv_priv(vq);
        struct jpu_q_data *q_data;
        unsigned int i;
 
        q_data = jpu_get_q_data(ctx, vq->type);
 
-       *nplanes = q_data->format.num_planes;
+       if (*nplanes) {
+               if (*nplanes != q_data->format.num_planes)
+                       return -EINVAL;
 
-       for (i = 0; i < *nplanes; i++) {
-               unsigned int q_size = q_data->format.plane_fmt[i].sizeimage;
-               unsigned int f_size = fmt ?
-                       fmt->fmt.pix_mp.plane_fmt[i].sizeimage : 0;
+               for (i = 0; i < *nplanes; i++) {
+                       unsigned int q_size = q_data->format.plane_fmt[i].sizeimage;
 
-               if (fmt && f_size < q_size)
-                       return -EINVAL;
+                       if (sizes[i] < q_size)
+                               return -EINVAL;
+                       alloc_ctxs[i] = ctx->jpu->alloc_ctx;
+               }
+               return 0;
+       }
 
-               sizes[i] = fmt ? f_size : q_size;
+       *nplanes = q_data->format.num_planes;
+
+       for (i = 0; i < *nplanes; i++) {
+               sizes[i] = q_data->format.plane_fmt[i].sizeimage;
                alloc_ctxs[i] = ctx->jpu->alloc_ctx;
        }
 
@@ -1300,17 +1305,17 @@ static int jpu_release(struct file *file)
        struct jpu *jpu = video_drvdata(file);
        struct jpu_ctx *ctx = fh_to_ctx(file->private_data);
 
-       mutex_lock(&jpu->mutex);
-       if (--jpu->ref_count == 0)
-               clk_disable_unprepare(jpu->clk);
-       mutex_unlock(&jpu->mutex);
-
        v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
        v4l2_ctrl_handler_free(&ctx->ctrl_handler);
        v4l2_fh_del(&ctx->fh);
        v4l2_fh_exit(&ctx->fh);
        kfree(ctx);
 
+       mutex_lock(&jpu->mutex);
+       if (--jpu->ref_count == 0)
+               clk_disable_unprepare(jpu->clk);
+       mutex_unlock(&jpu->mutex);
+
        return 0;
 }
 
@@ -1560,12 +1565,9 @@ static irqreturn_t jpu_irq_handler(int irq, void *dev_id)
                }
 
                dst_buf->field = src_buf->field;
-               dst_buf->timestamp = src_buf->timestamp;
+               dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
                if (src_buf->flags & V4L2_BUF_FLAG_TIMECODE)
                        dst_buf->timecode = src_buf->timecode;
-               dst_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
-               dst_buf->flags |= src_buf->flags &
-                                       V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
                dst_buf->flags = src_buf->flags &
                        (V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_KEYFRAME |
                         V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME |
index 537b858cb94a62c36d93cc57c1c1dc0091be1514..ec3abbed87d9051e56032f3df1c1aeeaecbc5978 100644 (file)
@@ -338,7 +338,7 @@ irqreturn_t s3c_camif_irq_handler(int irq, void *priv)
 
                if (!WARN_ON(vbuf == NULL)) {
                        /* Dequeue a filled buffer */
-                       v4l2_get_timestamp(&vbuf->vb.timestamp);
+                       vbuf->vb.vb2_buf.timestamp = ktime_get_ns();
                        vbuf->vb.sequence = vp->frame_sequence++;
                        vb2_buffer_done(&vbuf->vb.vb2_buf, VB2_BUF_STATE_DONE);
 
@@ -435,39 +435,28 @@ static void stop_streaming(struct vb2_queue *vq)
        camif_stop_capture(vp);
 }
 
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
                       unsigned int *num_buffers, unsigned int *num_planes,
                       unsigned int sizes[], void *allocators[])
 {
-       const struct v4l2_format *pfmt = parg;
-       const struct v4l2_pix_format *pix = NULL;
        struct camif_vp *vp = vb2_get_drv_priv(vq);
        struct camif_dev *camif = vp->camif;
        struct camif_frame *frame = &vp->out_frame;
-       const struct camif_fmt *fmt;
+       const struct camif_fmt *fmt = vp->out_fmt;
        unsigned int size;
 
-       if (pfmt) {
-               pix = &pfmt->fmt.pix;
-               fmt = s3c_camif_find_format(vp, &pix->pixelformat, -1);
-               if (fmt == NULL)
-                       return -EINVAL;
-               size = (pix->width * pix->height * fmt->depth) / 8;
-       } else {
-               fmt = vp->out_fmt;
-               if (fmt == NULL)
-                       return -EINVAL;
-               size = (frame->f_width * frame->f_height * fmt->depth) / 8;
-       }
-
-       *num_planes = 1;
+       if (fmt == NULL)
+               return -EINVAL;
 
-       if (pix)
-               sizes[0] = max(size, pix->sizeimage);
-       else
-               sizes[0] = size;
+       size = (frame->f_width * frame->f_height * fmt->depth) / 8;
        allocators[0] = camif->alloc_ctx;
 
+       if (*num_planes)
+               return sizes[0] < size ? -EINVAL : 0;
+
+       *num_planes = 1;
+       sizes[0] = size;
+
        pr_debug("size: %u\n", sizes[0]);
        return 0;
 }
index adaf1969ef6372e501441860f91b6f271de9fc88..57cbc3d9725def9051be0f702f6bc672100aa1f7 100644 (file)
@@ -26,7 +26,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-mediabus.h>
 #include <media/videobuf2-v4l2.h>
-#include <media/s3c_camif.h>
+#include <media/drv-intf/s3c_camif.h>
 
 #define S3C_CAMIF_DRIVER_NAME  "s3c-camif"
 #define CAMIF_REQ_BUFS_MIN     3
index af2d472ea1ddd86c1f7e8b762a6da3060326ad24..5ad36c1c2a5d37820c14283980a46bd871199530 100644 (file)
@@ -13,7 +13,7 @@
 #define CAMIF_REGS_H_
 
 #include "camif-core.h"
-#include <media/s3c_camif.h>
+#include <media/drv-intf/s3c_camif.h>
 
 /*
  * The id argument indicates the processing path:
index e1936d9d27dacd8d9c3d5f0398569266d72493ac..74bd46ca7942bed381d32064b983b09d3bc24185 100644 (file)
@@ -101,7 +101,7 @@ static struct g2d_frame *get_frame(struct g2d_ctx *ctx,
        }
 }
 
-static int g2d_queue_setup(struct vb2_queue *vq, const void *parg,
+static int g2d_queue_setup(struct vb2_queue *vq,
                           unsigned int *nbuffers, unsigned int *nplanes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
@@ -552,7 +552,7 @@ static irqreturn_t g2d_isr(int irq, void *prv)
        BUG_ON(dst == NULL);
 
        dst->timecode = src->timecode;
-       dst->timestamp = src->timestamp;
+       dst->vb2_buf.timestamp = src->vb2_buf.timestamp;
        dst->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
        dst->flags |=
                src->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
index 4a608cbe0fdb4628975db86730b3ba28f3dae24a..c3b13a630edfcf4ce0826e2af1d6bfdbf9b46ff0 100644 (file)
@@ -2430,7 +2430,6 @@ static struct v4l2_m2m_ops exynos4_jpeg_m2m_ops = {
  */
 
 static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
-                          const void *parg,
                           unsigned int *nbuffers, unsigned int *nplanes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
@@ -2621,7 +2620,7 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
        }
 
        dst_buf->timecode = src_buf->timecode;
-       dst_buf->timestamp = src_buf->timestamp;
+       dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
        dst_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
        dst_buf->flags |=
                src_buf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
@@ -2752,7 +2751,7 @@ static irqreturn_t exynos3250_jpeg_irq(int irq, void *dev_id)
        dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
 
        dst_buf->timecode = src_buf->timecode;
-       dst_buf->timestamp = src_buf->timestamp;
+       dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
 
        v4l2_m2m_buf_done(src_buf, state);
        if (curr_ctx->mode == S5P_JPEG_ENCODE)
index 3ffe2ecfd5efe37649750c64636c91c042f57a47..927ab492877931d87ce9f58af34f236df31ad360 100644 (file)
@@ -85,6 +85,26 @@ void set_work_bit_irqsave(struct s5p_mfc_ctx *ctx)
        spin_unlock_irqrestore(&dev->condlock, flags);
 }
 
+int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev)
+{
+       unsigned long flags;
+       int ctx;
+
+       spin_lock_irqsave(&dev->condlock, flags);
+       ctx = dev->curr_ctx;
+       do {
+               ctx = (ctx + 1) % MFC_NUM_CONTEXTS;
+               if (ctx == dev->curr_ctx) {
+                       if (!test_bit(ctx, &dev->ctx_work_bits))
+                               ctx = -EAGAIN;
+                       break;
+               }
+       } while (!test_bit(ctx, &dev->ctx_work_bits));
+       spin_unlock_irqrestore(&dev->condlock, flags);
+
+       return ctx;
+}
+
 /* Wake up context wait_queue */
 static void wake_up_ctx(struct s5p_mfc_ctx *ctx, unsigned int reason,
                        unsigned int err)
@@ -105,6 +125,20 @@ static void wake_up_dev(struct s5p_mfc_dev *dev, unsigned int reason,
        wake_up(&dev->queue);
 }
 
+void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq)
+{
+       struct s5p_mfc_buf *b;
+       int i;
+
+       while (!list_empty(lh)) {
+               b = list_entry(lh->next, struct s5p_mfc_buf, list);
+               for (i = 0; i < b->b->vb2_buf.num_planes; i++)
+                       vb2_set_plane_payload(&b->b->vb2_buf, i, 0);
+               vb2_buffer_done(&b->b->vb2_buf, VB2_BUF_STATE_ERROR);
+               list_del(&b->list);
+       }
+}
+
 static void s5p_mfc_watchdog(unsigned long arg)
 {
        struct s5p_mfc_dev *dev = (struct s5p_mfc_dev *)arg;
@@ -150,10 +184,8 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work)
                if (!ctx)
                        continue;
                ctx->state = MFCINST_ERROR;
-               s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
-                                               &ctx->dst_queue, &ctx->vq_dst);
-               s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
-                                               &ctx->src_queue, &ctx->vq_src);
+               s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+               s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
                clear_work_bit(ctx);
                wake_up_ctx(ctx, S5P_MFC_R2H_CMD_ERR_RET, 0);
        }
@@ -233,8 +265,8 @@ static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx)
                                == dec_y_addr) {
                        dst_buf->b->timecode =
                                                src_buf->b->timecode;
-                       dst_buf->b->timestamp =
-                                               src_buf->b->timestamp;
+                       dst_buf->b->vb2_buf.timestamp =
+                                               src_buf->b->vb2_buf.timestamp;
                        dst_buf->b->flags &=
                                ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
                        dst_buf->b->flags |=
@@ -327,7 +359,6 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
        unsigned int dst_frame_status;
        unsigned int dec_frame_status;
        struct s5p_mfc_buf *src_buf;
-       unsigned long flags;
        unsigned int res_change;
 
        dst_frame_status = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev)
@@ -343,17 +374,16 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
        if (res_change == S5P_FIMV_RES_INCREASE ||
                res_change == S5P_FIMV_RES_DECREASE) {
                ctx->state = MFCINST_RES_CHANGE_INIT;
-               s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+               s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
                wake_up_ctx(ctx, reason, err);
                WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
                s5p_mfc_clock_off();
-               s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+               s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
                return;
        }
        if (ctx->dpb_flush_flag)
                ctx->dpb_flush_flag = 0;
 
-       spin_lock_irqsave(&dev->irqlock, flags);
        /* All frames remaining in the buffer have been extracted  */
        if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_EMPTY) {
                if (ctx->state == MFCINST_RES_CHANGE_FLUSH) {
@@ -413,11 +443,10 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
                }
        }
 leave_handle_frame:
-       spin_unlock_irqrestore(&dev->irqlock, flags);
        if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING)
                                    || ctx->dst_queue_cnt < ctx->pb_count)
                clear_work_bit(ctx);
-       s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+       s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
        wake_up_ctx(ctx, reason, err);
        WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
        s5p_mfc_clock_off();
@@ -425,15 +454,13 @@ leave_handle_frame:
        if (test_bit(0, &dev->enter_suspend))
                wake_up_dev(dev, reason, err);
        else
-               s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+               s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
 }
 
 /* Error handling for interrupt */
 static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev,
                struct s5p_mfc_ctx *ctx, unsigned int reason, unsigned int err)
 {
-       unsigned long flags;
-
        mfc_err("Interrupt Error: %08x\n", err);
 
        if (ctx != NULL) {
@@ -450,13 +477,9 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev,
                        clear_work_bit(ctx);
                        ctx->state = MFCINST_ERROR;
                        /* Mark all dst buffers as having an error */
-                       spin_lock_irqsave(&dev->irqlock, flags);
-                       s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
-                                               &ctx->dst_queue, &ctx->vq_dst);
+                       s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
                        /* Mark all src buffers as having an error */
-                       s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
-                                               &ctx->src_queue, &ctx->vq_src);
-                       spin_unlock_irqrestore(&dev->irqlock, flags);
+                       s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
                        wake_up_ctx(ctx, reason, err);
                        break;
                default:
@@ -467,7 +490,7 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev,
                }
        }
        WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
-       s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+       s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
        s5p_mfc_clock_off();
        wake_up_dev(dev, reason, err);
        return;
@@ -491,7 +514,7 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
                ctx->img_height = s5p_mfc_hw_call(dev->mfc_ops, get_img_height,
                                dev);
 
-               s5p_mfc_hw_call_void(dev->mfc_ops, dec_calc_dpb_size, ctx);
+               s5p_mfc_hw_call(dev->mfc_ops, dec_calc_dpb_size, ctx);
 
                ctx->pb_count = s5p_mfc_hw_call(dev->mfc_ops, get_dpb_count,
                                dev);
@@ -518,11 +541,11 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
                        ctx->head_processed = 1;
                }
        }
-       s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+       s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
        clear_work_bit(ctx);
        WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
        s5p_mfc_clock_off();
-       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
        wake_up_ctx(ctx, reason, err);
 }
 
@@ -532,12 +555,11 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
 {
        struct s5p_mfc_buf *src_buf;
        struct s5p_mfc_dev *dev;
-       unsigned long flags;
 
        if (ctx == NULL)
                return;
        dev = ctx->dev;
-       s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+       s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
        ctx->int_type = reason;
        ctx->int_err = err;
        ctx->int_cond = 1;
@@ -545,7 +567,6 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
        if (err == 0) {
                ctx->state = MFCINST_RUNNING;
                if (!ctx->dpb_flush_flag && ctx->head_processed) {
-                       spin_lock_irqsave(&dev->irqlock, flags);
                        if (!list_empty(&ctx->src_queue)) {
                                src_buf = list_entry(ctx->src_queue.next,
                                             struct s5p_mfc_buf, list);
@@ -554,7 +575,6 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
                                vb2_buffer_done(&src_buf->b->vb2_buf,
                                                VB2_BUF_STATE_DONE);
                        }
-                       spin_unlock_irqrestore(&dev->irqlock, flags);
                } else {
                        ctx->dpb_flush_flag = 0;
                }
@@ -563,7 +583,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
                s5p_mfc_clock_off();
 
                wake_up(&ctx->queue);
-               s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+               s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
        } else {
                WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
 
@@ -582,7 +602,6 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx)
 
        ctx->state = MFCINST_FINISHED;
 
-       spin_lock(&dev->irqlock);
        if (!list_empty(&ctx->dst_queue)) {
                mb_entry = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf,
                                                                        list);
@@ -591,7 +610,6 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx)
                vb2_set_plane_payload(&mb_entry->b->vb2_buf, 0, 0);
                vb2_buffer_done(&mb_entry->b->vb2_buf, VB2_BUF_STATE_DONE);
        }
-       spin_unlock(&dev->irqlock);
 
        clear_work_bit(ctx);
 
@@ -599,7 +617,7 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx)
 
        s5p_mfc_clock_off();
        wake_up(&ctx->queue);
-       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
 }
 
 /* Interrupt processing */
@@ -613,6 +631,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
        mfc_debug_enter();
        /* Reset the timeout watchdog */
        atomic_set(&dev->watchdog_cnt, 0);
+       spin_lock(&dev->irqlock);
        ctx = dev->ctx[dev->curr_ctx];
        /* Get the reason of interrupt and the error code */
        reason = s5p_mfc_hw_call(dev->mfc_ops, get_int_reason, dev);
@@ -639,15 +658,15 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
 
                        if (ctx->state == MFCINST_FINISHING &&
                                                list_empty(&ctx->ref_queue)) {
-                               s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+                               s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
                                s5p_mfc_handle_stream_complete(ctx);
                                break;
                        }
-                       s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+                       s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
                        wake_up_ctx(ctx, reason, err);
                        WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
                        s5p_mfc_clock_off();
-                       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+                       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
                } else {
                        s5p_mfc_handle_frame(ctx, reason, err);
                }
@@ -677,7 +696,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
        case S5P_MFC_R2H_CMD_WAKEUP_RET:
                if (ctx)
                        clear_work_bit(ctx);
-               s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+               s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
                wake_up_dev(dev, reason, err);
                clear_bit(0, &dev->hw_lock);
                clear_bit(0, &dev->enter_suspend);
@@ -688,7 +707,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
                break;
 
        case S5P_MFC_R2H_CMD_COMPLETE_SEQ_RET:
-               s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+               s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
                ctx->int_type = reason;
                ctx->int_err = err;
                s5p_mfc_handle_stream_complete(ctx);
@@ -702,12 +721,13 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
 
        default:
                mfc_debug(2, "Unknown int reason\n");
-               s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+               s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
        }
+       spin_unlock(&dev->irqlock);
        mfc_debug_leave();
        return IRQ_HANDLED;
 irq_cleanup_hw:
-       s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+       s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
        ctx->int_type = reason;
        ctx->int_err = err;
        ctx->int_cond = 1;
@@ -716,7 +736,8 @@ irq_cleanup_hw:
 
        s5p_mfc_clock_off();
 
-       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+       spin_unlock(&dev->irqlock);
        mfc_debug(2, "Exit via irq_cleanup_hw\n");
        return IRQ_HANDLED;
 }
index d1a3f9b1bc4412dfb4a30d380d63e611717a974f..9eb2481ec292c2ee7ee99638d249005099b0c552 100644 (file)
@@ -308,7 +308,7 @@ struct s5p_mfc_dev {
        struct s5p_mfc_pm       pm;
        struct s5p_mfc_variant  *variant;
        int num_inst;
-       spinlock_t irqlock;     /* lock when operating on videobuf2 queues */
+       spinlock_t irqlock;     /* lock when operating on context */
        spinlock_t condlock;    /* lock when changing/checking if a context is
                                        ready to be processed */
        struct mutex mfc_mutex; /* video_device lock */
@@ -653,7 +653,7 @@ struct s5p_mfc_ctx {
                unsigned int bits;
        } slice_size;
 
-       struct s5p_mfc_codec_ops *c_ops;
+       const struct s5p_mfc_codec_ops *c_ops;
 
        struct v4l2_ctrl *ctrls[MFC_MAX_CTRLS];
        struct v4l2_ctrl_handler ctrl_handler;
@@ -694,13 +694,7 @@ struct mfc_control {
 
 /* Macro for making hardware specific calls */
 #define s5p_mfc_hw_call(f, op, args...) \
-       ((f && f->op) ? f->op(args) : -ENODEV)
-
-#define s5p_mfc_hw_call_void(f, op, args...) \
-do { \
-       if (f && f->op) \
-               f->op(args); \
-} while (0)
+       ((f && f->op) ? f->op(args) : (typeof(f->op(args)))(-ENODEV))
 
 #define fh_to_ctx(__fh) container_of(__fh, struct s5p_mfc_ctx, fh)
 #define ctrl_to_ctx(__ctrl) \
@@ -710,6 +704,8 @@ void clear_work_bit(struct s5p_mfc_ctx *ctx);
 void set_work_bit(struct s5p_mfc_ctx *ctx);
 void clear_work_bit_irqsave(struct s5p_mfc_ctx *ctx);
 void set_work_bit_irqsave(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev);
+void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq);
 
 #define HAS_PORTNUM(dev)       (dev ? (dev->variant ? \
                                (dev->variant->port_num ? 1 : 0) : 0) : 0)
index 40d8a03a141d339940960456773a65054284249e..cc888713b3b63f2af8d987b9cf93f30dbde9c484 100644 (file)
@@ -319,7 +319,7 @@ void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev)
        s5p_mfc_clock_on();
 
        s5p_mfc_reset(dev);
-       s5p_mfc_hw_call_void(dev->mfc_ops, release_dev_context_buffer, dev);
+       s5p_mfc_hw_call(dev->mfc_ops, release_dev_context_buffer, dev);
 
        s5p_mfc_clock_off();
 }
@@ -468,7 +468,7 @@ int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
        }
 
        set_work_bit_irqsave(ctx);
-       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
        if (s5p_mfc_wait_for_done_ctx(ctx,
                S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 0)) {
                /* Error or timeout */
@@ -482,9 +482,9 @@ int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
 
 err_free_desc_buf:
        if (ctx->type == MFCINST_DECODER)
-               s5p_mfc_hw_call_void(dev->mfc_ops, release_dec_desc_buffer, ctx);
+               s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx);
 err_free_inst_buf:
-       s5p_mfc_hw_call_void(dev->mfc_ops, release_instance_buffer, ctx);
+       s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx);
 err:
        return ret;
 }
@@ -493,17 +493,17 @@ void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
 {
        ctx->state = MFCINST_RETURN_INST;
        set_work_bit_irqsave(ctx);
-       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
        /* Wait until instance is returned or timeout occurred */
        if (s5p_mfc_wait_for_done_ctx(ctx,
                                S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0))
                mfc_err("Err returning instance\n");
 
        /* Free resources */
-       s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers, ctx);
-       s5p_mfc_hw_call_void(dev->mfc_ops, release_instance_buffer, ctx);
+       s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
+       s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx);
        if (ctx->type == MFCINST_DECODER)
-               s5p_mfc_hw_call_void(dev->mfc_ops, release_dec_desc_buffer, ctx);
+               s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx);
 
        ctx->inst_no = MFC_NO_INSTANCE_SET;
        ctx->state = MFCINST_FREE;
index 8c5060a7534fc88e9ea6e82095ff3fc365b4a02f..f2d6376ce618b24d82b9a3743a4179f9d98259df 100644 (file)
@@ -252,7 +252,7 @@ static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
        return 0;
 }
 
-static struct s5p_mfc_codec_ops decoder_codec_ops = {
+static const struct s5p_mfc_codec_ops decoder_codec_ops = {
        .pre_seq_start          = NULL,
        .post_seq_start         = NULL,
        .pre_frame_start        = NULL,
@@ -523,7 +523,7 @@ static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
                ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
                if (ret)
                        goto out;
-               s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers, ctx);
+               s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
                ctx->dst_bufs_cnt = 0;
        } else if (ctx->capture_state == QUEUE_FREE) {
                WARN_ON(ctx->dst_bufs_cnt != 0);
@@ -551,7 +551,7 @@ static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
 
                if (s5p_mfc_ctx_ready(ctx))
                        set_work_bit_irqsave(ctx);
-               s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+               s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
                s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_INIT_BUFFERS_RET,
                                          0);
        } else {
@@ -831,7 +831,7 @@ static int vidioc_decoder_cmd(struct file *file, void *priv,
                        if (s5p_mfc_ctx_ready(ctx))
                                set_work_bit_irqsave(ctx);
                        spin_unlock_irqrestore(&dev->irqlock, flags);
-                       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+                       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
                } else {
                        mfc_err("EOS: marking last buffer of stream");
                        buf = list_entry(ctx->src_queue.prev,
@@ -888,7 +888,7 @@ static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
 };
 
 static int s5p_mfc_queue_setup(struct vb2_queue *vq,
-                       const void *parg, unsigned int *buf_count,
+                       unsigned int *buf_count,
                        unsigned int *plane_count, unsigned int psize[],
                        void *allocators[])
 {
@@ -1012,7 +1012,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
        /* If context is ready then dev = work->data;schedule it to run */
        if (s5p_mfc_ctx_ready(ctx))
                set_work_bit_irqsave(ctx);
-       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
        return 0;
 }
 
@@ -1023,42 +1023,41 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q)
        struct s5p_mfc_dev *dev = ctx->dev;
        int aborted = 0;
 
+       spin_lock_irqsave(&dev->irqlock, flags);
        if ((ctx->state == MFCINST_FINISHING ||
                ctx->state ==  MFCINST_RUNNING) &&
                dev->curr_ctx == ctx->num && dev->hw_lock) {
                ctx->state = MFCINST_ABORT;
+               spin_unlock_irqrestore(&dev->irqlock, flags);
                s5p_mfc_wait_for_done_ctx(ctx,
                                        S5P_MFC_R2H_CMD_FRAME_DONE_RET, 0);
                aborted = 1;
+               spin_lock_irqsave(&dev->irqlock, flags);
        }
        if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-               spin_lock_irqsave(&dev->irqlock, flags);
-               s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
-                                               &ctx->dst_queue, &ctx->vq_dst);
+               s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
                INIT_LIST_HEAD(&ctx->dst_queue);
                ctx->dst_queue_cnt = 0;
                ctx->dpb_flush_flag = 1;
                ctx->dec_dst_flag = 0;
-               spin_unlock_irqrestore(&dev->irqlock, flags);
                if (IS_MFCV6_PLUS(dev) && (ctx->state == MFCINST_RUNNING)) {
                        ctx->state = MFCINST_FLUSH;
                        set_work_bit_irqsave(ctx);
-                       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+                       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+                       spin_unlock_irqrestore(&dev->irqlock, flags);
                        if (s5p_mfc_wait_for_done_ctx(ctx,
                                S5P_MFC_R2H_CMD_DPB_FLUSH_RET, 0))
                                mfc_err("Err flushing buffers\n");
+                       spin_lock_irqsave(&dev->irqlock, flags);
                }
-       }
-       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-               spin_lock_irqsave(&dev->irqlock, flags);
-               s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
-                                               &ctx->src_queue, &ctx->vq_src);
+       } else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
                INIT_LIST_HEAD(&ctx->src_queue);
                ctx->src_queue_cnt = 0;
-               spin_unlock_irqrestore(&dev->irqlock, flags);
        }
        if (aborted)
                ctx->state = MFCINST_RUNNING;
+       spin_unlock_irqrestore(&dev->irqlock, flags);
 }
 
 
@@ -1091,7 +1090,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
        }
        if (s5p_mfc_ctx_ready(ctx))
                set_work_bit_irqsave(ctx);
-       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
 }
 
 static struct vb2_ops s5p_mfc_dec_qops = {
@@ -1104,7 +1103,7 @@ static struct vb2_ops s5p_mfc_dec_qops = {
        .buf_queue              = s5p_mfc_buf_queue,
 };
 
-struct s5p_mfc_codec_ops *get_dec_codec_ops(void)
+const struct s5p_mfc_codec_ops *get_dec_codec_ops(void)
 {
        return &decoder_codec_ops;
 }
@@ -1119,7 +1118,7 @@ const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void)
        return &s5p_mfc_dec_ioctl_ops;
 }
 
-#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \
+#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2WHICH(x) == V4L2_CTRL_CLASS_MPEG) \
                                                && V4L2_CTRL_DRIVER_PRIV(x))
 
 int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx)
index d06a7cab5eb1bc32f86cb7edfbac1062fd141b14..886628b153f002dadfe89e6adcb4d501794e4f27 100644 (file)
@@ -13,7 +13,7 @@
 #ifndef S5P_MFC_DEC_H_
 #define S5P_MFC_DEC_H_
 
-struct s5p_mfc_codec_ops *get_dec_codec_ops(void);
+const struct s5p_mfc_codec_ops *get_dec_codec_ops(void);
 struct vb2_ops *get_dec_queue_ops(void);
 const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void);
 struct s5p_mfc_fmt *get_dec_def_fmt(bool src);
index 5c678ec9c9f26ad7e4c1025e139b76b8623b6ca8..0434f02a7175927d790f50eef9bd26d600cf5bc8 100644 (file)
@@ -769,15 +769,12 @@ static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx)
        struct s5p_mfc_buf *dst_mb;
        unsigned long dst_addr;
        unsigned int dst_size;
-       unsigned long flags;
 
-       spin_lock_irqsave(&dev->irqlock, flags);
        dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
        dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0);
        dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0);
-       s5p_mfc_hw_call_void(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
+       s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
                        dst_size);
-       spin_unlock_irqrestore(&dev->irqlock, flags);
        return 0;
 }
 
@@ -786,11 +783,9 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx)
        struct s5p_mfc_dev *dev = ctx->dev;
        struct s5p_mfc_enc_params *p = &ctx->enc_params;
        struct s5p_mfc_buf *dst_mb;
-       unsigned long flags;
        unsigned int enc_pb_count;
 
        if (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) {
-               spin_lock_irqsave(&dev->irqlock, flags);
                if (!list_empty(&ctx->dst_queue)) {
                        dst_mb = list_entry(ctx->dst_queue.next,
                                        struct s5p_mfc_buf, list);
@@ -802,14 +797,13 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx)
                        vb2_buffer_done(&dst_mb->b->vb2_buf,
                                        VB2_BUF_STATE_DONE);
                }
-               spin_unlock_irqrestore(&dev->irqlock, flags);
        }
 
        if (!IS_MFCV6_PLUS(dev)) {
                ctx->state = MFCINST_RUNNING;
                if (s5p_mfc_ctx_ready(ctx))
                        set_work_bit_irqsave(ctx);
-               s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+               s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
        } else {
                enc_pb_count = s5p_mfc_hw_call(dev->mfc_ops,
                                get_enc_dpb_count, dev);
@@ -826,25 +820,20 @@ static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx)
        struct s5p_mfc_dev *dev = ctx->dev;
        struct s5p_mfc_buf *dst_mb;
        struct s5p_mfc_buf *src_mb;
-       unsigned long flags;
        unsigned long src_y_addr, src_c_addr, dst_addr;
        unsigned int dst_size;
 
-       spin_lock_irqsave(&dev->irqlock, flags);
        src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
        src_y_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 0);
        src_c_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 1);
-       s5p_mfc_hw_call_void(dev->mfc_ops, set_enc_frame_buffer, ctx,
+       s5p_mfc_hw_call(dev->mfc_ops, set_enc_frame_buffer, ctx,
                                                        src_y_addr, src_c_addr);
-       spin_unlock_irqrestore(&dev->irqlock, flags);
 
-       spin_lock_irqsave(&dev->irqlock, flags);
        dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
        dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0);
        dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0);
-       s5p_mfc_hw_call_void(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
+       s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
                        dst_size);
-       spin_unlock_irqrestore(&dev->irqlock, flags);
 
        return 0;
 }
@@ -857,7 +846,6 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
        unsigned long mb_y_addr, mb_c_addr;
        int slice_type;
        unsigned int strm_size;
-       unsigned long flags;
 
        slice_type = s5p_mfc_hw_call(dev->mfc_ops, get_enc_slice_type, dev);
        strm_size = s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size, dev);
@@ -865,9 +853,8 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
        mfc_debug(2, "Encoded stream size: %d\n", strm_size);
        mfc_debug(2, "Display order: %d\n",
                  mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT));
-       spin_lock_irqsave(&dev->irqlock, flags);
        if (slice_type >= 0) {
-               s5p_mfc_hw_call_void(dev->mfc_ops, get_enc_frame_buffer, ctx,
+               s5p_mfc_hw_call(dev->mfc_ops, get_enc_frame_buffer, ctx,
                                &enc_y_addr, &enc_c_addr);
                list_for_each_entry(mb_entry, &ctx->src_queue, list) {
                        mb_y_addr = vb2_dma_contig_plane_dma_addr(
@@ -929,14 +916,13 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
                vb2_set_plane_payload(&mb_entry->b->vb2_buf, 0, strm_size);
                vb2_buffer_done(&mb_entry->b->vb2_buf, VB2_BUF_STATE_DONE);
        }
-       spin_unlock_irqrestore(&dev->irqlock, flags);
        if ((ctx->src_queue_cnt == 0) || (ctx->dst_queue_cnt == 0))
                clear_work_bit(ctx);
 
        return 0;
 }
 
-static struct s5p_mfc_codec_ops encoder_codec_ops = {
+static const struct s5p_mfc_codec_ops encoder_codec_ops = {
        .pre_seq_start          = enc_pre_seq_start,
        .post_seq_start         = enc_post_seq_start,
        .pre_frame_start        = enc_pre_frame_start,
@@ -1120,7 +1106,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
                        pix_fmt_mp->width, pix_fmt_mp->height,
                        ctx->img_width, ctx->img_height);
 
-               s5p_mfc_hw_call_void(dev->mfc_ops, enc_calc_src_size, ctx);
+               s5p_mfc_hw_call(dev->mfc_ops, enc_calc_src_size, ctx);
                pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
                pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
                pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
@@ -1178,7 +1164,7 @@ static int vidioc_reqbufs(struct file *file, void *priv,
                if (reqbufs->count == 0) {
                        mfc_debug(2, "Freeing buffers\n");
                        ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
-                       s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers,
+                       s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers,
                                        ctx);
                        ctx->output_state = QUEUE_FREE;
                        return ret;
@@ -1741,7 +1727,7 @@ static int vidioc_encoder_cmd(struct file *file, void *priv,
                        if (s5p_mfc_ctx_ready(ctx))
                                set_work_bit_irqsave(ctx);
                        spin_unlock_irqrestore(&dev->irqlock, flags);
-                       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+                       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
                } else {
                        mfc_debug(2, "EOS: marking last buffer of stream\n");
                        buf = list_entry(ctx->src_queue.prev,
@@ -1818,7 +1804,6 @@ static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb)
 }
 
 static int s5p_mfc_queue_setup(struct vb2_queue *vq,
-                       const void *parg,
                        unsigned int *buf_count, unsigned int *plane_count,
                        unsigned int psize[], void *allocators[])
 {
@@ -1969,7 +1954,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
        /* If context is ready then dev = work->data;schedule it to run */
        if (s5p_mfc_ctx_ready(ctx))
                set_work_bit_irqsave(ctx);
-       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
 
        return 0;
 }
@@ -1990,15 +1975,13 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q)
        ctx->state = MFCINST_FINISHED;
        spin_lock_irqsave(&dev->irqlock, flags);
        if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-               s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
-                                               &ctx->dst_queue, &ctx->vq_dst);
+               s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
                INIT_LIST_HEAD(&ctx->dst_queue);
                ctx->dst_queue_cnt = 0;
        }
        if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
                cleanup_ref_queue(ctx);
-               s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, &ctx->src_queue,
-                               &ctx->vq_src);
+               s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
                INIT_LIST_HEAD(&ctx->src_queue);
                ctx->src_queue_cnt = 0;
        }
@@ -2038,7 +2021,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
        }
        if (s5p_mfc_ctx_ready(ctx))
                set_work_bit_irqsave(ctx);
-       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
 }
 
 static struct vb2_ops s5p_mfc_enc_qops = {
@@ -2052,7 +2035,7 @@ static struct vb2_ops s5p_mfc_enc_qops = {
        .buf_queue              = s5p_mfc_buf_queue,
 };
 
-struct s5p_mfc_codec_ops *get_enc_codec_ops(void)
+const struct s5p_mfc_codec_ops *get_enc_codec_ops(void)
 {
        return &encoder_codec_ops;
 }
@@ -2067,7 +2050,7 @@ const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void)
        return &s5p_mfc_enc_ioctl_ops;
 }
 
-#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \
+#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2WHICH(x) == V4L2_CTRL_CLASS_MPEG) \
                                                && V4L2_CTRL_DRIVER_PRIV(x))
 
 int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx)
index 5118d46b3a9ea767acd6290a6b5a3d550aabc905..d0d42f81883219e864123b6cdc96522664708460 100644 (file)
@@ -13,7 +13,7 @@
 #ifndef S5P_MFC_ENC_H_
 #define S5P_MFC_ENC_H_
 
-struct s5p_mfc_codec_ops *get_enc_codec_ops(void);
+const struct s5p_mfc_codec_ops *get_enc_codec_ops(void);
 struct vb2_ops *get_enc_queue_ops(void);
 const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void);
 struct s5p_mfc_fmt *get_enc_def_fmt(bool src);
index 77a08b19b46d0032220a2a99ef0bd8fefe72f570..b6ac417ab63e6a0f3acd0edc649acb6d98b9222b 100644 (file)
 struct s5p_mfc_regs {
 
        /* codec common registers */
-       volatile void __iomem *risc_on;
-       volatile void __iomem *risc2host_int;
-       volatile void __iomem *host2risc_int;
-       volatile void __iomem *risc_base_address;
-       volatile void __iomem *mfc_reset;
-       volatile void __iomem *host2risc_command;
-       volatile void __iomem *risc2host_command;
-       volatile void __iomem *mfc_bus_reset_ctrl;
-       volatile void __iomem *firmware_version;
-       volatile void __iomem *instance_id;
-       volatile void __iomem *codec_type;
-       volatile void __iomem *context_mem_addr;
-       volatile void __iomem *context_mem_size;
-       volatile void __iomem *pixel_format;
-       volatile void __iomem *metadata_enable;
-       volatile void __iomem *mfc_version;
-       volatile void __iomem *dbg_info_enable;
-       volatile void __iomem *dbg_buffer_addr;
-       volatile void __iomem *dbg_buffer_size;
-       volatile void __iomem *hed_control;
-       volatile void __iomem *mfc_timeout_value;
-       volatile void __iomem *hed_shared_mem_addr;
-       volatile void __iomem *dis_shared_mem_addr;/* only v7 */
-       volatile void __iomem *ret_instance_id;
-       volatile void __iomem *error_code;
-       volatile void __iomem *dbg_buffer_output_size;
-       volatile void __iomem *metadata_status;
-       volatile void __iomem *metadata_addr_mb_info;
-       volatile void __iomem *metadata_size_mb_info;
-       volatile void __iomem *dbg_info_stage_counter;
+       void __iomem *risc_on;
+       void __iomem *risc2host_int;
+       void __iomem *host2risc_int;
+       void __iomem *risc_base_address;
+       void __iomem *mfc_reset;
+       void __iomem *host2risc_command;
+       void __iomem *risc2host_command;
+       void __iomem *mfc_bus_reset_ctrl;
+       void __iomem *firmware_version;
+       void __iomem *instance_id;
+       void __iomem *codec_type;
+       void __iomem *context_mem_addr;
+       void __iomem *context_mem_size;
+       void __iomem *pixel_format;
+       void __iomem *metadata_enable;
+       void __iomem *mfc_version;
+       void __iomem *dbg_info_enable;
+       void __iomem *dbg_buffer_addr;
+       void __iomem *dbg_buffer_size;
+       void __iomem *hed_control;
+       void __iomem *mfc_timeout_value;
+       void __iomem *hed_shared_mem_addr;
+       void __iomem *dis_shared_mem_addr;/* only v7 */
+       void __iomem *ret_instance_id;
+       void __iomem *error_code;
+       void __iomem *dbg_buffer_output_size;
+       void __iomem *metadata_status;
+       void __iomem *metadata_addr_mb_info;
+       void __iomem *metadata_size_mb_info;
+       void __iomem *dbg_info_stage_counter;
 
        /* decoder registers */
-       volatile void __iomem *d_crc_ctrl;
-       volatile void __iomem *d_dec_options;
-       volatile void __iomem *d_display_delay;
-       volatile void __iomem *d_set_frame_width;
-       volatile void __iomem *d_set_frame_height;
-       volatile void __iomem *d_sei_enable;
-       volatile void __iomem *d_min_num_dpb;
-       volatile void __iomem *d_min_first_plane_dpb_size;
-       volatile void __iomem *d_min_second_plane_dpb_size;
-       volatile void __iomem *d_min_third_plane_dpb_size;/* only v8 */
-       volatile void __iomem *d_min_num_mv;
-       volatile void __iomem *d_mvc_num_views;
-       volatile void __iomem *d_min_num_dis;/* only v7 */
-       volatile void __iomem *d_min_first_dis_size;/* only v7 */
-       volatile void __iomem *d_min_second_dis_size;/* only v7 */
-       volatile void __iomem *d_min_third_dis_size;/* only v7 */
-       volatile void __iomem *d_post_filter_luma_dpb0;/*  v7 and v8 */
-       volatile void __iomem *d_post_filter_luma_dpb1;/* v7 and v8 */
-       volatile void __iomem *d_post_filter_luma_dpb2;/* only v7 */
-       volatile void __iomem *d_post_filter_chroma_dpb0;/* v7 and v8 */
-       volatile void __iomem *d_post_filter_chroma_dpb1;/* v7 and v8 */
-       volatile void __iomem *d_post_filter_chroma_dpb2;/* only v7 */
-       volatile void __iomem *d_num_dpb;
-       volatile void __iomem *d_num_mv;
-       volatile void __iomem *d_init_buffer_options;
-       volatile void __iomem *d_first_plane_dpb_stride_size;/* only v8 */
-       volatile void __iomem *d_second_plane_dpb_stride_size;/* only v8 */
-       volatile void __iomem *d_third_plane_dpb_stride_size;/* only v8 */
-       volatile void __iomem *d_first_plane_dpb_size;
-       volatile void __iomem *d_second_plane_dpb_size;
-       volatile void __iomem *d_third_plane_dpb_size;/* only v8 */
-       volatile void __iomem *d_mv_buffer_size;
-       volatile void __iomem *d_first_plane_dpb;
-       volatile void __iomem *d_second_plane_dpb;
-       volatile void __iomem *d_third_plane_dpb;
-       volatile void __iomem *d_mv_buffer;
-       volatile void __iomem *d_scratch_buffer_addr;
-       volatile void __iomem *d_scratch_buffer_size;
-       volatile void __iomem *d_metadata_buffer_addr;
-       volatile void __iomem *d_metadata_buffer_size;
-       volatile void __iomem *d_nal_start_options;/* v7 and v8 */
-       volatile void __iomem *d_cpb_buffer_addr;
-       volatile void __iomem *d_cpb_buffer_size;
-       volatile void __iomem *d_available_dpb_flag_upper;
-       volatile void __iomem *d_available_dpb_flag_lower;
-       volatile void __iomem *d_cpb_buffer_offset;
-       volatile void __iomem *d_slice_if_enable;
-       volatile void __iomem *d_picture_tag;
-       volatile void __iomem *d_stream_data_size;
-       volatile void __iomem *d_dynamic_dpb_flag_upper;/* v7 and v8 */
-       volatile void __iomem *d_dynamic_dpb_flag_lower;/* v7 and v8 */
-       volatile void __iomem *d_display_frame_width;
-       volatile void __iomem *d_display_frame_height;
-       volatile void __iomem *d_display_status;
-       volatile void __iomem *d_display_first_plane_addr;
-       volatile void __iomem *d_display_second_plane_addr;
-       volatile void __iomem *d_display_third_plane_addr;/* only v8 */
-       volatile void __iomem *d_display_frame_type;
-       volatile void __iomem *d_display_crop_info1;
-       volatile void __iomem *d_display_crop_info2;
-       volatile void __iomem *d_display_picture_profile;
-       volatile void __iomem *d_display_luma_crc;/* v7 and v8 */
-       volatile void __iomem *d_display_chroma0_crc;/* v7 and v8 */
-       volatile void __iomem *d_display_chroma1_crc;/* only v8 */
-       volatile void __iomem *d_display_luma_crc_top;/* only v6 */
-       volatile void __iomem *d_display_chroma_crc_top;/* only v6 */
-       volatile void __iomem *d_display_luma_crc_bot;/* only v6 */
-       volatile void __iomem *d_display_chroma_crc_bot;/* only v6 */
-       volatile void __iomem *d_display_aspect_ratio;
-       volatile void __iomem *d_display_extended_ar;
-       volatile void __iomem *d_decoded_frame_width;
-       volatile void __iomem *d_decoded_frame_height;
-       volatile void __iomem *d_decoded_status;
-       volatile void __iomem *d_decoded_first_plane_addr;
-       volatile void __iomem *d_decoded_second_plane_addr;
-       volatile void __iomem *d_decoded_third_plane_addr;/* only v8 */
-       volatile void __iomem *d_decoded_frame_type;
-       volatile void __iomem *d_decoded_crop_info1;
-       volatile void __iomem *d_decoded_crop_info2;
-       volatile void __iomem *d_decoded_picture_profile;
-       volatile void __iomem *d_decoded_nal_size;
-       volatile void __iomem *d_decoded_luma_crc;
-       volatile void __iomem *d_decoded_chroma0_crc;
-       volatile void __iomem *d_decoded_chroma1_crc;/* only v8 */
-       volatile void __iomem *d_ret_picture_tag_top;
-       volatile void __iomem *d_ret_picture_tag_bot;
-       volatile void __iomem *d_ret_picture_time_top;
-       volatile void __iomem *d_ret_picture_time_bot;
-       volatile void __iomem *d_chroma_format;
-       volatile void __iomem *d_vc1_info;/* v7 and v8 */
-       volatile void __iomem *d_mpeg4_info;
-       volatile void __iomem *d_h264_info;
-       volatile void __iomem *d_metadata_addr_concealed_mb;
-       volatile void __iomem *d_metadata_size_concealed_mb;
-       volatile void __iomem *d_metadata_addr_vc1_param;
-       volatile void __iomem *d_metadata_size_vc1_param;
-       volatile void __iomem *d_metadata_addr_sei_nal;
-       volatile void __iomem *d_metadata_size_sei_nal;
-       volatile void __iomem *d_metadata_addr_vui;
-       volatile void __iomem *d_metadata_size_vui;
-       volatile void __iomem *d_metadata_addr_mvcvui;/* v7 and v8 */
-       volatile void __iomem *d_metadata_size_mvcvui;/* v7 and v8 */
-       volatile void __iomem *d_mvc_view_id;
-       volatile void __iomem *d_frame_pack_sei_avail;
-       volatile void __iomem *d_frame_pack_arrgment_id;
-       volatile void __iomem *d_frame_pack_sei_info;
-       volatile void __iomem *d_frame_pack_grid_pos;
-       volatile void __iomem *d_display_recovery_sei_info;/* v7 and v8 */
-       volatile void __iomem *d_decoded_recovery_sei_info;/* v7 and v8 */
-       volatile void __iomem *d_display_first_addr;/* only v7 */
-       volatile void __iomem *d_display_second_addr;/* only v7 */
-       volatile void __iomem *d_display_third_addr;/* only v7 */
-       volatile void __iomem *d_decoded_first_addr;/* only v7 */
-       volatile void __iomem *d_decoded_second_addr;/* only v7 */
-       volatile void __iomem *d_decoded_third_addr;/* only v7 */
-       volatile void __iomem *d_used_dpb_flag_upper;/* v7 and v8 */
-       volatile void __iomem *d_used_dpb_flag_lower;/* v7 and v8 */
+       void __iomem *d_crc_ctrl;
+       void __iomem *d_dec_options;
+       void __iomem *d_display_delay;
+       void __iomem *d_set_frame_width;
+       void __iomem *d_set_frame_height;
+       void __iomem *d_sei_enable;
+       void __iomem *d_min_num_dpb;
+       void __iomem *d_min_first_plane_dpb_size;
+       void __iomem *d_min_second_plane_dpb_size;
+       void __iomem *d_min_third_plane_dpb_size;/* only v8 */
+       void __iomem *d_min_num_mv;
+       void __iomem *d_mvc_num_views;
+       void __iomem *d_min_num_dis;/* only v7 */
+       void __iomem *d_min_first_dis_size;/* only v7 */
+       void __iomem *d_min_second_dis_size;/* only v7 */
+       void __iomem *d_min_third_dis_size;/* only v7 */
+       void __iomem *d_post_filter_luma_dpb0;/*  v7 and v8 */
+       void __iomem *d_post_filter_luma_dpb1;/* v7 and v8 */
+       void __iomem *d_post_filter_luma_dpb2;/* only v7 */
+       void __iomem *d_post_filter_chroma_dpb0;/* v7 and v8 */
+       void __iomem *d_post_filter_chroma_dpb1;/* v7 and v8 */
+       void __iomem *d_post_filter_chroma_dpb2;/* only v7 */
+       void __iomem *d_num_dpb;
+       void __iomem *d_num_mv;
+       void __iomem *d_init_buffer_options;
+       void __iomem *d_first_plane_dpb_stride_size;/* only v8 */
+       void __iomem *d_second_plane_dpb_stride_size;/* only v8 */
+       void __iomem *d_third_plane_dpb_stride_size;/* only v8 */
+       void __iomem *d_first_plane_dpb_size;
+       void __iomem *d_second_plane_dpb_size;
+       void __iomem *d_third_plane_dpb_size;/* only v8 */
+       void __iomem *d_mv_buffer_size;
+       void __iomem *d_first_plane_dpb;
+       void __iomem *d_second_plane_dpb;
+       void __iomem *d_third_plane_dpb;
+       void __iomem *d_mv_buffer;
+       void __iomem *d_scratch_buffer_addr;
+       void __iomem *d_scratch_buffer_size;
+       void __iomem *d_metadata_buffer_addr;
+       void __iomem *d_metadata_buffer_size;
+       void __iomem *d_nal_start_options;/* v7 and v8 */
+       void __iomem *d_cpb_buffer_addr;
+       void __iomem *d_cpb_buffer_size;
+       void __iomem *d_available_dpb_flag_upper;
+       void __iomem *d_available_dpb_flag_lower;
+       void __iomem *d_cpb_buffer_offset;
+       void __iomem *d_slice_if_enable;
+       void __iomem *d_picture_tag;
+       void __iomem *d_stream_data_size;
+       void __iomem *d_dynamic_dpb_flag_upper;/* v7 and v8 */
+       void __iomem *d_dynamic_dpb_flag_lower;/* v7 and v8 */
+       void __iomem *d_display_frame_width;
+       void __iomem *d_display_frame_height;
+       void __iomem *d_display_status;
+       void __iomem *d_display_first_plane_addr;
+       void __iomem *d_display_second_plane_addr;
+       void __iomem *d_display_third_plane_addr;/* only v8 */
+       void __iomem *d_display_frame_type;
+       void __iomem *d_display_crop_info1;
+       void __iomem *d_display_crop_info2;
+       void __iomem *d_display_picture_profile;
+       void __iomem *d_display_luma_crc;/* v7 and v8 */
+       void __iomem *d_display_chroma0_crc;/* v7 and v8 */
+       void __iomem *d_display_chroma1_crc;/* only v8 */
+       void __iomem *d_display_luma_crc_top;/* only v6 */
+       void __iomem *d_display_chroma_crc_top;/* only v6 */
+       void __iomem *d_display_luma_crc_bot;/* only v6 */
+       void __iomem *d_display_chroma_crc_bot;/* only v6 */
+       void __iomem *d_display_aspect_ratio;
+       void __iomem *d_display_extended_ar;
+       void __iomem *d_decoded_frame_width;
+       void __iomem *d_decoded_frame_height;
+       void __iomem *d_decoded_status;
+       void __iomem *d_decoded_first_plane_addr;
+       void __iomem *d_decoded_second_plane_addr;
+       void __iomem *d_decoded_third_plane_addr;/* only v8 */
+       void __iomem *d_decoded_frame_type;
+       void __iomem *d_decoded_crop_info1;
+       void __iomem *d_decoded_crop_info2;
+       void __iomem *d_decoded_picture_profile;
+       void __iomem *d_decoded_nal_size;
+       void __iomem *d_decoded_luma_crc;
+       void __iomem *d_decoded_chroma0_crc;
+       void __iomem *d_decoded_chroma1_crc;/* only v8 */
+       void __iomem *d_ret_picture_tag_top;
+       void __iomem *d_ret_picture_tag_bot;
+       void __iomem *d_ret_picture_time_top;
+       void __iomem *d_ret_picture_time_bot;
+       void __iomem *d_chroma_format;
+       void __iomem *d_vc1_info;/* v7 and v8 */
+       void __iomem *d_mpeg4_info;
+       void __iomem *d_h264_info;
+       void __iomem *d_metadata_addr_concealed_mb;
+       void __iomem *d_metadata_size_concealed_mb;
+       void __iomem *d_metadata_addr_vc1_param;
+       void __iomem *d_metadata_size_vc1_param;
+       void __iomem *d_metadata_addr_sei_nal;
+       void __iomem *d_metadata_size_sei_nal;
+       void __iomem *d_metadata_addr_vui;
+       void __iomem *d_metadata_size_vui;
+       void __iomem *d_metadata_addr_mvcvui;/* v7 and v8 */
+       void __iomem *d_metadata_size_mvcvui;/* v7 and v8 */
+       void __iomem *d_mvc_view_id;
+       void __iomem *d_frame_pack_sei_avail;
+       void __iomem *d_frame_pack_arrgment_id;
+       void __iomem *d_frame_pack_sei_info;
+       void __iomem *d_frame_pack_grid_pos;
+       void __iomem *d_display_recovery_sei_info;/* v7 and v8 */
+       void __iomem *d_decoded_recovery_sei_info;/* v7 and v8 */
+       void __iomem *d_display_first_addr;/* only v7 */
+       void __iomem *d_display_second_addr;/* only v7 */
+       void __iomem *d_display_third_addr;/* only v7 */
+       void __iomem *d_decoded_first_addr;/* only v7 */
+       void __iomem *d_decoded_second_addr;/* only v7 */
+       void __iomem *d_decoded_third_addr;/* only v7 */
+       void __iomem *d_used_dpb_flag_upper;/* v7 and v8 */
+       void __iomem *d_used_dpb_flag_lower;/* v7 and v8 */
 
        /* encoder registers */
-       volatile void __iomem *e_frame_width;
-       volatile void __iomem *e_frame_height;
-       volatile void __iomem *e_cropped_frame_width;
-       volatile void __iomem *e_cropped_frame_height;
-       volatile void __iomem *e_frame_crop_offset;
-       volatile void __iomem *e_enc_options;
-       volatile void __iomem *e_picture_profile;
-       volatile void __iomem *e_vbv_buffer_size;
-       volatile void __iomem *e_vbv_init_delay;
-       volatile void __iomem *e_fixed_picture_qp;
-       volatile void __iomem *e_rc_config;
-       volatile void __iomem *e_rc_qp_bound;
-       volatile void __iomem *e_rc_qp_bound_pb;/* v7 and v8 */
-       volatile void __iomem *e_rc_mode;
-       volatile void __iomem *e_mb_rc_config;
-       volatile void __iomem *e_padding_ctrl;
-       volatile void __iomem *e_air_threshold;
-       volatile void __iomem *e_mv_hor_range;
-       volatile void __iomem *e_mv_ver_range;
-       volatile void __iomem *e_num_dpb;
-       volatile void __iomem *e_luma_dpb;
-       volatile void __iomem *e_chroma_dpb;
-       volatile void __iomem *e_me_buffer;
-       volatile void __iomem *e_scratch_buffer_addr;
-       volatile void __iomem *e_scratch_buffer_size;
-       volatile void __iomem *e_tmv_buffer0;
-       volatile void __iomem *e_tmv_buffer1;
-       volatile void __iomem *e_ir_buffer_addr;/* v7 and v8 */
-       volatile void __iomem *e_source_first_plane_addr;
-       volatile void __iomem *e_source_second_plane_addr;
-       volatile void __iomem *e_source_third_plane_addr;/* v7 and v8 */
-       volatile void __iomem *e_source_first_plane_stride;/* v7 and v8 */
-       volatile void __iomem *e_source_second_plane_stride;/* v7 and v8 */
-       volatile void __iomem *e_source_third_plane_stride;/* v7 and v8 */
-       volatile void __iomem *e_stream_buffer_addr;
-       volatile void __iomem *e_stream_buffer_size;
-       volatile void __iomem *e_roi_buffer_addr;
-       volatile void __iomem *e_param_change;
-       volatile void __iomem *e_ir_size;
-       volatile void __iomem *e_gop_config;
-       volatile void __iomem *e_mslice_mode;
-       volatile void __iomem *e_mslice_size_mb;
-       volatile void __iomem *e_mslice_size_bits;
-       volatile void __iomem *e_frame_insertion;
-       volatile void __iomem *e_rc_frame_rate;
-       volatile void __iomem *e_rc_bit_rate;
-       volatile void __iomem *e_rc_roi_ctrl;
-       volatile void __iomem *e_picture_tag;
-       volatile void __iomem *e_bit_count_enable;
-       volatile void __iomem *e_max_bit_count;
-       volatile void __iomem *e_min_bit_count;
-       volatile void __iomem *e_metadata_buffer_addr;
-       volatile void __iomem *e_metadata_buffer_size;
-       volatile void __iomem *e_encoded_source_first_plane_addr;
-       volatile void __iomem *e_encoded_source_second_plane_addr;
-       volatile void __iomem *e_encoded_source_third_plane_addr;/* v7 and v8 */
-       volatile void __iomem *e_stream_size;
-       volatile void __iomem *e_slice_type;
-       volatile void __iomem *e_picture_count;
-       volatile void __iomem *e_ret_picture_tag;
-       volatile void __iomem *e_stream_buffer_write_pointer; /*  only v6 */
-       volatile void __iomem *e_recon_luma_dpb_addr;
-       volatile void __iomem *e_recon_chroma_dpb_addr;
-       volatile void __iomem *e_metadata_addr_enc_slice;
-       volatile void __iomem *e_metadata_size_enc_slice;
-       volatile void __iomem *e_mpeg4_options;
-       volatile void __iomem *e_mpeg4_hec_period;
-       volatile void __iomem *e_aspect_ratio;
-       volatile void __iomem *e_extended_sar;
-       volatile void __iomem *e_h264_options;
-       volatile void __iomem *e_h264_options_2;/* v7 and v8 */
-       volatile void __iomem *e_h264_lf_alpha_offset;
-       volatile void __iomem *e_h264_lf_beta_offset;
-       volatile void __iomem *e_h264_i_period;
-       volatile void __iomem *e_h264_fmo_slice_grp_map_type;
-       volatile void __iomem *e_h264_fmo_num_slice_grp_minus1;
-       volatile void __iomem *e_h264_fmo_slice_grp_change_dir;
-       volatile void __iomem *e_h264_fmo_slice_grp_change_rate_minus1;
-       volatile void __iomem *e_h264_fmo_run_length_minus1_0;
-       volatile void __iomem *e_h264_aso_slice_order_0;
-       volatile void __iomem *e_h264_chroma_qp_offset;
-       volatile void __iomem *e_h264_num_t_layer;
-       volatile void __iomem *e_h264_hierarchical_qp_layer0;
-       volatile void __iomem *e_h264_frame_packing_sei_info;
-       volatile void __iomem *e_h264_nal_control;/* v7 and v8 */
-       volatile void __iomem *e_mvc_frame_qp_view1;
-       volatile void __iomem *e_mvc_rc_bit_rate_view1;
-       volatile void __iomem *e_mvc_rc_qbound_view1;
-       volatile void __iomem *e_mvc_rc_mode_view1;
-       volatile void __iomem *e_mvc_inter_view_prediction_on;
-       volatile void __iomem *e_vp8_options;/* v7 and v8 */
-       volatile void __iomem *e_vp8_filter_options;/* v7 and v8 */
-       volatile void __iomem *e_vp8_golden_frame_option;/* v7 and v8 */
-       volatile void __iomem *e_vp8_num_t_layer;/* v7 and v8 */
-       volatile void __iomem *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */
-       volatile void __iomem *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */
-       volatile void __iomem *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */
+       void __iomem *e_frame_width;
+       void __iomem *e_frame_height;
+       void __iomem *e_cropped_frame_width;
+       void __iomem *e_cropped_frame_height;
+       void __iomem *e_frame_crop_offset;
+       void __iomem *e_enc_options;
+       void __iomem *e_picture_profile;
+       void __iomem *e_vbv_buffer_size;
+       void __iomem *e_vbv_init_delay;
+       void __iomem *e_fixed_picture_qp;
+       void __iomem *e_rc_config;
+       void __iomem *e_rc_qp_bound;
+       void __iomem *e_rc_qp_bound_pb;/* v7 and v8 */
+       void __iomem *e_rc_mode;
+       void __iomem *e_mb_rc_config;
+       void __iomem *e_padding_ctrl;
+       void __iomem *e_air_threshold;
+       void __iomem *e_mv_hor_range;
+       void __iomem *e_mv_ver_range;
+       void __iomem *e_num_dpb;
+       void __iomem *e_luma_dpb;
+       void __iomem *e_chroma_dpb;
+       void __iomem *e_me_buffer;
+       void __iomem *e_scratch_buffer_addr;
+       void __iomem *e_scratch_buffer_size;
+       void __iomem *e_tmv_buffer0;
+       void __iomem *e_tmv_buffer1;
+       void __iomem *e_ir_buffer_addr;/* v7 and v8 */
+       void __iomem *e_source_first_plane_addr;
+       void __iomem *e_source_second_plane_addr;
+       void __iomem *e_source_third_plane_addr;/* v7 and v8 */
+       void __iomem *e_source_first_plane_stride;/* v7 and v8 */
+       void __iomem *e_source_second_plane_stride;/* v7 and v8 */
+       void __iomem *e_source_third_plane_stride;/* v7 and v8 */
+       void __iomem *e_stream_buffer_addr;
+       void __iomem *e_stream_buffer_size;
+       void __iomem *e_roi_buffer_addr;
+       void __iomem *e_param_change;
+       void __iomem *e_ir_size;
+       void __iomem *e_gop_config;
+       void __iomem *e_mslice_mode;
+       void __iomem *e_mslice_size_mb;
+       void __iomem *e_mslice_size_bits;
+       void __iomem *e_frame_insertion;
+       void __iomem *e_rc_frame_rate;
+       void __iomem *e_rc_bit_rate;
+       void __iomem *e_rc_roi_ctrl;
+       void __iomem *e_picture_tag;
+       void __iomem *e_bit_count_enable;
+       void __iomem *e_max_bit_count;
+       void __iomem *e_min_bit_count;
+       void __iomem *e_metadata_buffer_addr;
+       void __iomem *e_metadata_buffer_size;
+       void __iomem *e_encoded_source_first_plane_addr;
+       void __iomem *e_encoded_source_second_plane_addr;
+       void __iomem *e_encoded_source_third_plane_addr;/* v7 and v8 */
+       void __iomem *e_stream_size;
+       void __iomem *e_slice_type;
+       void __iomem *e_picture_count;
+       void __iomem *e_ret_picture_tag;
+       void __iomem *e_stream_buffer_write_pointer; /*  only v6 */
+       void __iomem *e_recon_luma_dpb_addr;
+       void __iomem *e_recon_chroma_dpb_addr;
+       void __iomem *e_metadata_addr_enc_slice;
+       void __iomem *e_metadata_size_enc_slice;
+       void __iomem *e_mpeg4_options;
+       void __iomem *e_mpeg4_hec_period;
+       void __iomem *e_aspect_ratio;
+       void __iomem *e_extended_sar;
+       void __iomem *e_h264_options;
+       void __iomem *e_h264_options_2;/* v7 and v8 */
+       void __iomem *e_h264_lf_alpha_offset;
+       void __iomem *e_h264_lf_beta_offset;
+       void __iomem *e_h264_i_period;
+       void __iomem *e_h264_fmo_slice_grp_map_type;
+       void __iomem *e_h264_fmo_num_slice_grp_minus1;
+       void __iomem *e_h264_fmo_slice_grp_change_dir;
+       void __iomem *e_h264_fmo_slice_grp_change_rate_minus1;
+       void __iomem *e_h264_fmo_run_length_minus1_0;
+       void __iomem *e_h264_aso_slice_order_0;
+       void __iomem *e_h264_chroma_qp_offset;
+       void __iomem *e_h264_num_t_layer;
+       void __iomem *e_h264_hierarchical_qp_layer0;
+       void __iomem *e_h264_frame_packing_sei_info;
+       void __iomem *e_h264_nal_control;/* v7 and v8 */
+       void __iomem *e_mvc_frame_qp_view1;
+       void __iomem *e_mvc_rc_bit_rate_view1;
+       void __iomem *e_mvc_rc_qbound_view1;
+       void __iomem *e_mvc_rc_mode_view1;
+       void __iomem *e_mvc_inter_view_prediction_on;
+       void __iomem *e_vp8_options;/* v7 and v8 */
+       void __iomem *e_vp8_filter_options;/* v7 and v8 */
+       void __iomem *e_vp8_golden_frame_option;/* v7 and v8 */
+       void __iomem *e_vp8_num_t_layer;/* v7 and v8 */
+       void __iomem *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */
+       void __iomem *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */
+       void __iomem *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */
 };
 
 struct s5p_mfc_hw_ops {
@@ -281,28 +281,14 @@ struct s5p_mfc_hw_ops {
        void (*release_dev_context_buffer)(struct s5p_mfc_dev *dev);
        void (*dec_calc_dpb_size)(struct s5p_mfc_ctx *ctx);
        void (*enc_calc_src_size)(struct s5p_mfc_ctx *ctx);
-       int (*set_dec_stream_buffer)(struct s5p_mfc_ctx *ctx,
-                       int buf_addr, unsigned int start_num_byte,
-                       unsigned int buf_size);
-       int (*set_dec_frame_buffer)(struct s5p_mfc_ctx *ctx);
        int (*set_enc_stream_buffer)(struct s5p_mfc_ctx *ctx,
                        unsigned long addr, unsigned int size);
        void (*set_enc_frame_buffer)(struct s5p_mfc_ctx *ctx,
                        unsigned long y_addr, unsigned long c_addr);
        void (*get_enc_frame_buffer)(struct s5p_mfc_ctx *ctx,
                        unsigned long *y_addr, unsigned long *c_addr);
-       int (*set_enc_ref_buffer)(struct s5p_mfc_ctx *ctx);
-       int (*init_decode)(struct s5p_mfc_ctx *ctx);
-       int (*init_encode)(struct s5p_mfc_ctx *ctx);
-       int (*encode_one_frame)(struct s5p_mfc_ctx *ctx);
        void (*try_run)(struct s5p_mfc_dev *dev);
-       void (*cleanup_queue)(struct list_head *lh,
-                       struct vb2_queue *vq);
        void (*clear_int_flags)(struct s5p_mfc_dev *dev);
-       void (*write_info)(struct s5p_mfc_ctx *ctx, unsigned int data,
-                       unsigned int ofs);
-       unsigned int (*read_info)(struct s5p_mfc_ctx *ctx,
-                       unsigned long ofs);
        int (*get_dspl_y_adr)(struct s5p_mfc_dev *dev);
        int (*get_dec_y_adr)(struct s5p_mfc_dev *dev);
        int (*get_dspl_status)(struct s5p_mfc_dev *dev);
@@ -313,7 +299,6 @@ struct s5p_mfc_hw_ops {
        int (*get_int_reason)(struct s5p_mfc_dev *dev);
        int (*get_int_err)(struct s5p_mfc_dev *dev);
        int (*err_dec)(unsigned int err);
-       int (*err_dspl)(unsigned int err);
        int (*get_img_width)(struct s5p_mfc_dev *dev);
        int (*get_img_height)(struct s5p_mfc_dev *dev);
        int (*get_dpb_count)(struct s5p_mfc_dev *dev);
@@ -322,10 +307,6 @@ struct s5p_mfc_hw_ops {
        int (*get_enc_strm_size)(struct s5p_mfc_dev *dev);
        int (*get_enc_slice_type)(struct s5p_mfc_dev *dev);
        int (*get_enc_dpb_count)(struct s5p_mfc_dev *dev);
-       int (*get_enc_pic_count)(struct s5p_mfc_dev *dev);
-       int (*get_sei_avail_status)(struct s5p_mfc_ctx *ctx);
-       int (*get_mvc_num_views)(struct s5p_mfc_dev *dev);
-       int (*get_mvc_view_id)(struct s5p_mfc_dev *dev);
        unsigned int (*get_pic_type_top)(struct s5p_mfc_ctx *ctx);
        unsigned int (*get_pic_type_bot)(struct s5p_mfc_ctx *ctx);
        unsigned int (*get_crop_info_h)(struct s5p_mfc_ctx *ctx);
index 873c933bc7d4b509a6c0238fa73299a98f4aafd4..81e1e4ce6c2452dd76a24d4490a60257f4059e26 100644 (file)
@@ -1153,27 +1153,6 @@ static int s5p_mfc_encode_one_frame_v5(struct s5p_mfc_ctx *ctx)
        return 0;
 }
 
-static int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev)
-{
-       unsigned long flags;
-       int new_ctx;
-       int cnt;
-
-       spin_lock_irqsave(&dev->condlock, flags);
-       new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS;
-       cnt = 0;
-       while (!test_bit(new_ctx, &dev->ctx_work_bits)) {
-               new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS;
-               if (++cnt > MFC_NUM_CONTEXTS) {
-                       /* No contexts to run */
-                       spin_unlock_irqrestore(&dev->condlock, flags);
-                       return -EAGAIN;
-               }
-       }
-       spin_unlock_irqrestore(&dev->condlock, flags);
-       return new_ctx;
-}
-
 static void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx)
 {
        struct s5p_mfc_dev *dev = ctx->dev;
@@ -1187,7 +1166,6 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
 {
        struct s5p_mfc_dev *dev = ctx->dev;
        struct s5p_mfc_buf *temp_vb;
-       unsigned long flags;
 
        if (ctx->state == MFCINST_FINISHING) {
                last_frame = MFC_DEC_LAST_FRAME;
@@ -1197,11 +1175,9 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
                return 0;
        }
 
-       spin_lock_irqsave(&dev->irqlock, flags);
        /* Frames are being decoded */
        if (list_empty(&ctx->src_queue)) {
                mfc_debug(2, "No src buffers\n");
-               spin_unlock_irqrestore(&dev->irqlock, flags);
                return -EAGAIN;
        }
        /* Get the next source buffer */
@@ -1210,7 +1186,6 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
        s5p_mfc_set_dec_stream_buffer_v5(ctx,
                vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0),
                ctx->consumed_stream, temp_vb->b->vb2_buf.planes[0].bytesused);
-       spin_unlock_irqrestore(&dev->irqlock, flags);
        dev->curr_ctx = ctx->num;
        if (temp_vb->b->vb2_buf.planes[0].bytesused == 0) {
                last_frame = MFC_DEC_LAST_FRAME;
@@ -1224,21 +1199,17 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
 static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
 {
        struct s5p_mfc_dev *dev = ctx->dev;
-       unsigned long flags;
        struct s5p_mfc_buf *dst_mb;
        struct s5p_mfc_buf *src_mb;
        unsigned long src_y_addr, src_c_addr, dst_addr;
        unsigned int dst_size;
 
-       spin_lock_irqsave(&dev->irqlock, flags);
        if (list_empty(&ctx->src_queue) && ctx->state != MFCINST_FINISHING) {
                mfc_debug(2, "no src buffers\n");
-               spin_unlock_irqrestore(&dev->irqlock, flags);
                return -EAGAIN;
        }
        if (list_empty(&ctx->dst_queue)) {
                mfc_debug(2, "no dst buffers\n");
-               spin_unlock_irqrestore(&dev->irqlock, flags);
                return -EAGAIN;
        }
        if (list_empty(&ctx->src_queue)) {
@@ -1270,7 +1241,6 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
        dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0);
        dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0);
        s5p_mfc_set_enc_stream_buffer_v5(ctx, dst_addr, dst_size);
-       spin_unlock_irqrestore(&dev->irqlock, flags);
        dev->curr_ctx = ctx->num;
        mfc_debug(2, "encoding buffer with index=%d state=%d\n",
                  src_mb ? src_mb->b->vb2_buf.index : -1, ctx->state);
@@ -1281,11 +1251,9 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
 static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx)
 {
        struct s5p_mfc_dev *dev = ctx->dev;
-       unsigned long flags;
        struct s5p_mfc_buf *temp_vb;
 
        /* Initializing decoding - parsing header */
-       spin_lock_irqsave(&dev->irqlock, flags);
        mfc_debug(2, "Preparing to init decoding\n");
        temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
        s5p_mfc_set_dec_desc_buffer(ctx);
@@ -1294,7 +1262,6 @@ static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx)
        s5p_mfc_set_dec_stream_buffer_v5(ctx,
                        vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0),
                        0, temp_vb->b->vb2_buf.planes[0].bytesused);
-       spin_unlock_irqrestore(&dev->irqlock, flags);
        dev->curr_ctx = ctx->num;
        s5p_mfc_init_decode_v5(ctx);
 }
@@ -1302,18 +1269,15 @@ static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx)
 static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx)
 {
        struct s5p_mfc_dev *dev = ctx->dev;
-       unsigned long flags;
        struct s5p_mfc_buf *dst_mb;
        unsigned long dst_addr;
        unsigned int dst_size;
 
        s5p_mfc_set_enc_ref_buffer_v5(ctx);
-       spin_lock_irqsave(&dev->irqlock, flags);
        dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
        dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0);
        dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0);
        s5p_mfc_set_enc_stream_buffer_v5(ctx, dst_addr, dst_size);
-       spin_unlock_irqrestore(&dev->irqlock, flags);
        dev->curr_ctx = ctx->num;
        s5p_mfc_init_encode_v5(ctx);
 }
@@ -1321,7 +1285,6 @@ static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx)
 static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx)
 {
        struct s5p_mfc_dev *dev = ctx->dev;
-       unsigned long flags;
        struct s5p_mfc_buf *temp_vb;
        int ret;
 
@@ -1335,11 +1298,9 @@ static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx)
                        "before starting processing\n");
                return -EAGAIN;
        }
-       spin_lock_irqsave(&dev->irqlock, flags);
        if (list_empty(&ctx->src_queue)) {
                mfc_err("Header has been deallocated in the middle of"
                        " initialization\n");
-               spin_unlock_irqrestore(&dev->irqlock, flags);
                return -EIO;
        }
        temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
@@ -1348,7 +1309,6 @@ static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx)
        s5p_mfc_set_dec_stream_buffer_v5(ctx,
                        vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0),
                        0, temp_vb->b->vb2_buf.planes[0].bytesused);
-       spin_unlock_irqrestore(&dev->irqlock, flags);
        dev->curr_ctx = ctx->num;
        ret = s5p_mfc_set_dec_frame_buffer_v5(ctx);
        if (ret) {
@@ -1472,21 +1432,6 @@ static void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev)
        }
 }
 
-
-static void s5p_mfc_cleanup_queue_v5(struct list_head *lh, struct vb2_queue *vq)
-{
-       struct s5p_mfc_buf *b;
-       int i;
-
-       while (!list_empty(lh)) {
-               b = list_entry(lh->next, struct s5p_mfc_buf, list);
-               for (i = 0; i < b->b->vb2_buf.num_planes; i++)
-                       vb2_set_plane_payload(&b->b->vb2_buf, i, 0);
-               vb2_buffer_done(&b->b->vb2_buf, VB2_BUF_STATE_ERROR);
-               list_del(&b->list);
-       }
-}
-
 static void s5p_mfc_clear_int_flags_v5(struct s5p_mfc_dev *dev)
 {
        mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT);
@@ -1590,11 +1535,6 @@ static int s5p_mfc_err_dec_v5(unsigned int err)
        return (err & S5P_FIMV_ERR_DEC_MASK) >> S5P_FIMV_ERR_DEC_SHIFT;
 }
 
-static int s5p_mfc_err_dspl_v5(unsigned int err)
-{
-       return (err & S5P_FIMV_ERR_DSPL_MASK) >> S5P_FIMV_ERR_DSPL_SHIFT;
-}
-
 static int s5p_mfc_get_img_width_v5(struct s5p_mfc_dev *dev)
 {
        return mfc_read(dev, S5P_FIMV_SI_HRESOL);
@@ -1636,26 +1576,6 @@ static int s5p_mfc_get_enc_dpb_count_v5(struct s5p_mfc_dev *dev)
        return -1;
 }
 
-static int s5p_mfc_get_enc_pic_count_v5(struct s5p_mfc_dev *dev)
-{
-       return mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT);
-}
-
-static int s5p_mfc_get_sei_avail_status_v5(struct s5p_mfc_ctx *ctx)
-{
-       return s5p_mfc_read_info_v5(ctx, FRAME_PACK_SEI_AVAIL);
-}
-
-static int s5p_mfc_get_mvc_num_views_v5(struct s5p_mfc_dev *dev)
-{
-       return -1;
-}
-
-static int s5p_mfc_get_mvc_view_id_v5(struct s5p_mfc_dev *dev)
-{
-       return -1;
-}
-
 static unsigned int s5p_mfc_get_pic_type_top_v5(struct s5p_mfc_ctx *ctx)
 {
        return s5p_mfc_read_info_v5(ctx, PIC_TIME_TOP);
@@ -1688,20 +1608,11 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v5 = {
        .release_dev_context_buffer = s5p_mfc_release_dev_context_buffer_v5,
        .dec_calc_dpb_size = s5p_mfc_dec_calc_dpb_size_v5,
        .enc_calc_src_size = s5p_mfc_enc_calc_src_size_v5,
-       .set_dec_stream_buffer = s5p_mfc_set_dec_stream_buffer_v5,
-       .set_dec_frame_buffer = s5p_mfc_set_dec_frame_buffer_v5,
        .set_enc_stream_buffer = s5p_mfc_set_enc_stream_buffer_v5,
        .set_enc_frame_buffer = s5p_mfc_set_enc_frame_buffer_v5,
        .get_enc_frame_buffer = s5p_mfc_get_enc_frame_buffer_v5,
-       .set_enc_ref_buffer = s5p_mfc_set_enc_ref_buffer_v5,
-       .init_decode = s5p_mfc_init_decode_v5,
-       .init_encode = s5p_mfc_init_encode_v5,
-       .encode_one_frame = s5p_mfc_encode_one_frame_v5,
        .try_run = s5p_mfc_try_run_v5,
-       .cleanup_queue = s5p_mfc_cleanup_queue_v5,
        .clear_int_flags = s5p_mfc_clear_int_flags_v5,
-       .write_info = s5p_mfc_write_info_v5,
-       .read_info = s5p_mfc_read_info_v5,
        .get_dspl_y_adr = s5p_mfc_get_dspl_y_adr_v5,
        .get_dec_y_adr = s5p_mfc_get_dec_y_adr_v5,
        .get_dspl_status = s5p_mfc_get_dspl_status_v5,
@@ -1712,7 +1623,6 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v5 = {
        .get_int_reason = s5p_mfc_get_int_reason_v5,
        .get_int_err = s5p_mfc_get_int_err_v5,
        .err_dec = s5p_mfc_err_dec_v5,
-       .err_dspl = s5p_mfc_err_dspl_v5,
        .get_img_width = s5p_mfc_get_img_width_v5,
        .get_img_height = s5p_mfc_get_img_height_v5,
        .get_dpb_count = s5p_mfc_get_dpb_count_v5,
@@ -1721,10 +1631,6 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v5 = {
        .get_enc_strm_size = s5p_mfc_get_enc_strm_size_v5,
        .get_enc_slice_type = s5p_mfc_get_enc_slice_type_v5,
        .get_enc_dpb_count = s5p_mfc_get_enc_dpb_count_v5,
-       .get_enc_pic_count = s5p_mfc_get_enc_pic_count_v5,
-       .get_sei_avail_status = s5p_mfc_get_sei_avail_status_v5,
-       .get_mvc_num_views = s5p_mfc_get_mvc_num_views_v5,
-       .get_mvc_view_id = s5p_mfc_get_mvc_view_id_v5,
        .get_pic_type_top = s5p_mfc_get_pic_type_top_v5,
        .get_pic_type_bot = s5p_mfc_get_pic_type_bot_v5,
        .get_crop_info_h = s5p_mfc_get_crop_info_h_v5,
index b95845347348a21f33dffe63799108be336f16ed..d6f207e859ab947b2ae9c99def34caadd1a5695a 100644 (file)
@@ -505,7 +505,7 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
        }
 
        writel(ctx->inst_no, mfc_regs->instance_id);
-       s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
+       s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
                        S5P_FIMV_CH_INIT_BUFS_V6, NULL);
 
        mfc_debug(2, "After setting buffers.\n");
@@ -603,7 +603,7 @@ static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx)
        }
 
        writel(ctx->inst_no, mfc_regs->instance_id);
-       s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
+       s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
                        S5P_FIMV_CH_INIT_BUFS_V6, NULL);
 
        mfc_debug_leave();
@@ -1378,7 +1378,7 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
        writel(ctx->sei_fp_parse & 0x1, mfc_regs->d_sei_enable);
 
        writel(ctx->inst_no, mfc_regs->instance_id);
-       s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
+       s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
                        S5P_FIMV_CH_SEQ_HEADER_V6, NULL);
 
        mfc_debug_leave();
@@ -1393,7 +1393,7 @@ static inline void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush)
        if (flush) {
                dev->curr_ctx = ctx->num;
                writel(ctx->inst_no, mfc_regs->instance_id);
-               s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
+               s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
                                S5P_FIMV_H2R_CMD_FLUSH_V6, NULL);
        }
 }
@@ -1413,11 +1413,11 @@ static int s5p_mfc_decode_one_frame_v6(struct s5p_mfc_ctx *ctx,
         * is the last frame or not. */
        switch (last_frame) {
        case 0:
-               s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
+               s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
                                S5P_FIMV_CH_FRAME_START_V6, NULL);
                break;
        case 1:
-               s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
+               s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
                                S5P_FIMV_CH_LAST_FRAME_V6, NULL);
                break;
        default:
@@ -1455,7 +1455,7 @@ static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx)
        }
 
        writel(ctx->inst_no, mfc_regs->instance_id);
-       s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
+       s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
                        S5P_FIMV_CH_SEQ_HEADER_V6, NULL);
 
        return 0;
@@ -1500,37 +1500,13 @@ static int s5p_mfc_encode_one_frame_v6(struct s5p_mfc_ctx *ctx)
                cmd = S5P_FIMV_CH_LAST_FRAME_V6;
 
        writel(ctx->inst_no, mfc_regs->instance_id);
-       s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev, cmd, NULL);
+       s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, cmd, NULL);
 
        mfc_debug(2, "--\n");
 
        return 0;
 }
 
-static inline int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev)
-{
-       unsigned long flags;
-       int new_ctx;
-       int cnt;
-
-       spin_lock_irqsave(&dev->condlock, flags);
-       mfc_debug(2, "Previous context: %d (bits %08lx)\n", dev->curr_ctx,
-                                                       dev->ctx_work_bits);
-       new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS;
-       cnt = 0;
-       while (!test_bit(new_ctx, &dev->ctx_work_bits)) {
-               new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS;
-               cnt++;
-               if (cnt > MFC_NUM_CONTEXTS) {
-                       /* No contexts to run */
-                       spin_unlock_irqrestore(&dev->condlock, flags);
-                       return -EAGAIN;
-               }
-       }
-       spin_unlock_irqrestore(&dev->condlock, flags);
-       return new_ctx;
-}
-
 static inline void s5p_mfc_run_dec_last_frames(struct s5p_mfc_ctx *ctx)
 {
        struct s5p_mfc_dev *dev = ctx->dev;
@@ -1544,7 +1520,6 @@ static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx)
 {
        struct s5p_mfc_dev *dev = ctx->dev;
        struct s5p_mfc_buf *temp_vb;
-       unsigned long flags;
        int last_frame = 0;
 
        if (ctx->state == MFCINST_FINISHING) {
@@ -1556,11 +1531,9 @@ static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx)
                return 0;
        }
 
-       spin_lock_irqsave(&dev->irqlock, flags);
        /* Frames are being decoded */
        if (list_empty(&ctx->src_queue)) {
                mfc_debug(2, "No src buffers.\n");
-               spin_unlock_irqrestore(&dev->irqlock, flags);
                return -EAGAIN;
        }
        /* Get the next source buffer */
@@ -1570,7 +1543,6 @@ static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx)
                vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0),
                        ctx->consumed_stream,
                        temp_vb->b->vb2_buf.planes[0].bytesused);
-       spin_unlock_irqrestore(&dev->irqlock, flags);
 
        dev->curr_ctx = ctx->num;
        if (temp_vb->b->vb2_buf.planes[0].bytesused == 0) {
@@ -1586,7 +1558,6 @@ static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx)
 static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
 {
        struct s5p_mfc_dev *dev = ctx->dev;
-       unsigned long flags;
        struct s5p_mfc_buf *dst_mb;
        struct s5p_mfc_buf *src_mb;
        unsigned long src_y_addr, src_c_addr, dst_addr;
@@ -1595,17 +1566,13 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
        */
        unsigned int dst_size;
 
-       spin_lock_irqsave(&dev->irqlock, flags);
-
        if (list_empty(&ctx->src_queue) && ctx->state != MFCINST_FINISHING) {
                mfc_debug(2, "no src buffers.\n");
-               spin_unlock_irqrestore(&dev->irqlock, flags);
                return -EAGAIN;
        }
 
        if (list_empty(&ctx->dst_queue)) {
                mfc_debug(2, "no dst buffers.\n");
-               spin_unlock_irqrestore(&dev->irqlock, flags);
                return -EAGAIN;
        }
 
@@ -1639,8 +1606,6 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
 
        s5p_mfc_set_enc_stream_buffer_v6(ctx, dst_addr, dst_size);
 
-       spin_unlock_irqrestore(&dev->irqlock, flags);
-
        dev->curr_ctx = ctx->num;
        s5p_mfc_encode_one_frame_v6(ctx);
 
@@ -1650,18 +1615,15 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
 static inline void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx)
 {
        struct s5p_mfc_dev *dev = ctx->dev;
-       unsigned long flags;
        struct s5p_mfc_buf *temp_vb;
 
        /* Initializing decoding - parsing header */
-       spin_lock_irqsave(&dev->irqlock, flags);
        mfc_debug(2, "Preparing to init decoding.\n");
        temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
        mfc_debug(2, "Header size: %d\n", temp_vb->b->vb2_buf.planes[0].bytesused);
        s5p_mfc_set_dec_stream_buffer_v6(ctx,
                vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0), 0,
                        temp_vb->b->vb2_buf.planes[0].bytesused);
-       spin_unlock_irqrestore(&dev->irqlock, flags);
        dev->curr_ctx = ctx->num;
        s5p_mfc_init_decode_v6(ctx);
 }
@@ -1669,18 +1631,14 @@ static inline void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx)
 static inline void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx)
 {
        struct s5p_mfc_dev *dev = ctx->dev;
-       unsigned long flags;
        struct s5p_mfc_buf *dst_mb;
        unsigned long dst_addr;
        unsigned int dst_size;
 
-       spin_lock_irqsave(&dev->irqlock, flags);
-
        dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
        dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0);
        dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0);
        s5p_mfc_set_enc_stream_buffer_v6(ctx, dst_addr, dst_size);
-       spin_unlock_irqrestore(&dev->irqlock, flags);
        dev->curr_ctx = ctx->num;
        s5p_mfc_init_encode_v6(ctx);
 }
@@ -1846,21 +1804,6 @@ static void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev)
        }
 }
 
-
-static void s5p_mfc_cleanup_queue_v6(struct list_head *lh, struct vb2_queue *vq)
-{
-       struct s5p_mfc_buf *b;
-       int i;
-
-       while (!list_empty(lh)) {
-               b = list_entry(lh->next, struct s5p_mfc_buf, list);
-               for (i = 0; i < b->b->vb2_buf.num_planes; i++)
-                       vb2_set_plane_payload(&b->b->vb2_buf, i, 0);
-               vb2_buffer_done(&b->b->vb2_buf, VB2_BUF_STATE_ERROR);
-               list_del(&b->list);
-       }
-}
-
 static void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev)
 {
        const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
@@ -1868,14 +1811,6 @@ static void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev)
        writel(0, mfc_regs->risc2host_int);
 }
 
-static void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data,
-               unsigned int ofs)
-{
-       s5p_mfc_clock_on();
-       writel(data, (void __iomem *)((unsigned long)ofs));
-       s5p_mfc_clock_off();
-}
-
 static unsigned int
 s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned long ofs)
 {
@@ -1942,11 +1877,6 @@ static int s5p_mfc_err_dec_v6(unsigned int err)
        return (err & S5P_FIMV_ERR_DEC_MASK_V6) >> S5P_FIMV_ERR_DEC_SHIFT_V6;
 }
 
-static int s5p_mfc_err_dspl_v6(unsigned int err)
-{
-       return (err & S5P_FIMV_ERR_DSPL_MASK_V6) >> S5P_FIMV_ERR_DSPL_SHIFT_V6;
-}
-
 static int s5p_mfc_get_img_width_v6(struct s5p_mfc_dev *dev)
 {
        return readl(dev->mfc_regs->d_display_frame_width);
@@ -1987,27 +1917,6 @@ static int s5p_mfc_get_enc_slice_type_v6(struct s5p_mfc_dev *dev)
        return readl(dev->mfc_regs->e_slice_type);
 }
 
-static int s5p_mfc_get_enc_pic_count_v6(struct s5p_mfc_dev *dev)
-{
-       return readl(dev->mfc_regs->e_picture_count);
-}
-
-static int s5p_mfc_get_sei_avail_status_v6(struct s5p_mfc_ctx *ctx)
-{
-       struct s5p_mfc_dev *dev = ctx->dev;
-       return readl(dev->mfc_regs->d_frame_pack_sei_avail);
-}
-
-static int s5p_mfc_get_mvc_num_views_v6(struct s5p_mfc_dev *dev)
-{
-       return readl(dev->mfc_regs->d_mvc_num_views);
-}
-
-static int s5p_mfc_get_mvc_view_id_v6(struct s5p_mfc_dev *dev)
-{
-       return readl(dev->mfc_regs->d_mvc_view_id);
-}
-
 static unsigned int s5p_mfc_get_pic_type_top_v6(struct s5p_mfc_ctx *ctx)
 {
        return s5p_mfc_read_info_v6(ctx,
@@ -2282,20 +2191,11 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = {
                s5p_mfc_release_dev_context_buffer_v6,
        .dec_calc_dpb_size = s5p_mfc_dec_calc_dpb_size_v6,
        .enc_calc_src_size = s5p_mfc_enc_calc_src_size_v6,
-       .set_dec_stream_buffer = s5p_mfc_set_dec_stream_buffer_v6,
-       .set_dec_frame_buffer = s5p_mfc_set_dec_frame_buffer_v6,
        .set_enc_stream_buffer = s5p_mfc_set_enc_stream_buffer_v6,
        .set_enc_frame_buffer = s5p_mfc_set_enc_frame_buffer_v6,
        .get_enc_frame_buffer = s5p_mfc_get_enc_frame_buffer_v6,
-       .set_enc_ref_buffer = s5p_mfc_set_enc_ref_buffer_v6,
-       .init_decode = s5p_mfc_init_decode_v6,
-       .init_encode = s5p_mfc_init_encode_v6,
-       .encode_one_frame = s5p_mfc_encode_one_frame_v6,
        .try_run = s5p_mfc_try_run_v6,
-       .cleanup_queue = s5p_mfc_cleanup_queue_v6,
        .clear_int_flags = s5p_mfc_clear_int_flags_v6,
-       .write_info = s5p_mfc_write_info_v6,
-       .read_info = s5p_mfc_read_info_v6,
        .get_dspl_y_adr = s5p_mfc_get_dspl_y_adr_v6,
        .get_dec_y_adr = s5p_mfc_get_dec_y_adr_v6,
        .get_dspl_status = s5p_mfc_get_dspl_status_v6,
@@ -2306,7 +2206,6 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = {
        .get_int_reason = s5p_mfc_get_int_reason_v6,
        .get_int_err = s5p_mfc_get_int_err_v6,
        .err_dec = s5p_mfc_err_dec_v6,
-       .err_dspl = s5p_mfc_err_dspl_v6,
        .get_img_width = s5p_mfc_get_img_width_v6,
        .get_img_height = s5p_mfc_get_img_height_v6,
        .get_dpb_count = s5p_mfc_get_dpb_count_v6,
@@ -2315,10 +2214,6 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = {
        .get_enc_strm_size = s5p_mfc_get_enc_strm_size_v6,
        .get_enc_slice_type = s5p_mfc_get_enc_slice_type_v6,
        .get_enc_dpb_count = s5p_mfc_get_enc_dpb_count_v6,
-       .get_enc_pic_count = s5p_mfc_get_enc_pic_count_v6,
-       .get_sei_avail_status = s5p_mfc_get_sei_avail_status_v6,
-       .get_mvc_num_views = s5p_mfc_get_mvc_num_views_v6,
-       .get_mvc_view_id = s5p_mfc_get_mvc_view_id_v6,
        .get_pic_type_top = s5p_mfc_get_pic_type_top_v6,
        .get_pic_type_bot = s5p_mfc_get_pic_type_bot_v6,
        .get_crop_info_h = s5p_mfc_get_crop_info_h_v6,
index 79940757b34f863e005adef86c7e37cdba1c5295..e71b13e40f596b2cebf5e283edc573fa5012f3fe 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/v4l2-dv-timings.h>
 
-#include <media/s5p_hdmi.h>
+#include <linux/platform_data/media/s5p_hdmi.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-device.h>
@@ -627,7 +627,7 @@ static int hdmi_s_dv_timings(struct v4l2_subdev *sd,
 
        for (i = 0; i < ARRAY_SIZE(hdmi_timings); i++)
                if (v4l2_match_dv_timings(&hdmi_timings[i].dv_timings,
-                                       timings, 0))
+                                       timings, 0, false))
                        break;
        if (i == ARRAY_SIZE(hdmi_timings)) {
                dev_err(dev, "timings not supported\n");
index dc1c679e136c18456d09697e8d65bd87d67c37c4..d9e7f030294c7b3bcfa4f3d1984353a734f69898 100644 (file)
@@ -881,7 +881,7 @@ static const struct v4l2_file_operations mxr_fops = {
        .unlocked_ioctl = video_ioctl2,
 };
 
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
        unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[],
        void *alloc_ctxs[])
 {
index 8d171310af8ff65639eafaafc3acc32c188ada5e..0a97f9ab4f76f2a0a1295fe87f3eb4bc53803a54 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/slab.h>
 
-#include <media/sii9234.h>
+#include <linux/platform_data/media/sii9234.h>
 #include <media/v4l2-subdev.h>
 
 MODULE_AUTHOR("Tomasz Stanislawski <t.stanislaws@samsung.com>");
index d6ab33e7060aa824accddf2e295d77062f37984c..82b5d69b87fa6a0a9fc46080854d9b2dc0688894 100644 (file)
@@ -865,32 +865,14 @@ static const struct v4l2_ioctl_ops sh_veu_ioctl_ops = {
                /* ========== Queue operations ========== */
 
 static int sh_veu_queue_setup(struct vb2_queue *vq,
-                             const void *parg,
                              unsigned int *nbuffers, unsigned int *nplanes,
                              unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *f = parg;
        struct sh_veu_dev *veu = vb2_get_drv_priv(vq);
-       struct sh_veu_vfmt *vfmt;
-       unsigned int size, count = *nbuffers;
-
-       if (f) {
-               const struct v4l2_pix_format *pix = &f->fmt.pix;
-               const struct sh_veu_format *fmt = sh_veu_find_fmt(f);
-               struct v4l2_format ftmp = *f;
-
-               if (fmt->fourcc != pix->pixelformat)
-                       return -EINVAL;
-               sh_veu_try_fmt(&ftmp, fmt);
-               if (ftmp.fmt.pix.width != pix->width ||
-                   ftmp.fmt.pix.height != pix->height)
-                       return -EINVAL;
-               size = pix->bytesperline ? pix->bytesperline * pix->height * fmt->depth / fmt->ydepth :
-                       pix->width * pix->height * fmt->depth / fmt->ydepth;
-       } else {
-               vfmt = sh_veu_get_vfmt(veu, vq->type);
-               size = vfmt->bytesperline * vfmt->frame.height * vfmt->fmt->depth / vfmt->fmt->ydepth;
-       }
+       struct sh_veu_vfmt *vfmt = sh_veu_get_vfmt(veu, vq->type);
+       unsigned int count = *nbuffers;
+       unsigned int size = vfmt->bytesperline * vfmt->frame.height *
+               vfmt->fmt->depth / vfmt->fmt->ydepth;
 
        if (count < 2)
                *nbuffers = count = 2;
@@ -900,6 +882,11 @@ static int sh_veu_queue_setup(struct vb2_queue *vq,
                *nbuffers = count;
        }
 
+       if (*nplanes) {
+               alloc_ctxs[0] = veu->alloc_ctx;
+               return sizes[0] < size ? -EINVAL : 0;
+       }
+
        *nplanes = 1;
        sizes[0] = size;
        alloc_ctxs[0] = veu->alloc_ctx;
@@ -1107,7 +1094,7 @@ static irqreturn_t sh_veu_isr(int irq, void *dev_id)
        if (!src || !dst)
                return IRQ_NONE;
 
-       dst->timestamp = src->timestamp;
+       dst->vb2_buf.timestamp = src->vb2_buf.timestamp;
        dst->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
        dst->flags |=
                src->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
index 2231f8922df3d0fc0b2a72ac936278e1a39e024d..115740498274e6604daa4a92e6631295aaf74466 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/videodev2.h>
 #include <linux/module.h>
 
-#include <media/sh_vou.h>
+#include <media/drv-intf/sh_vou.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
@@ -243,22 +243,21 @@ static void sh_vou_stream_config(struct sh_vou_device *vou_dev)
 }
 
 /* Locking: caller holds fop_lock mutex */
-static int sh_vou_queue_setup(struct vb2_queue *vq, const void *parg,
+static int sh_vou_queue_setup(struct vb2_queue *vq,
                       unsigned int *nbuffers, unsigned int *nplanes,
                       unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct sh_vou_device *vou_dev = vb2_get_drv_priv(vq);
        struct v4l2_pix_format *pix = &vou_dev->pix;
        int bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8;
 
        dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
 
-       if (fmt && fmt->fmt.pix.sizeimage < pix->height * bytes_per_line)
-               return -EINVAL;
-       *nplanes = 1;
-       sizes[0] = fmt ? fmt->fmt.pix.sizeimage : pix->height * bytes_per_line;
        alloc_ctxs[0] = vou_dev->alloc_ctx;
+       if (*nplanes)
+               return sizes[0] < pix->height * bytes_per_line ? -EINVAL : 0;
+       *nplanes = 1;
+       sizes[0] = pix->height * bytes_per_line;
        return 0;
 }
 
@@ -1071,7 +1070,7 @@ static irqreturn_t sh_vou_isr(int irq, void *dev_id)
 
        list_del(&vb->list);
 
-       v4l2_get_timestamp(&vb->vb.timestamp);
+       vb->vb.vb2_buf.timestamp = ktime_get_ns();
        vb->vb.sequence = vou_dev->sequence++;
        vb->vb.field = V4L2_FIELD_INTERLACED;
        vb2_buffer_done(&vb->vb.vb2_buf, VB2_BUF_STATE_DONE);
index 454f68f0cdad36d56acd1110976d0834771ec0fc..c398b285180cda757ec291bb6cc0c004c3c27de4 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/slab.h>
 
 #include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
 #include <media/v4l2-of.h>
 #include <media/videobuf2-dma-contig.h>
 
@@ -79,6 +79,7 @@ struct atmel_isi {
        dma_addr_t                      fb_descriptors_phys;
        struct                          list_head dma_desc_head;
        struct isi_dma_desc             dma_desc[MAX_BUFFER_NUM];
+       bool                            enable_preview_path;
 
        struct completion               complete;
        /* ISI peripherial clock */
@@ -103,13 +104,55 @@ static u32 isi_readl(struct atmel_isi *isi, u32 reg)
        return readl(isi->regs + reg);
 }
 
+static u32 setup_cfg2_yuv_swap(struct atmel_isi *isi,
+               const struct soc_camera_format_xlate *xlate)
+{
+       if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUYV) {
+               /* all convert to YUYV */
+               switch (xlate->code) {
+               case MEDIA_BUS_FMT_VYUY8_2X8:
+                       return ISI_CFG2_YCC_SWAP_MODE_3;
+               case MEDIA_BUS_FMT_UYVY8_2X8:
+                       return ISI_CFG2_YCC_SWAP_MODE_2;
+               case MEDIA_BUS_FMT_YVYU8_2X8:
+                       return ISI_CFG2_YCC_SWAP_MODE_1;
+               }
+       } else if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_RGB565) {
+               /*
+                * Preview path is enabled, it will convert UYVY to RGB format.
+                * But if sensor output format is not UYVY, we need to set
+                * YCC_SWAP_MODE to convert it as UYVY.
+                */
+               switch (xlate->code) {
+               case MEDIA_BUS_FMT_VYUY8_2X8:
+                       return ISI_CFG2_YCC_SWAP_MODE_1;
+               case MEDIA_BUS_FMT_YUYV8_2X8:
+                       return ISI_CFG2_YCC_SWAP_MODE_2;
+               case MEDIA_BUS_FMT_YVYU8_2X8:
+                       return ISI_CFG2_YCC_SWAP_MODE_3;
+               }
+       }
+
+       /*
+        * By default, no swap for the codec path of Atmel ISI. So codec
+        * output is same as sensor's output.
+        * For instance, if sensor's output is YUYV, then codec outputs YUYV.
+        * And if sensor's output is UYVY, then codec outputs UYVY.
+        */
+       return ISI_CFG2_YCC_SWAP_DEFAULT;
+}
+
 static void configure_geometry(struct atmel_isi *isi, u32 width,
-                       u32 height, u32 code)
+               u32 height, const struct soc_camera_format_xlate *xlate)
 {
-       u32 cfg2;
+       u32 cfg2, psize;
+       u32 fourcc = xlate->host_fmt->fourcc;
+
+       isi->enable_preview_path = fourcc == V4L2_PIX_FMT_RGB565 ||
+                                  fourcc == V4L2_PIX_FMT_RGB32;
 
        /* According to sensor's output format to set cfg2 */
-       switch (code) {
+       switch (xlate->code) {
        default:
        /* Grey */
        case MEDIA_BUS_FMT_Y8_1X8:
@@ -117,16 +160,11 @@ static void configure_geometry(struct atmel_isi *isi, u32 width,
                break;
        /* YUV */
        case MEDIA_BUS_FMT_VYUY8_2X8:
-               cfg2 = ISI_CFG2_YCC_SWAP_MODE_3 | ISI_CFG2_COL_SPACE_YCbCr;
-               break;
        case MEDIA_BUS_FMT_UYVY8_2X8:
-               cfg2 = ISI_CFG2_YCC_SWAP_MODE_2 | ISI_CFG2_COL_SPACE_YCbCr;
-               break;
        case MEDIA_BUS_FMT_YVYU8_2X8:
-               cfg2 = ISI_CFG2_YCC_SWAP_MODE_1 | ISI_CFG2_COL_SPACE_YCbCr;
-               break;
        case MEDIA_BUS_FMT_YUYV8_2X8:
-               cfg2 = ISI_CFG2_YCC_SWAP_DEFAULT | ISI_CFG2_COL_SPACE_YCbCr;
+               cfg2 = ISI_CFG2_COL_SPACE_YCbCr |
+                               setup_cfg2_yuv_swap(isi, xlate);
                break;
        /* RGB, TODO */
        }
@@ -139,6 +177,16 @@ static void configure_geometry(struct atmel_isi *isi, u32 width,
        cfg2 |= ((height - 1) << ISI_CFG2_IM_VSIZE_OFFSET)
                        & ISI_CFG2_IM_VSIZE_MASK;
        isi_writel(isi, ISI_CFG2, cfg2);
+
+       /* No down sampling, preview size equal to sensor output size */
+       psize = ((width - 1) << ISI_PSIZE_PREV_HSIZE_OFFSET) &
+               ISI_PSIZE_PREV_HSIZE_MASK;
+       psize |= ((height - 1) << ISI_PSIZE_PREV_VSIZE_OFFSET) &
+               ISI_PSIZE_PREV_VSIZE_MASK;
+       isi_writel(isi, ISI_PSIZE, psize);
+       isi_writel(isi, ISI_PDECF, ISI_PDECF_NO_SAMPLING);
+
+       return;
 }
 
 static bool is_supported(struct soc_camera_device *icd,
@@ -151,8 +199,9 @@ static bool is_supported(struct soc_camera_device *icd,
        case V4L2_PIX_FMT_UYVY:
        case V4L2_PIX_FMT_YVYU:
        case V4L2_PIX_FMT_VYUY:
+       /* RGB */
+       case V4L2_PIX_FMT_RGB565:
                return true;
-       /* RGB, TODO */
        default:
                return false;
        }
@@ -165,7 +214,7 @@ static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi)
                struct frame_buffer *buf = isi->active;
 
                list_del_init(&buf->list);
-               v4l2_get_timestamp(&vbuf->timestamp);
+               vbuf->vb2_buf.timestamp = ktime_get_ns();
                vbuf->sequence = isi->sequence++;
                vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE);
        }
@@ -176,11 +225,19 @@ static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi)
                /* start next dma frame. */
                isi->active = list_entry(isi->video_buffer_list.next,
                                        struct frame_buffer, list);
-               isi_writel(isi, ISI_DMA_C_DSCR,
-                       (u32)isi->active->p_dma_desc->fbd_phys);
-               isi_writel(isi, ISI_DMA_C_CTRL,
-                       ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
-               isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
+               if (!isi->enable_preview_path) {
+                       isi_writel(isi, ISI_DMA_C_DSCR,
+                               (u32)isi->active->p_dma_desc->fbd_phys);
+                       isi_writel(isi, ISI_DMA_C_CTRL,
+                               ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
+                       isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
+               } else {
+                       isi_writel(isi, ISI_DMA_P_DSCR,
+                               (u32)isi->active->p_dma_desc->fbd_phys);
+                       isi_writel(isi, ISI_DMA_P_CTRL,
+                               ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
+                       isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_P_CH);
+               }
        }
        return IRQ_HANDLED;
 }
@@ -207,7 +264,8 @@ static irqreturn_t isi_interrupt(int irq, void *dev_id)
                isi_writel(isi, ISI_INTDIS, ISI_CTRL_DIS);
                ret = IRQ_HANDLED;
        } else {
-               if (likely(pending & ISI_SR_CXFR_DONE))
+               if (likely(pending & ISI_SR_CXFR_DONE) ||
+                               likely(pending & ISI_SR_PXFR_DONE))
                        ret = atmel_isi_handle_streaming(isi);
        }
 
@@ -245,7 +303,7 @@ static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset)
 /* ------------------------------------------------------------------
        Videobuf operations
    ------------------------------------------------------------------*/
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
                                unsigned int *nbuffers, unsigned int *nplanes,
                                unsigned int sizes[], void *alloc_ctxs[])
 {
@@ -352,21 +410,35 @@ static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer)
                        ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE);
 
        /* Check if already in a frame */
-       if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) {
-               dev_err(isi->soc_host.icd->parent, "Already in frame handling.\n");
-               return;
-       }
+       if (!isi->enable_preview_path) {
+               if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) {
+                       dev_err(isi->soc_host.icd->parent, "Already in frame handling.\n");
+                       return;
+               }
 
-       isi_writel(isi, ISI_DMA_C_DSCR, (u32)buffer->p_dma_desc->fbd_phys);
-       isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
-       isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
+               isi_writel(isi, ISI_DMA_C_DSCR,
+                               (u32)buffer->p_dma_desc->fbd_phys);
+               isi_writel(isi, ISI_DMA_C_CTRL,
+                               ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
+               isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
+       } else {
+               isi_writel(isi, ISI_DMA_P_DSCR,
+                               (u32)buffer->p_dma_desc->fbd_phys);
+               isi_writel(isi, ISI_DMA_P_CTRL,
+                               ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
+               isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_P_CH);
+       }
 
        cfg1 &= ~ISI_CFG1_FRATE_DIV_MASK;
        /* Enable linked list */
        cfg1 |= isi->pdata.frate | ISI_CFG1_DISCR;
 
-       /* Enable codec path and ISI */
-       ctrl = ISI_CTRL_CDC | ISI_CTRL_EN;
+       /* Enable ISI */
+       ctrl = ISI_CTRL_EN;
+
+       if (!isi->enable_preview_path)
+               ctrl |= ISI_CTRL_CDC;
+
        isi_writel(isi, ISI_CTRL, ctrl);
        isi_writel(isi, ISI_CFG1, cfg1);
 }
@@ -411,7 +483,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
        isi_writel(isi, ISI_INTDIS, (u32)~0UL);
 
        configure_geometry(isi, icd->user_width, icd->user_height,
-                               icd->current_fmt->code);
+                               icd->current_fmt);
 
        spin_lock_irq(&isi->lock);
        /* Clear any pending interrupt */
@@ -443,15 +515,17 @@ static void stop_streaming(struct vb2_queue *vq)
        }
        spin_unlock_irq(&isi->lock);
 
-       timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ;
-       /* Wait until the end of the current frame. */
-       while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) &&
-                       time_before(jiffies, timeout))
-               msleep(1);
+       if (!isi->enable_preview_path) {
+               timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ;
+               /* Wait until the end of the current frame. */
+               while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) &&
+                               time_before(jiffies, timeout))
+                       msleep(1);
 
-       if (time_after(jiffies, timeout))
-               dev_err(icd->parent,
-                       "Timeout waiting for finishing codec request\n");
+               if (time_after(jiffies, timeout))
+                       dev_err(icd->parent,
+                               "Timeout waiting for finishing codec request\n");
+       }
 
        /* Disable interrupts */
        isi_writel(isi, ISI_INTDIS,
@@ -617,6 +691,14 @@ static const struct soc_mbus_pixelfmt isi_camera_formats[] = {
                .order                  = SOC_MBUS_ORDER_LE,
                .layout                 = SOC_MBUS_LAYOUT_PACKED,
        },
+       {
+               .fourcc                 = V4L2_PIX_FMT_RGB565,
+               .name                   = "RGB565",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_2X8_PADHI,
+               .order                  = SOC_MBUS_ORDER_LE,
+               .layout                 = SOC_MBUS_LAYOUT_PACKED,
+       },
 };
 
 /* This will be corrected as we get more formats */
@@ -673,7 +755,7 @@ static int isi_camera_get_formats(struct soc_camera_device *icd,
                                  struct soc_camera_format_xlate *xlate)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       int formats = 0, ret;
+       int formats = 0, ret, i, n;
        /* sensor format */
        struct v4l2_subdev_mbus_code_enum code = {
                .which = V4L2_SUBDEV_FORMAT_ACTIVE,
@@ -707,11 +789,11 @@ static int isi_camera_get_formats(struct soc_camera_device *icd,
        case MEDIA_BUS_FMT_VYUY8_2X8:
        case MEDIA_BUS_FMT_YUYV8_2X8:
        case MEDIA_BUS_FMT_YVYU8_2X8:
-               formats++;
-               if (xlate) {
-                       xlate->host_fmt = &isi_camera_formats[0];
+               n = ARRAY_SIZE(isi_camera_formats);
+               formats += n;
+               for (i = 0; xlate && i < n; i++, xlate++) {
+                       xlate->host_fmt = &isi_camera_formats[i];
                        xlate->code     = code.code;
-                       xlate++;
                        dev_dbg(icd->parent, "Providing format %s using code %d\n",
                                isi_camera_formats[0].name, code.code);
                }
index 5acc771d2edcd61d2b4f2d6f7f1507c4f4422ffa..0acb32a2b65ce3bef62ce3132f73923a2062a0d1 100644 (file)
 #define ISI_CFG2_IM_VSIZE_MASK         (0x7FF << ISI_CFG2_IM_VSIZE_OFFSET)
 #define ISI_CFG2_IM_HSIZE_MASK         (0x7FF << ISI_CFG2_IM_HSIZE_OFFSET)
 
+/* Bitfields in PSIZE */
+#define ISI_PSIZE_PREV_VSIZE_OFFSET    0
+#define ISI_PSIZE_PREV_HSIZE_OFFSET    16
+#define ISI_PSIZE_PREV_VSIZE_MASK      (0x3FF << ISI_PSIZE_PREV_VSIZE_OFFSET)
+#define ISI_PSIZE_PREV_HSIZE_MASK      (0x3FF << ISI_PSIZE_PREV_HSIZE_OFFSET)
+
+/* Bitfields in PDECF */
+#define ISI_PDECF_DEC_FACTOR_MASK      (0xFF << 0)
+#define        ISI_PDECF_NO_SAMPLING           (16)
+
 /* Bitfields in CTRL */
 /* Also using in SR(ISI_V2) */
 #define ISI_CTRL_EN                            (1 << 0)
index 1f28d21a3c9a05672081b40abff0f0f368ff32af..48dd5b7851b520ff0c5a5f8c67701f3e59dd0c91 100644 (file)
 #include <media/videobuf2-v4l2.h>
 #include <media/videobuf2-dma-contig.h>
 #include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
 
 #include <linux/videodev2.h>
 
-#include <linux/platform_data/camera-mx2.h>
+#include <linux/platform_data/media/camera-mx2.h>
 
 #include <asm/dma.h>
 
@@ -469,21 +469,15 @@ static void mx2_camera_clock_stop(struct soc_camera_host *ici)
  *  Videobuf operations
  */
 static int mx2_videobuf_setup(struct vb2_queue *vq,
-                       const void *parg,
                        unsigned int *count, unsigned int *num_planes,
                        unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
 
        dev_dbg(icd->parent, "count=%d, size=%d\n", *count, sizes[0]);
 
-       /* TODO: support for VIDIOC_CREATE_BUFS not ready */
-       if (fmt != NULL)
-               return -ENOTTY;
-
        alloc_ctxs[0] = pcdev->alloc_ctx;
 
        sizes[0] = icd->sizeimage;
@@ -1351,7 +1345,7 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
                                vb2_get_plane_payload(vb, 0));
 
                list_del_init(&buf->internal.queue);
-               v4l2_get_timestamp(&vbuf->timestamp);
+               vb->timestamp = ktime_get_ns();
                vbuf->sequence = pcdev->frame_count;
                if (err)
                        vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
index 49c3a257a916e710aa8a2f832dc4030b5c98dbec..169ed11502265610fef99a6205f4c73456d64190 100644 (file)
@@ -23,9 +23,9 @@
 #include <media/v4l2-dev.h>
 #include <media/videobuf2-dma-contig.h>
 #include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
 
-#include <linux/platform_data/camera-mx3.h>
+#include <linux/platform_data/media/camera-mx3.h>
 #include <linux/platform_data/dma-imx.h>
 
 #define MX3_CAM_DRV_NAME "mx3-camera"
@@ -155,7 +155,7 @@ static void mx3_cam_dma_done(void *arg)
                struct mx3_camera_buffer *buf = to_mx3_vb(vb);
 
                list_del_init(&buf->queue);
-               v4l2_get_timestamp(&vb->timestamp);
+               vb->vb2_buf.timestamp = ktime_get_ns();
                vb->field = mx3_cam->field;
                vb->sequence = mx3_cam->sequence++;
                vb2_buffer_done(&vb->vb2_buf, VB2_BUF_STATE_DONE);
@@ -185,11 +185,9 @@ static void mx3_cam_dma_done(void *arg)
  * Calculate the __buffer__ (not data) size and number of buffers.
  */
 static int mx3_videobuf_setup(struct vb2_queue *vq,
-                       const void *parg,
                        unsigned int *count, unsigned int *num_planes,
                        unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
@@ -197,33 +195,6 @@ static int mx3_videobuf_setup(struct vb2_queue *vq,
        if (!mx3_cam->idmac_channel[0])
                return -EINVAL;
 
-       if (fmt) {
-               const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd,
-                                                               fmt->fmt.pix.pixelformat);
-               unsigned int bytes_per_line;
-               int ret;
-
-               if (!xlate)
-                       return -EINVAL;
-
-               ret = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
-                                             xlate->host_fmt);
-               if (ret < 0)
-                       return ret;
-
-               bytes_per_line = max_t(u32, fmt->fmt.pix.bytesperline, ret);
-
-               ret = soc_mbus_image_size(xlate->host_fmt, bytes_per_line,
-                                         fmt->fmt.pix.height);
-               if (ret < 0)
-                       return ret;
-
-               sizes[0] = max_t(u32, fmt->fmt.pix.sizeimage, ret);
-       } else {
-               /* Called from VIDIOC_REQBUFS or in compatibility mode */
-               sizes[0] = icd->sizeimage;
-       }
-
        alloc_ctxs[0] = mx3_cam->alloc_ctx;
 
        if (!vq->num_buffers)
@@ -232,9 +203,14 @@ static int mx3_videobuf_setup(struct vb2_queue *vq,
        if (!*count)
                *count = 2;
 
+       /* Called from VIDIOC_REQBUFS or in compatibility mode */
+       if (!*num_planes)
+               sizes[0] = icd->sizeimage;
+       else if (sizes[0] < icd->sizeimage)
+               return -EINVAL;
+
        /* If *num_planes != 0, we have already verified *count. */
-       if (!*num_planes &&
-           sizes[0] * *count + mx3_cam->buf_total > MAX_VIDEO_MEM * 1024 * 1024)
+       if (sizes[0] * *count + mx3_cam->buf_total > MAX_VIDEO_MEM * 1024 * 1024)
                *count = (MAX_VIDEO_MEM * 1024 * 1024 - mx3_cam->buf_total) /
                        sizes[0];
 
index ba8dcd11ae0ec9f9861b7dc472b469e73decdac7..bd721e35474ab53eef8f0ea5417dc13cb2975794 100644 (file)
@@ -28,9 +28,9 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
-#include <media/omap1_camera.h>
+#include <linux/platform_data/media/omap1_camera.h>
 #include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
 #include <media/videobuf-dma-contig.h>
 #include <media/videobuf-dma-sg.h>
 
index fcb942de0c7f069d6b27e4946676f88209407511..415f3bda60bfe732ac8a40335d21c7a21f5773bb 100644 (file)
 #include <media/v4l2-dev.h>
 #include <media/videobuf-dma-sg.h>
 #include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
 #include <media/v4l2-of.h>
 
 #include <linux/videodev2.h>
 
 #include <mach/dma.h>
-#include <linux/platform_data/camera-pxa.h>
+#include <linux/platform_data/media/camera-pxa.h>
 
 #define PXA_CAM_VERSION "0.0.6"
 #define PXA_CAM_DRV_NAME "pxa27x-camera"
index efe57b23fac15ce5b9d24c1e8cbbf35673d34c50..b7fd695b9ed5187d2f8d2c356269ebe6fc1d26d4 100644 (file)
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/platform_data/camera-rcar.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 
 #include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-device.h>
 
 #define TIMEOUT_MS             100
 
+#define RCAR_VIN_HSYNC_ACTIVE_LOW      (1 << 0)
+#define RCAR_VIN_VSYNC_ACTIVE_LOW      (1 << 1)
+#define RCAR_VIN_BT601                 (1 << 2)
+#define RCAR_VIN_BT656                 (1 << 3)
+
 enum chip_id {
        RCAR_GEN2,
        RCAR_H1,
@@ -527,46 +531,14 @@ struct rcar_vin_cam {
  * required
  */
 static int rcar_vin_videobuf_setup(struct vb2_queue *vq,
-                                  const void *parg,
                                   unsigned int *count,
                                   unsigned int *num_planes,
                                   unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct rcar_vin_priv *priv = ici->priv;
 
-       if (fmt) {
-               const struct soc_camera_format_xlate *xlate;
-               unsigned int bytes_per_line;
-               int ret;
-
-               if (fmt->fmt.pix.sizeimage < icd->sizeimage)
-                       return -EINVAL;
-
-               xlate = soc_camera_xlate_by_fourcc(icd,
-                                                  fmt->fmt.pix.pixelformat);
-               if (!xlate)
-                       return -EINVAL;
-               ret = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
-                                             xlate->host_fmt);
-               if (ret < 0)
-                       return ret;
-
-               bytes_per_line = max_t(u32, fmt->fmt.pix.bytesperline, ret);
-
-               ret = soc_mbus_image_size(xlate->host_fmt, bytes_per_line,
-                                         fmt->fmt.pix.height);
-               if (ret < 0)
-                       return ret;
-
-               sizes[0] = max_t(u32, fmt->fmt.pix.sizeimage, ret);
-       } else {
-               /* Called from VIDIOC_REQBUFS or in compatibility mode */
-               sizes[0] = icd->sizeimage;
-       }
-
        alloc_ctxs[0] = priv->alloc_ctx;
 
        if (!vq->num_buffers)
@@ -576,14 +548,18 @@ static int rcar_vin_videobuf_setup(struct vb2_queue *vq,
                *count = 2;
        priv->vb_count = *count;
 
-       *num_planes = 1;
-
        /* Number of hardware slots */
        if (is_continuous_transfer(priv))
                priv->nr_hw_slots = MAX_BUFFER_NUM;
        else
                priv->nr_hw_slots = 1;
 
+       if (*num_planes)
+               return sizes[0] < icd->sizeimage ? -EINVAL : 0;
+
+       sizes[0] = icd->sizeimage;
+       *num_planes = 1;
+
        dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]);
 
        return 0;
@@ -912,7 +888,7 @@ static irqreturn_t rcar_vin_irq(int irq, void *data)
 
                priv->queue_buf[slot]->field = priv->field;
                priv->queue_buf[slot]->sequence = priv->sequence++;
-               v4l2_get_timestamp(&priv->queue_buf[slot]->timestamp);
+               priv->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns();
                vb2_buffer_done(&priv->queue_buf[slot]->vb2_buf,
                                VB2_BUF_STATE_DONE);
                priv->queue_buf[slot] = NULL;
@@ -1853,63 +1829,43 @@ static const struct of_device_id rcar_vin_of_table[] = {
 MODULE_DEVICE_TABLE(of, rcar_vin_of_table);
 #endif
 
-static struct platform_device_id rcar_vin_id_table[] = {
-       { "r8a7779-vin",  RCAR_H1 },
-       { "r8a7778-vin",  RCAR_M1 },
-       { "uPD35004-vin", RCAR_E1 },
-       {},
-};
-MODULE_DEVICE_TABLE(platform, rcar_vin_id_table);
-
 static int rcar_vin_probe(struct platform_device *pdev)
 {
        const struct of_device_id *match = NULL;
        struct rcar_vin_priv *priv;
+       struct v4l2_of_endpoint ep;
+       struct device_node *np;
        struct resource *mem;
-       struct rcar_vin_platform_data *pdata;
        unsigned int pdata_flags;
        int irq, ret;
 
-       if (pdev->dev.of_node) {
-               struct v4l2_of_endpoint ep;
-               struct device_node *np;
+       match = of_match_device(of_match_ptr(rcar_vin_of_table), &pdev->dev);
 
-               match = of_match_device(of_match_ptr(rcar_vin_of_table),
-                                       &pdev->dev);
-
-               np = of_graph_get_next_endpoint(pdev->dev.of_node, NULL);
-               if (!np) {
-                       dev_err(&pdev->dev, "could not find endpoint\n");
-                       return -EINVAL;
-               }
+       np = of_graph_get_next_endpoint(pdev->dev.of_node, NULL);
+       if (!np) {
+               dev_err(&pdev->dev, "could not find endpoint\n");
+               return -EINVAL;
+       }
 
-               ret = v4l2_of_parse_endpoint(np, &ep);
-               if (ret) {
-                       dev_err(&pdev->dev, "could not parse endpoint\n");
-                       return ret;
-               }
+       ret = v4l2_of_parse_endpoint(np, &ep);
+       if (ret) {
+               dev_err(&pdev->dev, "could not parse endpoint\n");
+               return ret;
+       }
 
-               if (ep.bus_type == V4L2_MBUS_BT656)
-                       pdata_flags = RCAR_VIN_BT656;
-               else {
-                       pdata_flags = 0;
-                       if (ep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
-                               pdata_flags |= RCAR_VIN_HSYNC_ACTIVE_LOW;
-                       if (ep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
-                               pdata_flags |= RCAR_VIN_VSYNC_ACTIVE_LOW;
-               }
+       if (ep.bus_type == V4L2_MBUS_BT656)
+               pdata_flags = RCAR_VIN_BT656;
+       else {
+               pdata_flags = 0;
+               if (ep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+                       pdata_flags |= RCAR_VIN_HSYNC_ACTIVE_LOW;
+               if (ep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+                       pdata_flags |= RCAR_VIN_VSYNC_ACTIVE_LOW;
+       }
 
-               of_node_put(np);
+       of_node_put(np);
 
-               dev_dbg(&pdev->dev, "pdata_flags = %08x\n", pdata_flags);
-       } else {
-               pdata = pdev->dev.platform_data;
-               if (!pdata || !pdata->flags) {
-                       dev_err(&pdev->dev, "platform data not set\n");
-                       return -EINVAL;
-               }
-               pdata_flags = pdata->flags;
-       }
+       dev_dbg(&pdev->dev, "pdata_flags = %08x\n", pdata_flags);
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (mem == NULL)
@@ -1992,7 +1948,6 @@ static struct platform_driver rcar_vin_driver = {
                .name           = DRV_NAME,
                .of_match_table = of_match_ptr(rcar_vin_of_table),
        },
-       .id_table       = rcar_vin_id_table,
 };
 
 module_platform_driver(rcar_vin_driver);
index 67a669d826b809aade01b988d29fcf7b4efd9f2f..90c87f2b4ec075bbe96ee15201494f3dcc757753 100644 (file)
 #include <media/v4l2-common.h>
 #include <media/v4l2-dev.h>
 #include <media/soc_camera.h>
-#include <media/sh_mobile_ceu.h>
-#include <media/sh_mobile_csi2.h>
+#include <media/drv-intf/sh_mobile_ceu.h>
+#include <media/drv-intf/sh_mobile_csi2.h>
 #include <media/videobuf2-dma-contig.h>
 #include <media/v4l2-mediabus.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
 
 #include "soc_scale_crop.h"
 
@@ -210,43 +210,14 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev)
  *               for the current frame format if required
  */
 static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
-                       const void *parg,
                        unsigned int *count, unsigned int *num_planes,
                        unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct soc_camera_device *icd = container_of(vq,
                        struct soc_camera_device, vb2_vidq);
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
 
-       if (fmt) {
-               const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd,
-                                                               fmt->fmt.pix.pixelformat);
-               unsigned int bytes_per_line;
-               int ret;
-
-               if (!xlate)
-                       return -EINVAL;
-
-               ret = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
-                                             xlate->host_fmt);
-               if (ret < 0)
-                       return ret;
-
-               bytes_per_line = max_t(u32, fmt->fmt.pix.bytesperline, ret);
-
-               ret = soc_mbus_image_size(xlate->host_fmt, bytes_per_line,
-                                         fmt->fmt.pix.height);
-               if (ret < 0)
-                       return ret;
-
-               sizes[0] = max_t(u32, fmt->fmt.pix.sizeimage, ret);
-       } else {
-               /* Called from VIDIOC_REQBUFS or in compatibility mode */
-               sizes[0] = icd->sizeimage;
-       }
-
        alloc_ctxs[0] = pcdev->alloc_ctx;
 
        if (!vq->num_buffers)
@@ -255,8 +226,14 @@ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
        if (!*count)
                *count = 2;
 
+       /* Called from VIDIOC_REQBUFS or in compatibility mode */
+       if (!*num_planes)
+               sizes[0] = icd->sizeimage;
+       else if (sizes[0] < icd->sizeimage)
+               return -EINVAL;
+
        /* If *num_planes != 0, we have already verified *count. */
-       if (pcdev->video_limit && !*num_planes) {
+       if (pcdev->video_limit) {
                size_t size = PAGE_ALIGN(sizes[0]) * *count;
 
                if (size + pcdev->buf_total > pcdev->video_limit)
@@ -533,7 +510,7 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
                pcdev->active = NULL;
 
        ret = sh_mobile_ceu_capture(pcdev);
-       v4l2_get_timestamp(&vbuf->timestamp);
+       vbuf->vb2_buf.timestamp = ktime_get_ns();
        if (!ret) {
                vbuf->field = pcdev->field;
                vbuf->sequence = pcdev->sequence++;
index 12d3626ecf2221c870cdfce8867aa92f6cd31881..09b18365a4b1cff55a71523dc5b152cd5bd199cc 100644 (file)
 #include <linux/videodev2.h>
 #include <linux/module.h>
 
-#include <media/sh_mobile_ceu.h>
-#include <media/sh_mobile_csi2.h>
+#include <media/drv-intf/sh_mobile_ceu.h>
+#include <media/drv-intf/sh_mobile_csi2.h>
 #include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-device.h>
index dc98122e78dc503a8a0c02d3fdcd03f3093c093e..cc84c6d6a701ce249722010ed514c1e4a4630def 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/vmalloc.h>
 
 #include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
 #include <media/v4l2-async.h>
 #include <media/v4l2-clk.h>
 #include <media/v4l2-common.h>
@@ -1360,7 +1360,7 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd,
        struct soc_camera_host_desc *shd = &sdesc->host_desc;
        struct i2c_adapter *adap;
        struct v4l2_subdev *subdev;
-       char clk_name[V4L2_SUBDEV_NAME_SIZE];
+       char clk_name[V4L2_CLK_NAME_SIZE];
        int ret;
 
        /* First find out how we link the main client */
@@ -1391,8 +1391,8 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd,
        ssdd->sd_pdata.regulators = NULL;
        shd->board_info->platform_data = ssdd;
 
-       snprintf(clk_name, sizeof(clk_name), "%d-%04x",
-                shd->i2c_adapter_id, shd->board_info->addr);
+       v4l2_clk_name_i2c(clk_name, sizeof(clk_name),
+                         shd->i2c_adapter_id, shd->board_info->addr);
 
        icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd);
        if (IS_ERR(icd->clk)) {
@@ -1526,7 +1526,7 @@ static int scan_async_group(struct soc_camera_host *ici,
        struct soc_camera_async_client *sasc;
        struct soc_camera_device *icd;
        struct soc_camera_desc sdesc = {.host_desc.bus_id = ici->nr,};
-       char clk_name[V4L2_SUBDEV_NAME_SIZE];
+       char clk_name[V4L2_CLK_NAME_SIZE];
        unsigned int i;
        int ret;
 
@@ -1572,8 +1572,9 @@ static int scan_async_group(struct soc_camera_host *ici,
        icd->sasc = sasc;
        icd->parent = ici->v4l2_dev.dev;
 
-       snprintf(clk_name, sizeof(clk_name), "%d-%04x",
-                sasd->asd.match.i2c.adapter_id, sasd->asd.match.i2c.address);
+       v4l2_clk_name_i2c(clk_name, sizeof(clk_name),
+                         sasd->asd.match.i2c.adapter_id,
+                         sasd->asd.match.i2c.address);
 
        icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd);
        if (IS_ERR(icd->clk)) {
@@ -1631,7 +1632,7 @@ static int soc_of_bind(struct soc_camera_host *ici,
        struct soc_camera_async_client *sasc;
        struct soc_of_info *info;
        struct i2c_client *client;
-       char clk_name[V4L2_SUBDEV_NAME_SIZE + 32];
+       char clk_name[V4L2_CLK_NAME_SIZE];
        int ret;
 
        /* allocate a new subdev and add match info to it */
@@ -1674,11 +1675,11 @@ static int soc_of_bind(struct soc_camera_host *ici,
        client = of_find_i2c_device_by_node(remote);
 
        if (client)
-               snprintf(clk_name, sizeof(clk_name), "%d-%04x",
-                        client->adapter->nr, client->addr);
+               v4l2_clk_name_i2c(clk_name, sizeof(clk_name),
+                                 client->adapter->nr, client->addr);
        else
-               snprintf(clk_name, sizeof(clk_name), "of-%s",
-                        of_node_full_name(remote));
+               v4l2_clk_name_of(clk_name, sizeof(clk_name),
+                                of_node_full_name(remote));
 
        icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd);
        if (IS_ERR(icd->clk)) {
index cc8eb07582193a7777242a6f3d2c7e1bfd8f3b84..a51d2a42998c5797b2b4bb25a6944ee8bcf6c1e2 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-subdev.h>
 #include <media/soc_camera.h>
-#include <media/soc_camera_platform.h>
+#include <linux/platform_data/media/soc_camera_platform.h>
 
 struct soc_camera_platform_priv {
        struct v4l2_subdev subdev;
index 1dbcd426683ccececd101e441312a98464617269..e3e665e1c503afca118c2f7c874c1c2f626360e7 100644 (file)
@@ -13,7 +13,7 @@
 
 #include <media/v4l2-device.h>
 #include <media/v4l2-mediabus.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
 
 static const struct soc_mbus_lookup mbus_fmt[] = {
 {
index a0d267e017f61cfd224e20a49a7f61ff11dbfe57..d12a419c044a16a96991a26324a60078b34f3037 100644 (file)
@@ -191,7 +191,7 @@ static void bdisp_job_finish(struct bdisp_ctx *ctx, int vb_state)
        dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
 
        if (src_vb && dst_vb) {
-               dst_vb->timestamp = src_vb->timestamp;
+               dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
                dst_vb->timecode = src_vb->timecode;
                dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
                dst_vb->flags |= src_vb->flags &
@@ -297,7 +297,7 @@ static int bdisp_get_bufs(struct bdisp_ctx *ctx)
        if (ret)
                return ret;
 
-       dst_vb->timestamp = src_vb->timestamp;
+       dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
 
        return 0;
 }
@@ -438,11 +438,9 @@ static void bdisp_ctrls_delete(struct bdisp_ctx *ctx)
 }
 
 static int bdisp_queue_setup(struct vb2_queue *vq,
-                            const void *parg,
                             unsigned int *nb_buf, unsigned int *nb_planes,
                             unsigned int sizes[], void *allocators[])
 {
-       const struct v4l2_format *fmt = parg;
        struct bdisp_ctx *ctx = vb2_get_drv_priv(vq);
        struct bdisp_frame *frame = ctx_get_frame(ctx, vq->type);
 
@@ -455,13 +453,13 @@ static int bdisp_queue_setup(struct vb2_queue *vq,
                dev_err(ctx->bdisp_dev->dev, "Invalid format\n");
                return -EINVAL;
        }
+       allocators[0] = ctx->bdisp_dev->alloc_ctx;
 
-       if (fmt && fmt->fmt.pix.sizeimage < frame->sizeimage)
-               return -EINVAL;
+       if (*nb_planes)
+               return sizes[0] < frame->sizeimage ? -EINVAL : 0;
 
        *nb_planes = 1;
-       sizes[0] = fmt ? fmt->fmt.pix.sizeimage : frame->sizeimage;
-       allocators[0] = ctx->bdisp_dev->alloc_ctx;
+       sizes[0] = frame->sizeimage;
 
        return 0;
 }
index 95223ab71e1971b05e72ac9686e75a2c2aab7425..2dfbe8ab521435cc0d54915feb40e012ed2d8caf 100644 (file)
@@ -209,18 +209,18 @@ void c8sectpfe_tuner_unregister_frontend(struct c8sectpfe *c8sectpfe,
 
                tsin = fei->channel_data[n];
 
-               if (tsin && tsin->frontend) {
-                       dvb_unregister_frontend(tsin->frontend);
-                       dvb_frontend_detach(tsin->frontend);
-               }
+               if (tsin) {
+                       if (tsin->frontend) {
+                               dvb_unregister_frontend(tsin->frontend);
+                               dvb_frontend_detach(tsin->frontend);
+                       }
 
-               if (tsin && tsin->i2c_adapter)
                        i2c_put_adapter(tsin->i2c_adapter);
 
-               if (tsin && tsin->i2c_client) {
-                       if (tsin->i2c_client->dev.driver->owner)
+                       if (tsin->i2c_client) {
                                module_put(tsin->i2c_client->dev.driver->owner);
-                       i2c_unregister_device(tsin->i2c_client);
+                               i2c_unregister_device(tsin->i2c_client);
+                       }
                }
        }
 
index 8490a65ae1c6703a3e14ff57dfc792c9d354fad5..78e3cb9a628f2258a6bb4ceb75f8068c2e0799ae 100644 (file)
@@ -823,7 +823,7 @@ static int c8sectpfe_probe(struct platform_device *pdev)
                }
                of_node_put(i2c_bus);
 
-               tsin->rst_gpio = of_get_named_gpio(child, "rst-gpio", 0);
+               tsin->rst_gpio = of_get_named_gpio(child, "reset-gpios", 0);
 
                ret = gpio_is_valid(tsin->rst_gpio);
                if (!ret) {
index de24effd984fb3a360e269d31c483bf269f4e2b2..1fa00c2cf3d798d4f3a41aceae4a80ce0b8650da 100644 (file)
@@ -1288,7 +1288,7 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data)
        d_vb = ctx->dst_vb;
 
        d_vb->flags = s_vb->flags;
-       d_vb->timestamp = s_vb->timestamp;
+       d_vb->vb2_buf.timestamp = s_vb->vb2_buf.timestamp;
 
        if (s_vb->flags & V4L2_BUF_FLAG_TIMECODE)
                d_vb->timecode = s_vb->timecode;
@@ -1796,7 +1796,6 @@ static const struct v4l2_ioctl_ops vpe_ioctl_ops = {
  * Queue operations
  */
 static int vpe_queue_setup(struct vb2_queue *vq,
-                          const void *parg,
                           unsigned int *nbuffers, unsigned int *nplanes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
index 5820e45b3a9f9d38de2d48dbd15ce2b2d778be66..113c9f3c0b3eba57fa2328a473c395696e9492fa 100644 (file)
@@ -31,7 +31,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
 #include <media/videobuf-dma-contig.h>
-#include <media/timb_video.h>
+#include <linux/platform_data/media/timb_video.h>
 
 #define DRIVER_NAME                    "timb-video"
 
index 32e4ff46daf336a35f1dae867a8ec6075acb4e60..1254f7e4d73217b81681cb41a81571f60fa76eb2 100644 (file)
@@ -19,7 +19,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-image-sizes.h>
-#include <media/ov7670.h>
+#include <media/i2c/ov7670.h>
 #include <media/videobuf-dma-sg.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
index e18fb9f9ed2f7795414f79deed1c19f6cf334374..418113c998013d5fabc083364b662dc17d259e79 100644 (file)
@@ -235,7 +235,7 @@ static int device_process(struct vim2m_ctx *ctx,
        out_vb->sequence =
                get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE)->sequence++;
        in_vb->sequence = q_data->sequence++;
-       out_vb->timestamp = in_vb->timestamp;
+       out_vb->vb2_buf.timestamp = in_vb->vb2_buf.timestamp;
 
        if (in_vb->flags & V4L2_BUF_FLAG_TIMECODE)
                out_vb->timecode = in_vb->timecode;
@@ -710,11 +710,9 @@ static const struct v4l2_ioctl_ops vim2m_ioctl_ops = {
  */
 
 static int vim2m_queue_setup(struct vb2_queue *vq,
-                               const void *parg,
                                unsigned int *nbuffers, unsigned int *nplanes,
                                unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct vim2m_ctx *ctx = vb2_get_drv_priv(vq);
        struct vim2m_q_data *q_data;
        unsigned int size, count = *nbuffers;
@@ -723,17 +721,14 @@ static int vim2m_queue_setup(struct vb2_queue *vq,
 
        size = q_data->width * q_data->height * q_data->fmt->depth >> 3;
 
-       if (fmt) {
-               if (fmt->fmt.pix.sizeimage < size)
-                       return -EINVAL;
-               size = fmt->fmt.pix.sizeimage;
-       }
-
        while (size * count > MEM2MEM_VID_MEM_LIMIT)
                (count)--;
+       *nbuffers = count;
+
+       if (*nplanes)
+               return sizes[0] < size ? -EINVAL : 0;
 
        *nplanes = 1;
-       *nbuffers = count;
        sizes[0] = size;
 
        /*
index 55b304a705d52b137d8a4521cdfaf29e4ce6929d..751c1ba391e99f735f50dea3f1a8eb017ec8209b 100644 (file)
@@ -264,6 +264,7 @@ struct vivid_dev {
        bool                            vflip;
        bool                            vbi_cap_interlaced;
        bool                            loop_video;
+       bool                            reduced_fps;
 
        /* Framebuffer */
        unsigned long                   video_pbase;
@@ -285,7 +286,7 @@ struct vivid_dev {
        bool                            dqbuf_error;
        bool                            seq_wrap;
        bool                            time_wrap;
-       __kernel_time_t                 time_wrap_offset;
+       u64                             time_wrap_offset;
        unsigned                        perc_dropped_buffers;
        enum vivid_signal_mode          std_signal_mode;
        unsigned                        query_std_last;
index f41ac0b01fecbd8b8a860531ef55ce732629aabc..b98089c95ef52ff73d8a8a8ae50329e419fb6f3c 100644 (file)
@@ -78,6 +78,7 @@
 #define VIVID_CID_TIME_WRAP            (VIVID_CID_VIVID_BASE + 39)
 #define VIVID_CID_MAX_EDID_BLOCKS      (VIVID_CID_VIVID_BASE + 40)
 #define VIVID_CID_PERCENTAGE_FILL      (VIVID_CID_VIVID_BASE + 41)
+#define VIVID_CID_REDUCED_FPS          (VIVID_CID_VIVID_BASE + 42)
 
 #define VIVID_CID_STD_SIGNAL_MODE      (VIVID_CID_VIVID_BASE + 60)
 #define VIVID_CID_STANDARD             (VIVID_CID_VIVID_BASE + 61)
@@ -424,6 +425,10 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
                dev->sensor_vflip = ctrl->val;
                tpg_s_vflip(&dev->tpg, dev->sensor_vflip ^ dev->vflip);
                break;
+       case VIVID_CID_REDUCED_FPS:
+               dev->reduced_fps = ctrl->val;
+               vivid_update_format_cap(dev, true);
+               break;
        case VIVID_CID_HAS_CROP_CAP:
                dev->has_crop_cap = ctrl->val;
                vivid_update_format_cap(dev, true);
@@ -601,6 +606,15 @@ static const struct v4l2_ctrl_config vivid_ctrl_vflip = {
        .step = 1,
 };
 
+static const struct v4l2_ctrl_config vivid_ctrl_reduced_fps = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_REDUCED_FPS,
+       .name = "Reduced Framerate",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
 static const struct v4l2_ctrl_config vivid_ctrl_has_crop_cap = {
        .ops = &vivid_vid_cap_ctrl_ops,
        .id = VIVID_CID_HAS_CROP_CAP,
@@ -940,7 +954,7 @@ static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_out = {
 static int vivid_streaming_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_streaming);
-       struct timeval tv;
+       u64 rem;
 
        switch (ctrl->id) {
        case VIVID_CID_DQBUF_ERROR:
@@ -979,8 +993,16 @@ static int vivid_streaming_s_ctrl(struct v4l2_ctrl *ctrl)
                        dev->time_wrap_offset = 0;
                        break;
                }
-               v4l2_get_timestamp(&tv);
-               dev->time_wrap_offset = -tv.tv_sec - 16;
+               /*
+                * We want to set the time 16 seconds before the 32 bit tv_sec
+                * value of struct timeval would wrap around. So first we
+                * calculate ktime_get_ns() % ((1 << 32) * NSEC_PER_SEC), and
+                * then we set the offset to ((1 << 32) - 16) * NSEC_PER_SEC).
+                */
+               div64_u64_rem(ktime_get_ns(),
+                       0x100000000ULL * NSEC_PER_SEC, &rem);
+               dev->time_wrap_offset =
+                       (0x100000000ULL - 16) * NSEC_PER_SEC - rem;
                break;
        }
        return 0;
@@ -1340,11 +1362,13 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
        v4l2_ctrl_handler_init(hdl_vid_cap, 55);
        v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_class, NULL);
        v4l2_ctrl_handler_init(hdl_vid_out, 26);
-       v4l2_ctrl_new_custom(hdl_vid_out, &vivid_ctrl_class, NULL);
+       if (!no_error_inj)
+               v4l2_ctrl_new_custom(hdl_vid_out, &vivid_ctrl_class, NULL);
        v4l2_ctrl_handler_init(hdl_vbi_cap, 21);
        v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_class, NULL);
        v4l2_ctrl_handler_init(hdl_vbi_out, 19);
-       v4l2_ctrl_new_custom(hdl_vbi_out, &vivid_ctrl_class, NULL);
+       if (!no_error_inj)
+               v4l2_ctrl_new_custom(hdl_vbi_out, &vivid_ctrl_class, NULL);
        v4l2_ctrl_handler_init(hdl_radio_rx, 17);
        v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_class, NULL);
        v4l2_ctrl_handler_init(hdl_radio_tx, 17);
@@ -1414,6 +1438,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
                v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_vflip, NULL);
                v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_sav, NULL);
                v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_eav, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_reduced_fps, NULL);
                if (show_ccs_cap) {
                        dev->ctrl_has_crop_cap = v4l2_ctrl_new_custom(hdl_vid_cap,
                                &vivid_ctrl_has_crop_cap, NULL);
index 83cc6d3b47841261c0a9663ea62680d34b538fca..9034281944a4c6f2d149bee922564894837c6c30 100644 (file)
@@ -441,7 +441,7 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
         * "Start of Exposure".
         */
        if (dev->tstamp_src_is_soe)
-               v4l2_get_timestamp(&buf->vb.timestamp);
+               buf->vb.vb2_buf.timestamp = ktime_get_ns();
        if (dev->field_cap == V4L2_FIELD_ALTERNATE) {
                /*
                 * 60 Hz standards start with the bottom field, 50 Hz standards
@@ -558,8 +558,8 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
         * the timestamp now.
         */
        if (!dev->tstamp_src_is_soe)
-               v4l2_get_timestamp(&buf->vb.timestamp);
-       buf->vb.timestamp.tv_sec += dev->time_wrap_offset;
+               buf->vb.vb2_buf.timestamp = ktime_get_ns();
+       buf->vb.vb2_buf.timestamp += dev->time_wrap_offset;
 }
 
 /*
index c2c46dcdbe95acb3b79c02004d7d38594c4d18a3..98eed5889bc17e96243a23b4e215460ff89169af 100644 (file)
@@ -95,8 +95,8 @@ static void vivid_thread_vid_out_tick(struct vivid_dev *dev)
                         */
                        vid_out_buf->vb.sequence /= 2;
                }
-               v4l2_get_timestamp(&vid_out_buf->vb.timestamp);
-               vid_out_buf->vb.timestamp.tv_sec += dev->time_wrap_offset;
+               vid_out_buf->vb.vb2_buf.timestamp =
+                       ktime_get_ns() + dev->time_wrap_offset;
                vb2_buffer_done(&vid_out_buf->vb.vb2_buf, dev->dqbuf_error ?
                                VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
                dprintk(dev, 2, "vid_out buffer %d done\n",
@@ -108,8 +108,8 @@ static void vivid_thread_vid_out_tick(struct vivid_dev *dev)
                        vivid_sliced_vbi_out_process(dev, vbi_out_buf);
 
                vbi_out_buf->vb.sequence = dev->vbi_out_seq_count;
-               v4l2_get_timestamp(&vbi_out_buf->vb.timestamp);
-               vbi_out_buf->vb.timestamp.tv_sec += dev->time_wrap_offset;
+               vbi_out_buf->vb.vb2_buf.timestamp =
+                       ktime_get_ns() + dev->time_wrap_offset;
                vb2_buffer_done(&vbi_out_buf->vb.vb2_buf, dev->dqbuf_error ?
                                VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
                dprintk(dev, 2, "vbi_out buffer %d done\n",
index 082c401764ce8ed359df38708d69ee5c649edbf4..3d1604cb982f2cf525933c6d3dde8dc22fcf16f7 100644 (file)
@@ -117,8 +117,8 @@ static void vivid_thread_sdr_cap_tick(struct vivid_dev *dev)
        if (sdr_cap_buf) {
                sdr_cap_buf->vb.sequence = dev->sdr_cap_seq_count;
                vivid_sdr_cap_process(dev, sdr_cap_buf);
-               v4l2_get_timestamp(&sdr_cap_buf->vb.timestamp);
-               sdr_cap_buf->vb.timestamp.tv_sec += dev->time_wrap_offset;
+               sdr_cap_buf->vb.vb2_buf.timestamp =
+                       ktime_get_ns() + dev->time_wrap_offset;
                vb2_buffer_done(&sdr_cap_buf->vb.vb2_buf, dev->dqbuf_error ?
                                VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
                dev->dqbuf_error = false;
@@ -213,7 +213,7 @@ static int vivid_thread_sdr_cap(void *data)
        return 0;
 }
 
-static int sdr_cap_queue_setup(struct vb2_queue *vq, const void *parg,
+static int sdr_cap_queue_setup(struct vb2_queue *vq,
                       unsigned *nbuffers, unsigned *nplanes,
                       unsigned sizes[], void *alloc_ctxs[])
 {
index e903d023e9dfa941c1c627bb683138d6b259b46e..cda45a582bfef3756766df64cb6c0a6e3cbeb242 100644 (file)
@@ -108,8 +108,7 @@ void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf)
        if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode))
                vivid_vbi_gen_raw(&dev->vbi_gen, &vbi, vbuf);
 
-       v4l2_get_timestamp(&buf->vb.timestamp);
-       buf->vb.timestamp.tv_sec += dev->time_wrap_offset;
+       buf->vb.vb2_buf.timestamp = ktime_get_ns() + dev->time_wrap_offset;
 }
 
 
@@ -133,11 +132,10 @@ void vivid_sliced_vbi_cap_process(struct vivid_dev *dev,
                        vbuf[i] = dev->vbi_gen.data[i];
        }
 
-       v4l2_get_timestamp(&buf->vb.timestamp);
-       buf->vb.timestamp.tv_sec += dev->time_wrap_offset;
+       buf->vb.vb2_buf.timestamp = ktime_get_ns() + dev->time_wrap_offset;
 }
 
-static int vbi_cap_queue_setup(struct vb2_queue *vq, const void *parg,
+static int vbi_cap_queue_setup(struct vb2_queue *vq,
                       unsigned *nbuffers, unsigned *nplanes,
                       unsigned sizes[], void *alloc_ctxs[])
 {
index 75c5709f938e989d57d449041c182d2813500533..3c5a469e6f49799faf846647e059d8d8c46cacbd 100644 (file)
@@ -27,7 +27,7 @@
 #include "vivid-vbi-out.h"
 #include "vivid-vbi-cap.h"
 
-static int vbi_out_queue_setup(struct vb2_queue *vq, const void *parg,
+static int vbi_out_queue_setup(struct vb2_queue *vq,
                       unsigned *nbuffers, unsigned *nplanes,
                       unsigned sizes[], void *alloc_ctxs[])
 {
index ef5412311b2fa057a9dc96f5f0f620ddfaa9f0ce..b84f081c1b929b9e89d577fbdf585c30e836d34a 100644 (file)
@@ -95,11 +95,10 @@ static const struct v4l2_discrete_probe webcam_probe = {
        VIVID_WEBCAM_SIZES
 };
 
-static int vid_cap_queue_setup(struct vb2_queue *vq, const void *parg,
+static int vid_cap_queue_setup(struct vb2_queue *vq,
                       unsigned *nbuffers, unsigned *nplanes,
                       unsigned sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct vivid_dev *dev = vb2_get_drv_priv(vq);
        unsigned buffers = tpg_g_buffers(&dev->tpg);
        unsigned h = dev->fmt_cap_rect.height;
@@ -122,27 +121,16 @@ static int vid_cap_queue_setup(struct vb2_queue *vq, const void *parg,
                dev->queue_setup_error = false;
                return -EINVAL;
        }
-       if (fmt) {
-               const struct v4l2_pix_format_mplane *mp;
-               struct v4l2_format mp_fmt;
-               const struct vivid_fmt *vfmt;
-
-               if (!V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
-                       fmt_sp2mp(fmt, &mp_fmt);
-                       fmt = &mp_fmt;
-               }
-               mp = &fmt->fmt.pix_mp;
+       if (*nplanes) {
                /*
-                * Check if the number of planes in the specified format match
+                * Check if the number of requested planes match
                 * the number of buffers in the current format. You can't mix that.
                 */
-               if (mp->num_planes != buffers)
+               if (*nplanes != buffers)
                        return -EINVAL;
-               vfmt = vivid_get_format(dev, mp->pixelformat);
                for (p = 0; p < buffers; p++) {
-                       sizes[p] = mp->plane_fmt[p].sizeimage;
                        if (sizes[p] < tpg_g_line_width(&dev->tpg, p) * h +
-                                                       vfmt->data_offset[p])
+                                               dev->fmt_cap->data_offset[p])
                                return -EINVAL;
                }
        } else {
@@ -405,6 +393,7 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls)
 {
        struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt;
        unsigned size;
+       u64 pixelclock;
 
        switch (dev->input_type[dev->input]) {
        case WEBCAM:
@@ -434,8 +423,15 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls)
                dev->src_rect.width = bt->width;
                dev->src_rect.height = bt->height;
                size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt);
+               if (dev->reduced_fps && can_reduce_fps(bt)) {
+                       pixelclock = div_u64(bt->pixelclock * 1000, 1001);
+                       bt->flags |= V4L2_DV_FL_REDUCED_FPS;
+               } else {
+                       pixelclock = bt->pixelclock;
+                       bt->flags &= ~V4L2_DV_FL_REDUCED_FPS;
+               }
                dev->timeperframe_vid_cap = (struct v4l2_fract) {
-                       size / 100, (u32)bt->pixelclock / 100
+                       size / 100, (u32)pixelclock / 100
                };
                if (bt->interlaced)
                        dev->field_cap = V4L2_FIELD_ALTERNATE;
@@ -1662,7 +1658,7 @@ int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh,
            !valid_cvt_gtf_timings(timings))
                return -EINVAL;
 
-       if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0))
+       if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0, false))
                return 0;
        if (vb2_is_busy(&dev->vb_vid_cap_q))
                return -EBUSY;
index b77acb6a70138a4f093c783f73e0b4dae8ddddad..64e4d66482c1f35e42a1739c6bb56824108fb5c3 100644 (file)
 #include "vivid-kthread-out.h"
 #include "vivid-vid-out.h"
 
-static int vid_out_queue_setup(struct vb2_queue *vq, const void *parg,
+static int vid_out_queue_setup(struct vb2_queue *vq,
                       unsigned *nbuffers, unsigned *nplanes,
                       unsigned sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct vivid_dev *dev = vb2_get_drv_priv(vq);
        const struct vivid_fmt *vfmt = dev->fmt_out;
        unsigned planes = vfmt->buffers;
@@ -64,26 +63,16 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const void *parg,
                return -EINVAL;
        }
 
-       if (fmt) {
-               const struct v4l2_pix_format_mplane *mp;
-               struct v4l2_format mp_fmt;
-
-               if (!V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
-                       fmt_sp2mp(fmt, &mp_fmt);
-                       fmt = &mp_fmt;
-               }
-               mp = &fmt->fmt.pix_mp;
+       if (*nplanes) {
                /*
-                * Check if the number of planes in the specified format match
+                * Check if the number of requested planes match
                 * the number of planes in the current format. You can't mix that.
                 */
-               if (mp->num_planes != planes)
+               if (*nplanes != planes)
                        return -EINVAL;
-               sizes[0] = mp->plane_fmt[0].sizeimage;
                if (sizes[0] < size)
                        return -EINVAL;
                for (p = 1; p < planes; p++) {
-                       sizes[p] = mp->plane_fmt[p].sizeimage;
                        if (sizes[p] < dev->bytesperline_out[p] * h)
                                return -EINVAL;
                }
@@ -224,6 +213,7 @@ void vivid_update_format_out(struct vivid_dev *dev)
 {
        struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt;
        unsigned size, p;
+       u64 pixelclock;
 
        switch (dev->output_type[dev->output]) {
        case SVID:
@@ -245,8 +235,14 @@ void vivid_update_format_out(struct vivid_dev *dev)
                dev->sink_rect.width = bt->width;
                dev->sink_rect.height = bt->height;
                size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt);
+
+               if (can_reduce_fps(bt) && (bt->flags & V4L2_DV_FL_REDUCED_FPS))
+                       pixelclock = div_u64(bt->pixelclock * 1000, 1001);
+               else
+                       pixelclock = bt->pixelclock;
+
                dev->timeperframe_vid_out = (struct v4l2_fract) {
-                       size / 100, (u32)bt->pixelclock / 100
+                       size / 100, (u32)pixelclock / 100
                };
                if (bt->interlaced)
                        dev->field_out = V4L2_FIELD_ALTERNATE;
@@ -1149,7 +1145,7 @@ int vivid_vid_out_s_dv_timings(struct file *file, void *_fh,
                                0, NULL, NULL) &&
            !valid_cvt_gtf_timings(timings))
                return -EINVAL;
-       if (v4l2_match_dv_timings(timings, &dev->dv_timings_out, 0))
+       if (v4l2_match_dv_timings(timings, &dev->dv_timings_out, 0, true))
                return 0;
        if (vb2_is_busy(&dev->vb_vid_out_q))
                return -EBUSY;
index 5ce88e1f5d710cea2e8fab573019750b20a7df1f..45eb65fa23dbbc20b05f82c05948541c39ad0996 100644 (file)
@@ -274,35 +274,6 @@ static int __vsp1_video_try_format(struct vsp1_video *video,
        return 0;
 }
 
-static bool
-vsp1_video_format_adjust(struct vsp1_video *video,
-                        const struct v4l2_pix_format_mplane *format,
-                        struct v4l2_pix_format_mplane *adjust)
-{
-       unsigned int i;
-
-       *adjust = *format;
-       __vsp1_video_try_format(video, adjust, NULL);
-
-       if (format->width != adjust->width ||
-           format->height != adjust->height ||
-           format->pixelformat != adjust->pixelformat ||
-           format->num_planes != adjust->num_planes)
-               return false;
-
-       for (i = 0; i < format->num_planes; ++i) {
-               if (format->plane_fmt[i].bytesperline !=
-                   adjust->plane_fmt[i].bytesperline)
-                       return false;
-
-               adjust->plane_fmt[i].sizeimage =
-                       max(adjust->plane_fmt[i].sizeimage,
-                           format->plane_fmt[i].sizeimage);
-       }
-
-       return true;
-}
-
 /* -----------------------------------------------------------------------------
  * Pipeline Management
  */
@@ -611,7 +582,7 @@ vsp1_video_complete_buffer(struct vsp1_video *video)
        spin_unlock_irqrestore(&video->irqlock, flags);
 
        done->buf.sequence = video->sequence++;
-       v4l2_get_timestamp(&done->buf.timestamp);
+       done->buf.vb2_buf.timestamp = ktime_get_ns();
        for (i = 0; i < done->buf.vb2_buf.num_planes; ++i)
                vb2_set_plane_payload(&done->buf.vb2_buf, i, done->length[i]);
        vb2_buffer_done(&done->buf.vb2_buf, VB2_BUF_STATE_DONE);
@@ -787,26 +758,24 @@ void vsp1_pipelines_resume(struct vsp1_device *vsp1)
  */
 
 static int
-vsp1_video_queue_setup(struct vb2_queue *vq, const void *parg,
+vsp1_video_queue_setup(struct vb2_queue *vq,
                     unsigned int *nbuffers, unsigned int *nplanes,
                     unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct vsp1_video *video = vb2_get_drv_priv(vq);
-       const struct v4l2_pix_format_mplane *format;
-       struct v4l2_pix_format_mplane pix_mp;
+       const struct v4l2_pix_format_mplane *format = &video->format;
        unsigned int i;
 
-       if (fmt) {
-               /* Make sure the format is valid and adjust the sizeimage field
-                * if needed.
-                */
-               if (!vsp1_video_format_adjust(video, &fmt->fmt.pix_mp, &pix_mp))
+       if (*nplanes) {
+               if (*nplanes != format->num_planes)
                        return -EINVAL;
 
-               format = &pix_mp;
-       } else {
-               format = &video->format;
+               for (i = 0; i < *nplanes; i++) {
+                       if (sizes[i] < format->plane_fmt[i].sizeimage)
+                               return -EINVAL;
+                       alloc_ctxs[i] = video->alloc_ctx;
+               }
+               return 0;
        }
 
        *nplanes = format->num_planes;
index d11cc7072cd59d2c873dfe68863676b1e8731f42..722758f3392412ccc41f83ef4a221961bdd93ef5 100644 (file)
@@ -303,27 +303,25 @@ static void xvip_dma_complete(void *param)
 
        buf->buf.field = V4L2_FIELD_NONE;
        buf->buf.sequence = dma->sequence++;
-       v4l2_get_timestamp(&buf->buf.timestamp);
+       buf->buf.vb2_buf.timestamp = ktime_get_ns();
        vb2_set_plane_payload(&buf->buf.vb2_buf, 0, dma->format.sizeimage);
        vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE);
 }
 
 static int
-xvip_dma_queue_setup(struct vb2_queue *vq, const void *parg,
+xvip_dma_queue_setup(struct vb2_queue *vq,
                     unsigned int *nbuffers, unsigned int *nplanes,
                     unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct xvip_dma *dma = vb2_get_drv_priv(vq);
 
+       alloc_ctxs[0] = dma->alloc_ctx;
        /* Make sure the image size is large enough. */
-       if (fmt && fmt->fmt.pix.sizeimage < dma->format.sizeimage)
-               return -EINVAL;
+       if (*nplanes)
+               return sizes[0] < dma->format.sizeimage ? -EINVAL : 0;
 
        *nplanes = 1;
-
-       sizes[0] = fmt ? fmt->fmt.pix.sizeimage : dma->format.sizeimage;
-       alloc_ctxs[0] = dma->alloc_ctx;
+       sizes[0] = dma->format.sizeimage;
 
        return 0;
 }
index b5f7d5ecb7f68fbabeb8fde1ed9439f1492ed053..8bd7e373601953e0337f1ecb385915084759ffc2 100644 (file)
@@ -731,6 +731,7 @@ static int xtpg_parse_of(struct xtpg_device *xtpg)
                format = xvip_of_get_format(port);
                if (IS_ERR(format)) {
                        dev_err(dev, "invalid format in DT");
+                       of_node_put(port);
                        return PTR_ERR(format);
                }
 
@@ -739,6 +740,7 @@ static int xtpg_parse_of(struct xtpg_device *xtpg)
                        xtpg->vip_format = format;
                } else if (xtpg->vip_format != format) {
                        dev_err(dev, "in/out format mismatch in DT");
+                       of_node_put(port);
                        return -EINVAL;
                }
 
index 7b7cb9c28d2cf2708bee7be1110a0cf0648b6469..b9bf24fefa5a6aee0c068cc1ab684062819c6a16 100644 (file)
@@ -476,8 +476,10 @@ static int xvip_graph_dma_init(struct xvip_composite_device *xdev)
 
        for_each_child_of_node(ports, port) {
                ret = xvip_graph_dma_init_one(xdev, port);
-               if (ret < 0)
+               if (ret < 0) {
+                       of_node_put(port);
                        return ret;
+               }
        }
 
        return 0;
index 5236035f0f2a464423f7379347a19ed81acc9975..70fd8e80198a5797895a5a7a60056307279bd795 100644 (file)
@@ -42,7 +42,7 @@
 #include <linux/videodev2.h>
 #include <linux/io.h>
 #include <linux/slab.h>
-#include <media/tea575x.h>
+#include <media/drv-intf/tea575x.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-fh.h>
@@ -108,7 +108,7 @@ static void maxiradio_tea575x_set_direction(struct snd_tea575x *tea, bool output
 {
 }
 
-static struct snd_tea575x_ops maxiradio_tea_ops = {
+static const struct snd_tea575x_ops maxiradio_tea_ops = {
        .set_pins = maxiradio_tea575x_set_pins,
        .get_pins = maxiradio_tea575x_get_pins,
        .set_direction = maxiradio_tea575x_set_direction,
index b8d61cbc18cb5d7b9c2dd902c2900c32c399cf1a..dc81d422b3947944cddee6d0a76a47f792e8f91b 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/io.h>          /* outb, outb_p                 */
 #include <linux/isa.h>
 #include <linux/pnp.h>
-#include <media/tea575x.h>
+#include <media/drv-intf/tea575x.h>
 
 MODULE_AUTHOR("Ondrej Zary");
 MODULE_DESCRIPTION("MediaForte SF16-FMR2 and SF16-FMD2 FM radio card driver");
@@ -82,7 +82,7 @@ static void fmr2_tea575x_set_direction(struct snd_tea575x *tea, bool output)
 {
 }
 
-static struct snd_tea575x_ops fmr2_tea_ops = {
+static const struct snd_tea575x_ops fmr2_tea_ops = {
        .set_pins = fmr2_tea575x_set_pins,
        .get_pins = fmr2_tea575x_get_pins,
        .set_direction = fmr2_tea575x_set_direction,
index 050b3bb96fecc13a15f05d3f294147200954e8dd..85667a95f003a053ecfeb9a2ad3254453b543d31 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/usb.h>
 #include <linux/workqueue.h>
 #include <media/v4l2-device.h>
-#include <media/tea575x.h>
+#include <media/drv-intf/tea575x.h>
 
 #if defined(CONFIG_LEDS_CLASS) || \
     (defined(CONFIG_LEDS_CLASS_MODULE) && defined(CONFIG_RADIO_SHARK_MODULE))
@@ -150,7 +150,7 @@ static u32 shark_read_val(struct snd_tea575x *tea)
        return val;
 }
 
-static struct snd_tea575x_ops shark_tea_ops = {
+static const struct snd_tea575x_ops shark_tea_ops = {
        .write_val = shark_write_val,
        .read_val  = shark_read_val,
 };
index 8654e0dc5c95376aa7140498e10af342b955d15a..0e65a85d52c6667dac78d175b365cfff17e9ec11 100644 (file)
@@ -137,7 +137,7 @@ static int shark_read_reg(struct radio_tea5777 *tea, u32 *reg_ret)
        return 0;
 }
 
-static struct radio_tea5777_ops shark_tea_ops = {
+static const struct radio_tea5777_ops shark_tea_ops = {
        .write_reg = shark_write_reg,
        .read_reg  = shark_read_reg,
 };
index 9cbb8cdf0ac05baf5214f71d7b71bf143812ba7a..859f0c08ee0543c67af2a4ecbf368906722fbba0 100644 (file)
@@ -31,7 +31,7 @@
 #include <media/v4l2-event.h>
 #include <media/v4l2-device.h>
 
-#include <media/si476x.h>
+#include <media/drv-intf/si476x.h>
 #include <linux/mfd/si476x-core.h>
 
 #define FM_FREQ_RANGE_LOW   64000000
index 4ea43a90a151ed10604c57b01de530f5848cbbce..4bd942526a1bb83a07344074df77e3bfdec8dde5 100644 (file)
@@ -76,7 +76,7 @@ struct radio_tea5777 {
        u32 read_reg;
        u64 write_reg;
        struct mutex mutex;
-       struct radio_tea5777_ops *ops;
+       const struct radio_tea5777_ops *ops;
        void *private_data;
        u8 card[32];
        u8 bus_info[32];
index 04baafe5e901dbae109ba01214249d4450628daf..a82eb9678d6c5379a8d029fff5e85a4f4464f048 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
-#include <media/timb_radio.h>
+#include <linux/platform_data/media/timb_radio.h>
 
 #define DRIVER_NAME "timb-radio"
 
index a77319dcba05c2875d466c6866a36f6998c019b1..5146be2a1a501a81a6faba23a25d7b17f414d690 100644 (file)
@@ -31,7 +31,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-event.h>
-#include <media/si4713.h>
+#include <linux/platform_data/media/si4713.h>
 
 #include "si4713.h"
 
index 8a376e142188511a8511324c094b8273248e244d..29d0e1f104d2bcdf6f15dc245351b2109a038cee 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/gpio/consumer.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-ctrls.h>
-#include <media/si4713.h>
+#include <linux/platform_data/media/si4713.h>
 
 #define SI4713_PRODUCT_NUMBER          0x0D
 
index 43d1ea53cb666ea8d21e7defe739140359d93e7f..3e08475af5790913326ba675bbca66342eb23867 100644 (file)
@@ -31,7 +31,7 @@
 #include <media/v4l2-fh.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-event.h>
-#include <media/tea575x.h>
+#include <media/drv-intf/tea575x.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips");
index b6e13116c6f5a94aee66c839a14bd48a13fc4ed8..bd4d68500085311156f4644042affe458d7ef05b 100644 (file)
@@ -101,7 +101,8 @@ config IR_SHARP_DECODER
 
        ---help---
           Enable this option if you have an infrared remote control which
-          uses the Sharp protocol, and you need software decoding support.
+          uses the Sharp protocol (Sharp, Denon), and you need software
+          decoding support.
 
 config IR_MCE_KBD_DECODER
        tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol"
index 7dbc9ca6d8852ba49b7c2693ca882068f0fc2bf1..5b63b1f15cb18b4431c872923b88d1cd2c0bf764 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/platform_device.h>
 #include <linux/irq.h>
 #include <media/rc-core.h>
-#include <media/gpio-ir-recv.h>
+#include <linux/platform_data/media/gpio-ir-recv.h>
 
 #define GPIO_IR_DRIVER_NAME    "gpio-rc-recv"
 #define GPIO_IR_DEVICE_NAME    "gpio_ir_recv"
@@ -30,6 +30,7 @@ struct gpio_rc_dev {
        struct rc_dev *rcdev;
        int gpio_nr;
        bool active_low;
+       struct timer_list flush_timer;
 };
 
 #ifdef CONFIG_OF
@@ -93,12 +94,26 @@ static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id)
        if (rc < 0)
                goto err_get_value;
 
+       mod_timer(&gpio_dev->flush_timer,
+                 jiffies + nsecs_to_jiffies(gpio_dev->rcdev->timeout));
+
        ir_raw_event_handle(gpio_dev->rcdev);
 
 err_get_value:
        return IRQ_HANDLED;
 }
 
+static void flush_timer(unsigned long arg)
+{
+       struct gpio_rc_dev *gpio_dev = (struct gpio_rc_dev *)arg;
+       DEFINE_IR_RAW_EVENT(ev);
+
+       ev.timeout = true;
+       ev.duration = gpio_dev->rcdev->timeout;
+       ir_raw_event_store(gpio_dev->rcdev, &ev);
+       ir_raw_event_handle(gpio_dev->rcdev);
+}
+
 static int gpio_ir_recv_probe(struct platform_device *pdev)
 {
        struct gpio_rc_dev *gpio_dev;
@@ -144,6 +159,9 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
        rcdev->input_id.version = 0x0100;
        rcdev->dev.parent = &pdev->dev;
        rcdev->driver_name = GPIO_IR_DRIVER_NAME;
+       rcdev->min_timeout = 0;
+       rcdev->timeout = IR_DEFAULT_TIMEOUT;
+       rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
        if (pdata->allowed_protos)
                rcdev->allowed_protocols = pdata->allowed_protos;
        else
@@ -154,6 +172,9 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
        gpio_dev->gpio_nr = pdata->gpio_nr;
        gpio_dev->active_low = pdata->active_low;
 
+       setup_timer(&gpio_dev->flush_timer, flush_timer,
+                   (unsigned long)gpio_dev);
+
        rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv");
        if (rc < 0)
                goto err_gpio_request;
@@ -196,6 +217,7 @@ static int gpio_ir_recv_remove(struct platform_device *pdev)
        struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
 
        free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);
+       del_timer_sync(&gpio_dev->flush_timer);
        rc_unregister_device(gpio_dev->rcdev);
        gpio_free(gpio_dev->gpio_nr);
        kfree(gpio_dev);
index 30bcf188d3773006dd0afc1d1a314f044b8e8db8..182402f7b4d152ae8befc0255b36e32183d0118b 100644 (file)
@@ -47,9 +47,6 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
 {
        struct jvc_dec *data = &dev->raw->jvc;
 
-       if (!(dev->enabled_protocols & RC_BIT_JVC))
-               return 0;
-
        if (!is_timing_event(ev)) {
                if (ev.reset)
                        data->state = STATE_INACTIVE;
index a32659fcd266c5d36cbde8ce5ea86e6cc4609977..5effc65d29479721bffdf8cb1e9abd72bf2b2359 100644 (file)
@@ -415,6 +415,7 @@ static int ir_lirc_unregister(struct rc_dev *dev)
 
        lirc_unregister_driver(lirc->drv->minor);
        lirc_buffer_free(lirc->drv->rbuf);
+       kfree(lirc->drv->rbuf);
        kfree(lirc->drv);
 
        return 0;
index 9f3c9b59f30ccf27bf96b00b9d9142057f5148cf..d80986251ee025490ccd01082dfdf8767b5522c2 100644 (file)
@@ -216,9 +216,6 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
        u32 scancode;
        unsigned long delay;
 
-       if (!(dev->enabled_protocols & RC_BIT_MCE_KBD))
-               return 0;
-
        if (!is_timing_event(ev)) {
                if (ev.reset)
                        data->state = STATE_INACTIVE;
index 7b81fec0820fe6abb54561dfef2f973175c512c9..bea0d1eedee04346abcef4bb9a2229a5f7614e48 100644 (file)
@@ -52,9 +52,6 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
        u8 address, not_address, command, not_command;
        bool send_32bits = false;
 
-       if (!(dev->enabled_protocols & RC_BIT_NEC))
-               return 0;
-
        if (!is_timing_event(ev)) {
                if (ev.reset)
                        data->state = STATE_INACTIVE;
index 84fa6e9b59a1acd9360364fbd30ca0a4e00d3a56..6ffe776abf6bd5c8d1a2553532437db7156ff9d4 100644 (file)
@@ -53,9 +53,6 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
        u32 scancode;
        enum rc_type protocol;
 
-       if (!(dev->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ)))
-               return 0;
-
        if (!is_timing_event(ev)) {
                if (ev.reset)
                        data->state = STATE_INACTIVE;
index d16bc67af732251998fb280b86d887835cf39e1b..e0e2edefa6510cdf39954f57e1b276f5bbacdb12 100644 (file)
@@ -90,11 +90,6 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
        u8 toggle;
        enum rc_type protocol;
 
-       if (!(dev->enabled_protocols &
-             (RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 |
-              RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE)))
-               return 0;
-
        if (!is_timing_event(ev)) {
                if (ev.reset)
                        data->state = STATE_INACTIVE;
index b1e19a26208d88627ab95743717e1fd6a039dc54..4e1711a4046676d79261b7f0a1a082993fcac6a6 100644 (file)
@@ -31,7 +31,7 @@
 
 #include <media/lirc.h>
 #include <media/lirc_dev.h>
-#include <media/ir-rx51.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 |          \
index ad1dc6ae21fc1b5c499fd5b967b2e9e30cddb918..7331e5e7c497a384f34251676d05062df1ed484b 100644 (file)
@@ -58,9 +58,6 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
        u32 scancode;
        u8 address, command, not_command;
 
-       if (!(dev->enabled_protocols & RC_BIT_SANYO))
-               return 0;
-
        if (!is_timing_event(ev)) {
                if (ev.reset) {
                        IR_dprintk(1, "SANYO event reset received. reset to state 0\n");
index b7acdbae8159383c4405f1ca989b826e8d72e717..317677f06f2c6e147d380bd3b4705df5e99224fe 100644 (file)
@@ -48,9 +48,6 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
        struct sharp_dec *data = &dev->raw->sharp;
        u32 msg, echo, address, command, scancode;
 
-       if (!(dev->enabled_protocols & RC_BIT_SHARP))
-               return 0;
-
        if (!is_timing_event(ev)) {
                if (ev.reset)
                        data->state = STATE_INACTIVE;
@@ -118,7 +115,9 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 
                if (data->count == SHARP_NBITS) {
                        /* exp,chk bits should be 1,0 */
-                       if ((data->bits & 0x3) != 0x2)
+                       if ((data->bits & 0x3) != 0x2 &&
+                       /* DENON variant, both chk bits 0 */
+                           (data->bits & 0x3) != 0x0)
                                break;
                        data->state = STATE_ECHO_SPACE;
                } else {
index 58ef06f35175964e5412e340f9acd3ffef638fee..baa972c76e0e19a5f0b5651310df2c93daf0e8fa 100644 (file)
@@ -46,10 +46,6 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
        u32 scancode;
        u8 device, subdevice, function;
 
-       if (!(dev->enabled_protocols &
-             (RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20)))
-               return 0;
-
        if (!is_timing_event(ev)) {
                if (ev.reset)
                        data->state = STATE_INACTIVE;
index 1017d4816e8d55600e835962d813812121f7767a..18596190bbb8d63deef35db20e5a5c815958a375 100644 (file)
@@ -43,9 +43,6 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 {
        struct xmp_dec *data = &dev->raw->xmp;
 
-       if (!(dev->enabled_protocols & RC_BIT_XMP))
-               return 0;
-
        if (!is_timing_event(ev)) {
                if (ev.reset)
                        data->state = STATE_INACTIVE;
index 85af7a8691677a9b3965f469f37bc49b741de6b7..18adf580f502443bafc7c0e310d2556e5908f7dc 100644 (file)
 
 #include "nuvoton-cir.h"
 
+static const struct nvt_chip nvt_chips[] = {
+       { "w83667hg", NVT_W83667HG },
+       { "NCT6775F", NVT_6775F },
+       { "NCT6776F", NVT_6776F },
+       { "NCT6779D", NVT_6779D },
+};
+
+static inline bool is_w83667hg(struct nvt_dev *nvt)
+{
+       return nvt->chip_ver == NVT_W83667HG;
+}
+
 /* write val to config reg */
 static inline void nvt_cr_write(struct nvt_dev *nvt, u8 val, u8 reg)
 {
@@ -224,74 +236,60 @@ static void cir_wake_dump_regs(struct nvt_dev *nvt)
        pr_cont("\n");
 }
 
+static inline const char *nvt_find_chip(struct nvt_dev *nvt, int id)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(nvt_chips); i++)
+               if ((id & SIO_ID_MASK) == nvt_chips[i].chip_ver) {
+                       nvt->chip_ver = nvt_chips[i].chip_ver;
+                       return nvt_chips[i].name;
+               }
+
+       return NULL;
+}
+
+
 /* detect hardware features */
-static int nvt_hw_detect(struct nvt_dev *nvt)
+static void nvt_hw_detect(struct nvt_dev *nvt)
 {
-       unsigned long flags;
-       u8 chip_major, chip_minor;
-       char chip_id[12];
-       bool chip_unknown = false;
+       const char *chip_name;
+       int chip_id;
 
        nvt_efm_enable(nvt);
 
        /* Check if we're wired for the alternate EFER setup */
-       chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
-       if (chip_major == 0xff) {
+       nvt->chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
+       if (nvt->chip_major == 0xff) {
                nvt->cr_efir = CR_EFIR2;
                nvt->cr_efdr = CR_EFDR2;
                nvt_efm_enable(nvt);
-               chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
+               nvt->chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
        }
 
-       chip_minor = nvt_cr_read(nvt, CR_CHIP_ID_LO);
-
-       /* these are the known working chip revisions... */
-       switch (chip_major) {
-       case CHIP_ID_HIGH_667:
-               strcpy(chip_id, "w83667hg\0");
-               if (chip_minor != CHIP_ID_LOW_667)
-                       chip_unknown = true;
-               break;
-       case CHIP_ID_HIGH_677B:
-               strcpy(chip_id, "w83677hg\0");
-               if (chip_minor != CHIP_ID_LOW_677B2 &&
-                   chip_minor != CHIP_ID_LOW_677B3)
-                       chip_unknown = true;
-               break;
-       case CHIP_ID_HIGH_677C:
-               strcpy(chip_id, "w83677hg-c\0");
-               if (chip_minor != CHIP_ID_LOW_677C)
-                       chip_unknown = true;
-               break;
-       default:
-               strcpy(chip_id, "w836x7hg\0");
-               chip_unknown = true;
-               break;
-       }
+       nvt->chip_minor = nvt_cr_read(nvt, CR_CHIP_ID_LO);
+
+       chip_id = nvt->chip_major << 8 | nvt->chip_minor;
+       chip_name = nvt_find_chip(nvt, chip_id);
 
        /* warn, but still let the driver load, if we don't know this chip */
-       if (chip_unknown)
-               nvt_pr(KERN_WARNING, "%s: unknown chip, id: 0x%02x 0x%02x, "
-                      "it may not work...", chip_id, chip_major, chip_minor);
+       if (!chip_name)
+               dev_warn(&nvt->pdev->dev,
+                        "unknown chip, id: 0x%02x 0x%02x, it may not work...",
+                        nvt->chip_major, nvt->chip_minor);
        else
-               nvt_dbg("%s: chip id: 0x%02x 0x%02x",
-                       chip_id, chip_major, chip_minor);
+               dev_info(&nvt->pdev->dev,
+                        "found %s or compatible: chip id: 0x%02x 0x%02x",
+                        chip_name, nvt->chip_major, nvt->chip_minor);
 
        nvt_efm_disable(nvt);
-
-       spin_lock_irqsave(&nvt->nvt_lock, flags);
-       nvt->chip_major = chip_major;
-       nvt->chip_minor = chip_minor;
-       spin_unlock_irqrestore(&nvt->nvt_lock, flags);
-
-       return 0;
 }
 
 static void nvt_cir_ldev_init(struct nvt_dev *nvt)
 {
        u8 val, psreg, psmask, psval;
 
-       if (nvt->chip_major == CHIP_ID_HIGH_667) {
+       if (is_w83667hg(nvt)) {
                psreg = CR_MULTIFUNC_PIN_SEL;
                psmask = MULTIFUNC_PIN_SEL_MASK;
                psval = MULTIFUNC_ENABLE_CIR | MULTIFUNC_ENABLE_CIRWB;
@@ -485,8 +483,9 @@ static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt)
        duration *= SAMPLE_PERIOD;
 
        if (!count || !duration) {
-               nvt_pr(KERN_NOTICE, "Unable to determine carrier! (c:%u, d:%u)",
-                      count, duration);
+               dev_notice(&nvt->pdev->dev,
+                          "Unable to determine carrier! (c:%u, d:%u)",
+                          count, duration);
                return 0;
        }
 
@@ -661,7 +660,7 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
 
 static void nvt_handle_rx_fifo_overrun(struct nvt_dev *nvt)
 {
-       nvt_pr(KERN_WARNING, "RX FIFO overrun detected, flushing data!");
+       dev_warn(&nvt->pdev->dev, "RX FIFO overrun detected, flushing data!");
 
        nvt->pkts = 0;
        nvt_clear_cir_fifo(nvt);
@@ -719,7 +718,7 @@ static void nvt_get_rx_ir_data(struct nvt_dev *nvt)
 
 static void nvt_cir_log_irqs(u8 status, u8 iren)
 {
-       nvt_pr(KERN_INFO, "IRQ 0x%02x (IREN 0x%02x) :%s%s%s%s%s%s%s%s%s",
+       nvt_dbg("IRQ 0x%02x (IREN 0x%02x) :%s%s%s%s%s%s%s%s%s",
                status, iren,
                status & CIR_IRSTS_RDR  ? " RDR"        : "",
                status & CIR_IRSTS_RTR  ? " RTR"        : "",
@@ -779,7 +778,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data)
        if (!status) {
                nvt_dbg_verbose("%s exiting, IRSTS 0x0", __func__);
                nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
-               return IRQ_RETVAL(IRQ_NONE);
+               return IRQ_NONE;
        }
 
        /* ack/clear all irq flags we've got */
@@ -790,11 +789,10 @@ static irqreturn_t nvt_cir_isr(int irq, void *data)
        iren = nvt_cir_reg_read(nvt, CIR_IREN);
        if (!iren) {
                nvt_dbg_verbose("%s exiting, CIR not enabled", __func__);
-               return IRQ_RETVAL(IRQ_NONE);
+               return IRQ_NONE;
        }
 
-       if (debug)
-               nvt_cir_log_irqs(status, iren);
+       nvt_cir_log_irqs(status, iren);
 
        if (status & CIR_IRSTS_RTR) {
                /* FIXME: add code for study/learn mode */
@@ -853,7 +851,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data)
        }
 
        nvt_dbg_verbose("%s done", __func__);
-       return IRQ_RETVAL(IRQ_HANDLED);
+       return IRQ_HANDLED;
 }
 
 /* Interrupt service routine for CIR Wake */
@@ -867,7 +865,7 @@ static irqreturn_t nvt_cir_wake_isr(int irq, void *data)
 
        status = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS);
        if (!status)
-               return IRQ_RETVAL(IRQ_NONE);
+               return IRQ_NONE;
 
        if (status & CIR_WAKE_IRSTS_IR_PENDING)
                nvt_clear_cir_wake_fifo(nvt);
@@ -879,7 +877,7 @@ static irqreturn_t nvt_cir_wake_isr(int irq, void *data)
        iren = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN);
        if (!iren) {
                nvt_dbg_wake("%s exiting, wake not enabled", __func__);
-               return IRQ_RETVAL(IRQ_HANDLED);
+               return IRQ_HANDLED;
        }
 
        if ((status & CIR_WAKE_IRSTS_PE) &&
@@ -896,7 +894,7 @@ static irqreturn_t nvt_cir_wake_isr(int irq, void *data)
        }
 
        nvt_dbg_wake("%s done", __func__);
-       return IRQ_RETVAL(IRQ_HANDLED);
+       return IRQ_HANDLED;
 }
 
 static void nvt_enable_cir(struct nvt_dev *nvt)
@@ -974,7 +972,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
        struct rc_dev *rdev;
        int ret = -ENOMEM;
 
-       nvt = kzalloc(sizeof(struct nvt_dev), GFP_KERNEL);
+       nvt = devm_kzalloc(&pdev->dev, sizeof(struct nvt_dev), GFP_KERNEL);
        if (!nvt)
                return ret;
 
@@ -1026,9 +1024,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
 
        init_waitqueue_head(&nvt->tx.queue);
 
-       ret = nvt_hw_detect(nvt);
-       if (ret)
-               goto exit_free_dev_rdev;
+       nvt_hw_detect(nvt);
 
        /* Initialize CIR & CIR Wake Logical Devices */
        nvt_efm_enable(nvt);
@@ -1074,25 +1070,26 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
 
        ret = -EBUSY;
        /* now claim resources */
-       if (!request_region(nvt->cir_addr,
+       if (!devm_request_region(&pdev->dev, nvt->cir_addr,
                            CIR_IOREG_LENGTH, NVT_DRIVER_NAME))
                goto exit_unregister_device;
 
-       if (request_irq(nvt->cir_irq, nvt_cir_isr, IRQF_SHARED,
-                       NVT_DRIVER_NAME, (void *)nvt))
-               goto exit_release_cir_addr;
+       if (devm_request_irq(&pdev->dev, nvt->cir_irq, nvt_cir_isr,
+                            IRQF_SHARED, NVT_DRIVER_NAME, (void *)nvt))
+               goto exit_unregister_device;
 
-       if (!request_region(nvt->cir_wake_addr,
+       if (!devm_request_region(&pdev->dev, nvt->cir_wake_addr,
                            CIR_IOREG_LENGTH, NVT_DRIVER_NAME))
-               goto exit_free_irq;
+               goto exit_unregister_device;
 
-       if (request_irq(nvt->cir_wake_irq, nvt_cir_wake_isr, IRQF_SHARED,
-                       NVT_DRIVER_NAME, (void *)nvt))
-               goto exit_release_cir_wake_addr;
+       if (devm_request_irq(&pdev->dev, nvt->cir_wake_irq,
+                            nvt_cir_wake_isr, IRQF_SHARED,
+                            NVT_DRIVER_NAME, (void *)nvt))
+               goto exit_unregister_device;
 
        device_init_wakeup(&pdev->dev, true);
 
-       nvt_pr(KERN_NOTICE, "driver has been successfully loaded\n");
+       dev_notice(&pdev->dev, "driver has been successfully loaded\n");
        if (debug) {
                cir_dump_regs(nvt);
                cir_wake_dump_regs(nvt);
@@ -1100,18 +1097,11 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
 
        return 0;
 
-exit_release_cir_wake_addr:
-       release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
-exit_free_irq:
-       free_irq(nvt->cir_irq, nvt);
-exit_release_cir_addr:
-       release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
 exit_unregister_device:
        rc_unregister_device(rdev);
        rdev = NULL;
 exit_free_dev_rdev:
        rc_free_device(rdev);
-       kfree(nvt);
 
        return ret;
 }
@@ -1129,15 +1119,7 @@ static void nvt_remove(struct pnp_dev *pdev)
        nvt_enable_wake(nvt);
        spin_unlock_irqrestore(&nvt->nvt_lock, flags);
 
-       /* free resources */
-       free_irq(nvt->cir_irq, nvt);
-       free_irq(nvt->cir_wake_irq, nvt);
-       release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
-       release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
-
        rc_unregister_device(nvt->rdev);
-
-       kfree(nvt);
 }
 
 static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state)
index e1cf23c3875b16ead52464d4e6ad3c479fd1e951..0ad15d34e9c93ce8adedd5f114f84543776f3055 100644 (file)
@@ -35,9 +35,6 @@
 static int debug;
 
 
-#define nvt_pr(level, text, ...) \
-       printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__)
-
 #define nvt_dbg(text, ...) \
        if (debug) \
                printk(KERN_DEBUG \
@@ -64,6 +61,21 @@ static int debug;
 #define TX_BUF_LEN 256
 #define RX_BUF_LEN 32
 
+#define SIO_ID_MASK 0xfff0
+
+enum nvt_chip_ver {
+       NVT_UNKNOWN     = 0,
+       NVT_W83667HG    = 0xa510,
+       NVT_6775F       = 0xb470,
+       NVT_6776F       = 0xc330,
+       NVT_6779D       = 0xc560
+};
+
+struct nvt_chip {
+       const char *name;
+       enum nvt_chip_ver chip_ver;
+};
+
 struct nvt_dev {
        struct pnp_dev *pdev;
        struct rc_dev *rdev;
@@ -93,6 +105,7 @@ struct nvt_dev {
        int cir_irq;
        int cir_wake_irq;
 
+       enum nvt_chip_ver chip_ver;
        /* hardware id */
        u8 chip_major;
        u8 chip_minor;
@@ -326,15 +339,6 @@ struct nvt_dev {
 #define EFER_EFM_ENABLE                0x87
 #define EFER_EFM_DISABLE       0xaa
 
-/* Chip IDs found in CR_CHIP_ID_{HI,LO} */
-#define CHIP_ID_HIGH_667       0xa5
-#define CHIP_ID_HIGH_677B      0xb4
-#define CHIP_ID_HIGH_677C      0xc3
-#define CHIP_ID_LOW_667                0x13
-#define CHIP_ID_LOW_677B2      0x72
-#define CHIP_ID_LOW_677B3      0x73
-#define CHIP_ID_LOW_677C       0x33
-
 /* Config regs we need to care about */
 #define CR_SOFTWARE_RESET      0x02
 #define CR_LOGICAL_DEV_SEL     0x07
index b68d4f76273448fcbc98fc1e215a6656c9b6c6ec..7359f3d03b647244baeb8c99ad7076e9a11ba74d 100644 (file)
@@ -167,75 +167,4 @@ void ir_raw_init(void);
  * loads the compiled decoders for their usage with IR raw events
  */
 
-/* from ir-nec-decoder.c */
-#ifdef CONFIG_IR_NEC_DECODER_MODULE
-#define load_nec_decode()      request_module_nowait("ir-nec-decoder")
-#else
-static inline void load_nec_decode(void) { }
-#endif
-
-/* from ir-rc5-decoder.c */
-#ifdef CONFIG_IR_RC5_DECODER_MODULE
-#define load_rc5_decode()      request_module_nowait("ir-rc5-decoder")
-#else
-static inline void load_rc5_decode(void) { }
-#endif
-
-/* from ir-rc6-decoder.c */
-#ifdef CONFIG_IR_RC6_DECODER_MODULE
-#define load_rc6_decode()      request_module_nowait("ir-rc6-decoder")
-#else
-static inline void load_rc6_decode(void) { }
-#endif
-
-/* from ir-jvc-decoder.c */
-#ifdef CONFIG_IR_JVC_DECODER_MODULE
-#define load_jvc_decode()      request_module_nowait("ir-jvc-decoder")
-#else
-static inline void load_jvc_decode(void) { }
-#endif
-
-/* from ir-sony-decoder.c */
-#ifdef CONFIG_IR_SONY_DECODER_MODULE
-#define load_sony_decode()     request_module_nowait("ir-sony-decoder")
-#else
-static inline void load_sony_decode(void) { }
-#endif
-
-/* from ir-sanyo-decoder.c */
-#ifdef CONFIG_IR_SANYO_DECODER_MODULE
-#define load_sanyo_decode()    request_module_nowait("ir-sanyo-decoder")
-#else
-static inline void load_sanyo_decode(void) { }
-#endif
-
-/* from ir-sharp-decoder.c */
-#ifdef CONFIG_IR_SHARP_DECODER_MODULE
-#define load_sharp_decode()    request_module_nowait("ir-sharp-decoder")
-#else
-static inline void load_sharp_decode(void) { }
-#endif
-
-/* from ir-mce_kbd-decoder.c */
-#ifdef CONFIG_IR_MCE_KBD_DECODER_MODULE
-#define load_mce_kbd_decode()  request_module_nowait("ir-mce_kbd-decoder")
-#else
-static inline void load_mce_kbd_decode(void) { }
-#endif
-
-/* from ir-lirc-codec.c */
-#ifdef CONFIG_IR_LIRC_CODEC_MODULE
-#define load_lirc_codec()      request_module_nowait("ir-lirc-codec")
-#else
-static inline void load_lirc_codec(void) { }
-#endif
-
-/* from ir-xmp-decoder.c */
-#ifdef CONFIG_IR_XMP_DECODER_MODULE
-#define load_xmp_decode()      request_module_nowait("ir-xmp-decoder")
-#else
-static inline void load_xmp_decode(void) { }
-#endif
-
-
 #endif /* _RC_CORE_PRIV */
index ad260520a9d4071a9c4198051832dc7523a17a50..c69807fe2feff08c47441dc2bf3c780c4440d505 100644 (file)
@@ -59,7 +59,9 @@ static int ir_raw_event_thread(void *data)
 
                mutex_lock(&ir_raw_handler_lock);
                list_for_each_entry(handler, &ir_raw_handler_list, list)
-                       handler->decode(raw->dev, ev);
+                       if (raw->dev->enabled_protocols & handler->protocols ||
+                           !handler->protocols)
+                               handler->decode(raw->dev, ev);
                raw->prev_ev = ev;
                mutex_unlock(&ir_raw_handler_lock);
        }
@@ -246,6 +248,14 @@ static int change_protocol(struct rc_dev *dev, u64 *rc_type)
        return 0;
 }
 
+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);
+}
+
 /*
  * Used to (un)register raw event clients
  */
@@ -337,33 +347,16 @@ EXPORT_SYMBOL(ir_raw_handler_register);
 void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
 {
        struct ir_raw_event_ctrl *raw;
+       u64 protocols = ir_raw_handler->protocols;
 
        mutex_lock(&ir_raw_handler_lock);
        list_del(&ir_raw_handler->list);
-       if (ir_raw_handler->raw_unregister)
-               list_for_each_entry(raw, &ir_raw_client_list, list)
+       list_for_each_entry(raw, &ir_raw_client_list, list) {
+               ir_raw_disable_protocols(raw->dev, protocols);
+               if (ir_raw_handler->raw_unregister)
                        ir_raw_handler->raw_unregister(raw->dev);
-       available_protocols &= ~ir_raw_handler->protocols;
+       }
+       available_protocols &= ~protocols;
        mutex_unlock(&ir_raw_handler_lock);
 }
 EXPORT_SYMBOL(ir_raw_handler_unregister);
-
-void ir_raw_init(void)
-{
-       /* Load the decoder modules */
-
-       load_nec_decode();
-       load_rc5_decode();
-       load_rc6_decode();
-       load_jvc_decode();
-       load_sony_decode();
-       load_sanyo_decode();
-       load_sharp_decode();
-       load_mce_kbd_decode();
-       load_lirc_codec();
-       load_xmp_decode();
-
-       /* If needed, we may later add some init code. In this case,
-          it is needed to change the CONFIG_MODULE test at rc-core.h
-        */
-}
index 3f0f71adabb4dbba061ef57e1f798ca0e9187c77..1042fa331a0749284762b33a83fd1ac1600548c7 100644 (file)
@@ -61,7 +61,7 @@ struct rc_map *rc_map_get(const char *name)
        struct rc_map_list *map;
 
        map = seek_rc_map(name);
-#ifdef MODULE
+#ifdef CONFIG_MODULES
        if (!map) {
                int rc = request_module("%s", name);
                if (rc < 0) {
@@ -777,30 +777,31 @@ static struct class rc_class = {
  * used by the sysfs protocols file. Note that the order
  * of the entries is relevant.
  */
-static struct {
+static const struct {
        u64     type;
-       char    *name;
+       const char      *name;
+       const char      *module_name;
 } proto_names[] = {
-       { RC_BIT_NONE,          "none"          },
-       { RC_BIT_OTHER,         "other"         },
-       { RC_BIT_UNKNOWN,       "unknown"       },
+       { RC_BIT_NONE,          "none",         NULL                    },
+       { RC_BIT_OTHER,         "other",        NULL                    },
+       { RC_BIT_UNKNOWN,       "unknown",      NULL                    },
        { RC_BIT_RC5 |
-         RC_BIT_RC5X,          "rc-5"          },
-       { RC_BIT_NEC,           "nec"           },
+         RC_BIT_RC5X,          "rc-5",         "ir-rc5-decoder"        },
+       { RC_BIT_NEC,           "nec",          "ir-nec-decoder"        },
        { RC_BIT_RC6_0 |
          RC_BIT_RC6_6A_20 |
          RC_BIT_RC6_6A_24 |
          RC_BIT_RC6_6A_32 |
-         RC_BIT_RC6_MCE,       "rc-6"          },
-       { RC_BIT_JVC,           "jvc"           },
+         RC_BIT_RC6_MCE,       "rc-6",         "ir-rc6-decoder"        },
+       { RC_BIT_JVC,           "jvc",          "ir-jvc-decoder"        },
        { RC_BIT_SONY12 |
          RC_BIT_SONY15 |
-         RC_BIT_SONY20,        "sony"          },
-       { RC_BIT_RC5_SZ,        "rc-5-sz"       },
-       { RC_BIT_SANYO,         "sanyo"         },
-       { RC_BIT_SHARP,         "sharp"         },
-       { RC_BIT_MCE_KBD,       "mce_kbd"       },
-       { RC_BIT_XMP,           "xmp"           },
+         RC_BIT_SONY20,        "sony",         "ir-sony-decoder"       },
+       { RC_BIT_RC5_SZ,        "rc-5-sz",      "ir-rc5-decoder"        },
+       { RC_BIT_SANYO,         "sanyo",        "ir-sanyo-decoder"      },
+       { RC_BIT_SHARP,         "sharp",        "ir-sharp-decoder"      },
+       { RC_BIT_MCE_KBD,       "mce_kbd",      "ir-mce_kbd-decoder"    },
+       { RC_BIT_XMP,           "xmp",          "ir-xmp-decoder"        },
 };
 
 /**
@@ -979,6 +980,48 @@ static int parse_protocol_change(u64 *protocols, const char *buf)
        return count;
 }
 
+static void ir_raw_load_modules(u64 *protocols)
+
+{
+       u64 available;
+       int i, ret;
+
+       for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
+               if (proto_names[i].type == RC_BIT_NONE ||
+                   proto_names[i].type & (RC_BIT_OTHER | RC_BIT_UNKNOWN))
+                       continue;
+
+               available = ir_raw_get_allowed_protocols();
+               if (!(*protocols & proto_names[i].type & ~available))
+                       continue;
+
+               if (!proto_names[i].module_name) {
+                       pr_err("Can't enable IR protocol %s\n",
+                              proto_names[i].name);
+                       *protocols &= ~proto_names[i].type;
+                       continue;
+               }
+
+               ret = request_module("%s", proto_names[i].module_name);
+               if (ret < 0) {
+                       pr_err("Couldn't load IR protocol module %s\n",
+                              proto_names[i].module_name);
+                       *protocols &= ~proto_names[i].type;
+                       continue;
+               }
+               msleep(20);
+               available = ir_raw_get_allowed_protocols();
+               if (!(*protocols & proto_names[i].type & ~available))
+                       continue;
+
+               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;
+       }
+}
+
 /**
  * store_protocols() - changes the current/wakeup IR protocol(s)
  * @device:    the device descriptor
@@ -1045,6 +1088,9 @@ static ssize_t store_protocols(struct device *device,
                goto out;
        }
 
+       if (dev->driver_type == RC_DRIVER_IR_RAW)
+               ir_raw_load_modules(&new_protocols);
+
        if (new_protocols != old_protocols) {
                *current_protocols = new_protocols;
                IR_dprintk(1, "Protocols changed to 0x%llx\n",
@@ -1420,17 +1466,13 @@ int rc_register_device(struct rc_dev *dev)
        dev->input_dev->rep[REP_PERIOD] = 125;
 
        path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
-       printk(KERN_INFO "%s: %s as %s\n",
-               dev_name(&dev->dev),
-               dev->input_name ? dev->input_name : "Unspecified device",
-               path ? path : "N/A");
+       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) {
-               /* Load raw decoders, if they aren't already */
                if (!raw_init) {
-                       IR_dprintk(1, "Loading raw decoders\n");
-                       ir_raw_init();
+                       request_module_nowait("ir-lirc-codec");
                        raw_init = true;
                }
                /* calls ir_register_device so unlock mutex here*/
index 37d040158dff50302b1a065b8a6518298db0a47c..1fa0c9d1c5083766c53bafe11d5e955bdd6c838a 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/reset.h>
 #include <media/rc-core.h>
 #include <linux/pinctrl/consumer.h>
+#include <linux/pm_wakeirq.h>
 
 struct st_rc_device {
        struct device                   *dev;
@@ -190,6 +191,9 @@ static void st_rc_hardware_init(struct st_rc_device *dev)
 static int st_rc_remove(struct platform_device *pdev)
 {
        struct st_rc_device *rc_dev = platform_get_drvdata(pdev);
+
+       dev_pm_clear_wake_irq(&pdev->dev);
+       device_init_wakeup(&pdev->dev, false);
        clk_disable_unprepare(rc_dev->sys_clock);
        rc_unregister_device(rc_dev->rdev);
        return 0;
@@ -298,22 +302,22 @@ static int st_rc_probe(struct platform_device *pdev)
        rdev->map_name = RC_MAP_LIRC;
        rdev->input_name = "ST Remote Control Receiver";
 
-       /* enable wake via this device */
-       device_set_wakeup_capable(dev, true);
-       device_set_wakeup_enable(dev, true);
-
        ret = rc_register_device(rdev);
        if (ret < 0)
                goto clkerr;
 
        rc_dev->rdev = rdev;
        if (devm_request_irq(dev, rc_dev->irq, st_rc_rx_interrupt,
-                       IRQF_NO_SUSPEND, IR_ST_NAME, rc_dev) < 0) {
+                            0, IR_ST_NAME, rc_dev) < 0) {
                dev_err(dev, "IRQ %d register failed\n", rc_dev->irq);
                ret = -EINVAL;
                goto rcerr;
        }
 
+       /* enable wake via this device */
+       device_init_wakeup(dev, true);
+       dev_pm_set_wake_irq(dev, rc_dev->irq);
+
        /**
         * for LIRC_MODE_MODE2 or LIRC_MODE_PULSE or LIRC_MODE_RAW
         * lircd expects a long space first before a signal train to sync.
index 5a17cb88ff27e45e12482b50170fc15e7f386fa9..815243c65bc3c7037671f7bfc391a99deb2994c8 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/ktime.h>
 #include <linux/usb.h>
 #include <linux/usb/input.h>
 #include <media/rc-core.h>
@@ -96,8 +97,8 @@ struct streamzap_ir {
        /* sum of signal lengths received since signal start */
        unsigned long           sum;
        /* start time of signal; necessary for gap tracking */
-       struct timeval          signal_last;
-       struct timeval          signal_start;
+       ktime_t                 signal_last;
+       ktime_t                 signal_start;
        bool                    timeout_enabled;
 
        char                    name[128];
@@ -136,20 +137,18 @@ static void sz_push_full_pulse(struct streamzap_ir *sz,
        DEFINE_IR_RAW_EVENT(rawir);
 
        if (sz->idle) {
-               long deltv;
+               int delta;
 
                sz->signal_last = sz->signal_start;
-               do_gettimeofday(&sz->signal_start);
+               sz->signal_start = ktime_get_real();
 
-               deltv = sz->signal_start.tv_sec - sz->signal_last.tv_sec;
+               delta = ktime_us_delta(sz->signal_start, sz->signal_last);
                rawir.pulse = false;
-               if (deltv > 15) {
+               if (delta > (15 * USEC_PER_SEC)) {
                        /* really long time */
                        rawir.duration = IR_MAX_DURATION;
                } else {
-                       rawir.duration = (int)(deltv * 1000000 +
-                               sz->signal_start.tv_usec -
-                               sz->signal_last.tv_usec);
+                       rawir.duration = delta;
                        rawir.duration -= sz->sum;
                        rawir.duration = US_TO_NS(rawir.duration);
                        rawir.duration = (rawir.duration > IR_MAX_DURATION) ?
@@ -428,7 +427,7 @@ static int streamzap_probe(struct usb_interface *intf,
        sz->max_timeout = US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION);
        #endif
 
-       do_gettimeofday(&sz->signal_start);
+       sz->signal_start = ktime_get_real();
 
        /* Complete final initialisations */
        usb_fill_int_urb(sz->urb_in, usbdev, pipe, sz->buf_in,
index 7830aef3db459661e9c3e436dc53477d3ae7625a..40f77685cc4a206eca9260ee1ad1271f7bdf1e35 100644 (file)
@@ -153,6 +153,8 @@ static int sunxi_ir_probe(struct platform_device *pdev)
        if (!ir)
                return -ENOMEM;
 
+       spin_lock_init(&ir->ir_lock);
+
        if (of_device_is_compatible(dn, "allwinner,sun5i-a13-ir"))
                ir->fifo_size = 64;
        else
index 95ed46f2cd2600b036f1ac2299757e0b616a3da1..353b178becf66c92532a81e6c09ad8f8d70759a4 100644 (file)
@@ -385,7 +385,7 @@ static const struct dvb_tuner_ops max2165_tuner_ops = {
        .info = {
                .name           = "Maxim MAX2165",
                .frequency_min  = 470000000,
-               .frequency_max  = 780000000,
+               .frequency_max  = 862000000,
                .frequency_step =     50000,
        },
 
index 9e9c5eb4cb66949a7e84a9789a9829f6f1f913d9..6457ac91ef09567b8b3986d3c6bf3aa55771cfaa 100644 (file)
@@ -225,7 +225,6 @@ struct mt2063_state {
        const struct mt2063_config *config;
        struct dvb_tuner_ops ops;
        struct dvb_frontend *frontend;
-       struct tuner_state status;
 
        u32 frequency;
        u32 srate;
index ce157edd45fa1adb3dd382037dd421f8b8590091..0e1ca2b00e61e3e78e3f30f1f357a2902aebb7d0 100644 (file)
@@ -168,6 +168,7 @@ static int si2157_init(struct dvb_frontend *fe)
                len = fw->data[fw->size - remaining];
                if (len > SI2157_ARGLEN) {
                        dev_err(&client->dev, "Bad firmware length\n");
+                       ret = -EINVAL;
                        goto err_release_firmware;
                }
                memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len);
index 565a59310747680858bb2bf30543e05becd579a0..0d4ac5947f3ab7b890f904edfee2f95cab1ba20c 100644 (file)
@@ -316,7 +316,7 @@ static void airspy_urb_complete(struct urb *urb)
                len = airspy_convert_stream(s, ptr, urb->transfer_buffer,
                                urb->actual_length);
                vb2_set_plane_payload(&fbuf->vb.vb2_buf, 0, len);
-               v4l2_get_timestamp(&fbuf->vb.timestamp);
+               fbuf->vb.vb2_buf.timestamp = ktime_get_ns();
                fbuf->vb.sequence = s->sequence++;
                vb2_buffer_done(&fbuf->vb.vb2_buf, VB2_BUF_STATE_DONE);
        }
@@ -488,7 +488,7 @@ static void airspy_disconnect(struct usb_interface *intf)
 
 /* Videobuf2 operations */
 static int airspy_queue_setup(struct vb2_queue *vq,
-               const void *parg, unsigned int *nbuffers,
+               unsigned int *nbuffers,
                unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
 {
        struct airspy *s = vb2_get_drv_priv(vq);
index 07d08c49f4d495d0fc40d26a3bde82051eae7c30..5a28ce3a1d492600d002a504323745f4857bf259 100644 (file)
@@ -198,6 +198,7 @@ int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap)
        pr_info("%s: firmware: %s loaded with success\n",
                DRIVER_NAME, fw1);
        release_firmware(firmware);
+       firmware = NULL;
 
        /* wait for boot to complete */
        mdelay(100);
index 130c8b49bf7fb56a2ca460c8bbf37ea9faf984c5..b4efc103ae5786b5e2297032a4d4b00e86655f09 100644 (file)
 
 /* ------------------------------------------------------------------ */
 
-static int vbi_queue_setup(struct vb2_queue *vq, const void *parg,
+static int vbi_queue_setup(struct vb2_queue *vq,
                           unsigned int *nbuffers, unsigned int *nplanes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct au0828_dev *dev = vb2_get_drv_priv(vq);
-       unsigned long img_size = dev->vbi_width * dev->vbi_height * 2;
-       unsigned long size;
-
-       size = fmt ? (fmt->fmt.vbi.samples_per_line *
-               (fmt->fmt.vbi.count[0] + fmt->fmt.vbi.count[1])) : img_size;
-       if (size < img_size)
-               return -EINVAL;
+       unsigned long size = dev->vbi_width * dev->vbi_height * 2;
 
+       if (*nplanes)
+               return sizes[0] < size ? -EINVAL : 0;
        *nplanes = 1;
        sizes[0] = size;
-
        return 0;
 }
 
index 45c622e234f7fb4bade7608cfdda352f908b608e..0a725a161dd6c0020b8304f3a3230ed6b37a1032 100644 (file)
@@ -314,7 +314,7 @@ static inline void buffer_filled(struct au0828_dev *dev,
                vb->sequence = dev->vbi_frame_count++;
 
        vb->field = V4L2_FIELD_INTERLACED;
-       v4l2_get_timestamp(&vb->timestamp);
+       vb->vb2_buf.timestamp = ktime_get_ns();
        vb2_buffer_done(&vb->vb2_buf, VB2_BUF_STATE_DONE);
 }
 
@@ -638,19 +638,15 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
        return rc;
 }
 
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
                       unsigned int *nbuffers, unsigned int *nplanes,
                       unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct au0828_dev *dev = vb2_get_drv_priv(vq);
-       unsigned long img_size = dev->height * dev->bytesperline;
-       unsigned long size;
-
-       size = fmt ? fmt->fmt.pix.sizeimage : img_size;
-       if (size < img_size)
-               return -EINVAL;
+       unsigned long size = dev->height * dev->bytesperline;
 
+       if (*nplanes)
+               return sizes[0] < size ? -EINVAL : 0;
        *nplanes = 1;
        sizes[0] = size;
 
index 351a78a84c3d618346167563c15d77a204fffeae..c1aa1ab2ece9ffc28d33a9cb4f0d44c2cca15948 100644 (file)
@@ -890,8 +890,7 @@ static void cpia2_usb_disconnect(struct usb_interface *intf)
                DBG("Wakeup waiting processes\n");
                cam->curbuff->status = FRAME_READY;
                cam->curbuff->length = 0;
-               if (waitqueue_active(&cam->wq_stream))
-                       wake_up_interruptible(&cam->wq_stream);
+               wake_up_interruptible(&cam->wq_stream);
        }
 
        DBG("Releasing interface\n");
index 47a98a2014a5bb619744a77e4b58f51c2e764399..48643b94e69449503618e2d95fc16a8da01c319b 100644 (file)
@@ -37,7 +37,7 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-event.h>
-#include <media/cx2341x.h>
+#include <media/drv-intf/cx2341x.h>
 #include <media/tuner.h>
 
 #define CX231xx_FIRM_IMAGE_SIZE 376836
@@ -1492,6 +1492,27 @@ static struct videobuf_queue_ops cx231xx_qops = {
 
 /* ------------------------------------------------------------------ */
 
+static int vidioc_cropcap(struct file *file, void *priv,
+                         struct v4l2_cropcap *cc)
+{
+       struct cx231xx_fh *fh = priv;
+       struct cx231xx *dev = fh->dev;
+       bool is_50hz = dev->encodernorm.id & V4L2_STD_625_50;
+
+       if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       cc->bounds.left = 0;
+       cc->bounds.top = 0;
+       cc->bounds.width = dev->ts1.width;
+       cc->bounds.height = dev->ts1.height;
+       cc->defrect = cc->bounds;
+       cc->pixelaspect.numerator = is_50hz ? 54 : 11;
+       cc->pixelaspect.denominator = is_50hz ? 59 : 10;
+
+       return 0;
+}
+
 static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm)
 {
        struct cx231xx_fh  *fh  = file->private_data;
@@ -1834,6 +1855,7 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
        .vidioc_g_input          = cx231xx_g_input,
        .vidioc_s_input          = cx231xx_s_input,
        .vidioc_s_ctrl           = vidioc_s_ctrl,
+       .vidioc_cropcap          = vidioc_cropcap,
        .vidioc_querycap         = cx231xx_querycap,
        .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
        .vidioc_g_fmt_vid_cap    = vidioc_g_fmt_vid_cap,
@@ -1901,7 +1923,7 @@ static int cx231xx_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx)
        return 0;
 }
 
-static struct cx2341x_handler_ops cx231xx_ops = {
+static const struct cx2341x_handler_ops cx231xx_ops = {
        /* needed for the video clock freq */
        .s_audio_sampling_freq = cx231xx_s_audio_sampling_freq,
        /* needed for setting up the video resolution */
index 4a117a58c39a0de5521759b564209811245b3567..89dc695c696e5b154b6543f2b85c83459b13a622 100644 (file)
@@ -30,7 +30,7 @@
 #include <media/tveeprom.h>
 #include <media/v4l2-common.h>
 
-#include <media/cx25840.h>
+#include <media/drv-intf/cx25840.h>
 #include "dvb-usb-ids.h"
 #include "xc5000.h"
 #include "tda18271.h"
@@ -352,7 +352,7 @@ struct cx231xx_board cx231xx_boards[] = {
                .agc_analog_digital_select_gpio = 0x0c,
                .gpio_pin_status_mask = 0x4001000,
                .tuner_i2c_master = I2C_1_MUX_1,
-               .demod_i2c_master = I2C_2,
+               .demod_i2c_master = I2C_1_MUX_1,
                .has_dvb = 1,
                .demod_addr = 0x0e,
                .norm = V4L2_STD_NTSC,
@@ -713,7 +713,7 @@ struct cx231xx_board cx231xx_boards[] = {
                .agc_analog_digital_select_gpio = 0x0c,
                .gpio_pin_status_mask = 0x4001000,
                .tuner_i2c_master = I2C_1_MUX_3,
-               .demod_i2c_master = I2C_2,
+               .demod_i2c_master = I2C_1_MUX_3,
                .has_dvb = 1,
                .demod_addr = 0x0e,
                .norm = V4L2_STD_PAL,
@@ -752,7 +752,7 @@ struct cx231xx_board cx231xx_boards[] = {
                .agc_analog_digital_select_gpio = 0x0c,
                .gpio_pin_status_mask = 0x4001000,
                .tuner_i2c_master = I2C_1_MUX_3,
-               .demod_i2c_master = I2C_2,
+               .demod_i2c_master = I2C_1_MUX_3,
                .has_dvb = 1,
                .demod_addr = 0x0e,
                .norm = V4L2_STD_PAL,
@@ -791,7 +791,7 @@ struct cx231xx_board cx231xx_boards[] = {
                .agc_analog_digital_select_gpio = 0x0c,
                .gpio_pin_status_mask = 0x4001000,
                .tuner_i2c_master = I2C_1_MUX_3,
-               .demod_i2c_master = I2C_2,
+               .demod_i2c_master = I2C_1_MUX_3,
                .has_dvb = 1,
                .demod_addr = 0x0e,
                .norm = V4L2_STD_NTSC,
index a2fd49b6be837cef33fe694bd6f48520e21312e7..f497888d94bfdf748b90ecf495f709c29f112e9b 100644 (file)
@@ -914,6 +914,7 @@ EXPORT_SYMBOL_GPL(cx231xx_uninit_isoc);
  */
 void cx231xx_uninit_bulk(struct cx231xx *dev)
 {
+       struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq;
        struct urb *urb;
        int i;
 
@@ -931,7 +932,7 @@ void cx231xx_uninit_bulk(struct cx231xx *dev)
                        if (dev->video_mode.bulk_ctl.transfer_buffer[i]) {
                                usb_free_coherent(dev->udev,
                                                urb->transfer_buffer_length,
-                                               dev->video_mode.isoc_ctl.
+                                               dev->video_mode.bulk_ctl.
                                                transfer_buffer[i],
                                                urb->transfer_dma);
                        }
@@ -943,10 +944,12 @@ void cx231xx_uninit_bulk(struct cx231xx *dev)
 
        kfree(dev->video_mode.bulk_ctl.urb);
        kfree(dev->video_mode.bulk_ctl.transfer_buffer);
+       kfree(dma_q->p_left_data);
 
        dev->video_mode.bulk_ctl.urb = NULL;
        dev->video_mode.bulk_ctl.transfer_buffer = NULL;
        dev->video_mode.bulk_ctl.num_bufs = 0;
+       dma_q->p_left_data = NULL;
 
        if (dev->mode_tv == 0)
                cx231xx_capture_start(dev, 0, Raw_Video);
@@ -1196,6 +1199,16 @@ int cx231xx_init_bulk(struct cx231xx *dev, int max_packets,
                                  sb_size, cx231xx_bulk_irq_callback, dma_q);
        }
 
+       /* clear halt */
+       rc = usb_clear_halt(dev->udev, dev->video_mode.bulk_ctl.urb[0]->pipe);
+       if (rc < 0) {
+               dev_err(dev->dev,
+                       "failed to clear USB bulk endpoint stall/halt condition (error=%i)\n",
+                       rc);
+               cx231xx_uninit_bulk(dev);
+               return rc;
+       }
+
        init_waitqueue_head(&dma_q->wq);
 
        /* submit urbs and enables IRQ */
index 66ee161fc7ba891a14bdace5f79b4a155d993ded..e3594b9fab4a58247630a5b5d37af4eb8363b3db 100644 (file)
@@ -725,7 +725,7 @@ static int dvb_init(struct cx231xx *dev)
 
                dev->dvb->frontend = dvb_attach(lgdt3305_attach,
                                                &hcw_lgdt3305_config,
-                                               tuner_i2c);
+                                               demod_i2c);
 
                if (dev->dvb->frontend == NULL) {
                        dev_err(dev->dev,
@@ -746,7 +746,7 @@ static int dvb_init(struct cx231xx *dev)
 
                dev->dvb->frontend = dvb_attach(si2165_attach,
                        &hauppauge_930C_HD_1113xx_si2165_config,
-                       tuner_i2c
+                       demod_i2c
                        );
 
                if (dev->dvb->frontend == NULL) {
@@ -779,7 +779,7 @@ static int dvb_init(struct cx231xx *dev)
 
                dev->dvb->frontend = dvb_attach(si2165_attach,
                        &pctv_quatro_stick_1114xx_si2165_config,
-                       tuner_i2c
+                       demod_i2c
                        );
 
                if (dev->dvb->frontend == NULL) {
@@ -835,7 +835,7 @@ static int dvb_init(struct cx231xx *dev)
 
                dev->dvb->frontend = dvb_attach(lgdt3306a_attach,
                        &hauppauge_955q_lgdt3306a_config,
-                       tuner_i2c
+                       demod_i2c
                        );
 
                if (dev->dvb->frontend == NULL) {
index a08014d20a5c2f12af14dd7f477802b587743902..15bb573b78ac82767dd58f6248fbb8def8b24e97 100644 (file)
@@ -32,7 +32,7 @@
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
-#include <media/msp3400.h>
+#include <media/drv-intf/msp3400.h>
 #include <media/tuner.h>
 
 #include "cx231xx-vbi.h"
index d0d8f08e37c8706baf94552ed85a6149491e080a..a70850fe6235ac8dc25b6c0ef63e3d633029bd0a 100644 (file)
@@ -36,7 +36,7 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-event.h>
-#include <media/msp3400.h>
+#include <media/drv-intf/msp3400.h>
 #include <media/tuner.h>
 
 #include "dvb_frontend.h"
@@ -1444,6 +1444,7 @@ static int vidioc_cropcap(struct file *file, void *priv,
 {
        struct cx231xx_fh *fh = priv;
        struct cx231xx *dev = fh->dev;
+       bool is_50hz = dev->norm & V4L2_STD_625_50;
 
        if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
@@ -1453,8 +1454,8 @@ static int vidioc_cropcap(struct file *file, void *priv,
        cc->bounds.width = dev->width;
        cc->bounds.height = dev->height;
        cc->defrect = cc->bounds;
-       cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
-       cc->pixelaspect.denominator = 59;
+       cc->pixelaspect.numerator = is_50hz ? 54 : 11;
+       cc->pixelaspect.denominator = is_50hz ? 59 : 10;
 
        return 0;
 }
index 54790fbe8fdc21304a7360e68534187511de5328..ec6d3f5bc36d7a9bcaaf573793c2c6f7c4e71711 100644 (file)
 #include <linux/mutex.h>
 #include <linux/usb.h>
 
-#include <media/cx2341x.h>
+#include <media/drv-intf/cx2341x.h>
 
 #include <media/videobuf-vmalloc.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-fh.h>
 #include <media/rc-core.h>
-#include <media/ir-kbd-i2c.h>
+#include <media/i2c/ir-kbd-i2c.h>
 #include <media/videobuf-dvb.h>
 
 #include "cx231xx-reg.h"
index 9facc92c8dea53da1c516120b849a10433a60f95..3dc8ef004f8ba2b423cd0254a88d05ca7353e65d 100644 (file)
@@ -9,7 +9,7 @@ config DVB_USB_V2
          <file:Documentation/dvb/README.dvb-usb>.
 
          For a complete list of supported USB devices see the LinuxTV DVB Wiki:
-         <http://www.linuxtv.org/wiki/index.php/DVB_USB>
+         <https://linuxtv.org/wiki/index.php/DVB_USB>
 
          Say Y if you own a USB DVB device.
 
index ea3753653368d46a2f8f1a0017812dbe08a22c34..84f6de6fa07db183d94fca0ad6473fc85da34e11 100644 (file)
@@ -35,7 +35,7 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
 struct mxl111sf_demod_state {
        struct mxl111sf_state *mxl_state;
 
-       struct mxl111sf_demod_config *cfg;
+       const struct mxl111sf_demod_config *cfg;
 
        struct dvb_frontend fe;
 };
@@ -579,7 +579,7 @@ static struct dvb_frontend_ops mxl111sf_demod_ops = {
 };
 
 struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
-                                          struct mxl111sf_demod_config *cfg)
+                                  const struct mxl111sf_demod_config *cfg)
 {
        struct mxl111sf_demod_state *state = NULL;
 
index 0bd83e52669c143854ec2eea9636d8279251a185..7065aca81252cc6275bafa2e36f6d9f013340166 100644 (file)
@@ -35,11 +35,11 @@ struct mxl111sf_demod_config {
 #if IS_ENABLED(CONFIG_DVB_USB_MXL111SF)
 extern
 struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
-                                          struct mxl111sf_demod_config *cfg);
+                                  const struct mxl111sf_demod_config *cfg);
 #else
 static inline
 struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
-                                          struct mxl111sf_demod_config *cfg)
+                                  const struct mxl111sf_demod_config *cfg)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
index bec12b0e076b37e6a6d429550a63861f011cd33a..1710f9038d7500a59a3133ea03de2a5860f6984e 100644 (file)
@@ -288,9 +288,9 @@ static int mxl111sf_adap_fe_init(struct dvb_frontend *fe)
        err = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
 
        mxl_fail(err);
-       mxl111sf_enable_usb_output(state);
+       err = mxl111sf_enable_usb_output(state);
        mxl_fail(err);
-       mxl1x1sf_top_master_ctrl(state, 1);
+       err = mxl1x1sf_top_master_ctrl(state, 1);
        mxl_fail(err);
 
        if ((MXL111SF_GPIO_MOD_DVBT != adap_state->gpio_mode) &&
@@ -731,7 +731,7 @@ fail:
        return ret;
 }
 
-static struct mxl111sf_demod_config mxl_demod_config = {
+static const struct mxl111sf_demod_config mxl_demod_config = {
        .read_reg        = mxl111sf_read_reg,
        .write_reg       = mxl111sf_write_reg,
        .program_regs    = mxl111sf_ctrl_program_regs,
index 5a503a6bb8c5dc9f40b0a4b051db9d489d8ff92c..eb5787a3191e7afc31e69e6e9757297b745279c0 100644 (file)
@@ -181,11 +181,17 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                        goto err_mutex_unlock;
                } else if (msg[0].addr == 0x10) {
                        /* method 1 - integrated demod */
-                       req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
-                       req.index = CMD_DEMOD_RD | dev->page;
-                       req.size = msg[1].len;
-                       req.data = &msg[1].buf[0];
-                       ret = rtl28xxu_ctrl_msg(d, &req);
+                       if (msg[0].buf[0] == 0x00) {
+                               /* return demod page from driver cache */
+                               msg[1].buf[0] = dev->page;
+                               ret = 0;
+                       } else {
+                               req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
+                               req.index = CMD_DEMOD_RD | dev->page;
+                               req.size = msg[1].len;
+                               req.data = &msg[1].buf[0];
+                               ret = rtl28xxu_ctrl_msg(d, &req);
+                       }
                } else if (msg[0].len < 2) {
                        /* method 2 - old I2C */
                        req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
index 128eee61570d1bb53a7ace0a33dbde45fb2ce2ed..f03b0b70c9015b486fee657a8c10a67950a958a1 100644 (file)
@@ -9,7 +9,7 @@ config DVB_USB
          <file:Documentation/dvb/README.dvb-usb>.
 
          For a complete list of supported USB devices see the LinuxTV DVB Wiki:
-         <http://www.linuxtv.org/wiki/index.php/DVB_USB>
+         <https://linuxtv.org/wiki/index.php/DVB_USB>
 
          Say Y if you own a USB DVB device.
 
index ed0b3a87983e457782eac7a4976425edfc01f972..b58acd3fcd9918368b2eadac79d61a5f64d80b38 100644 (file)
@@ -21,7 +21,7 @@
 
 #include <linux/i2c.h>
 #include <media/soc_camera.h>
-#include <media/mt9v011.h>
+#include <media/i2c/mt9v011.h>
 #include <media/v4l2-clk.h>
 #include <media/v4l2-common.h>
 
@@ -322,7 +322,7 @@ int em28xx_detect_sensor(struct em28xx *dev)
 
 int em28xx_init_camera(struct em28xx *dev)
 {
-       char clk_name[V4L2_SUBDEV_NAME_SIZE];
+       char clk_name[V4L2_CLK_NAME_SIZE];
        struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus];
        struct i2c_adapter *adap = &dev->i2c_adap[dev->def_i2c_bus];
        struct em28xx_v4l2 *v4l2 = dev->v4l2;
index 394004607059bffaa28c62dbd84a5cc1e649b26b..a1b6ef5894a689a39c6597aa668db2d1d4115b33 100644 (file)
 #include <linux/i2c.h>
 #include <linux/usb.h>
 #include <media/tuner.h>
-#include <media/msp3400.h>
-#include <media/saa7115.h>
-#include <media/tvp5150.h>
-#include <media/tvaudio.h>
+#include <media/drv-intf/msp3400.h>
+#include <media/i2c/saa7115.h>
+#include <media/i2c/tvp5150.h>
+#include <media/i2c/tvaudio.h>
 #include <media/i2c-addr.h>
 #include <media/tveeprom.h>
 #include <media/v4l2-common.h>
@@ -1051,8 +1051,12 @@ struct em28xx_board em28xx_boards[] = {
        },
        [EM2870_BOARD_TERRATEC_XS_MT2060] = {
                .name         = "Terratec Cinergy T XS (MT2060)",
-               .valid        = EM28XX_BOARD_NOT_VALIDATED,
+               .xclk         = EM28XX_XCLK_IR_RC5_MODE |
+                               EM28XX_XCLK_FREQUENCY_12MHZ,
+               .i2c_speed    = EM28XX_I2C_CLK_WAIT_ENABLE,
                .tuner_type   = TUNER_ABSENT, /* MT2060 */
+               .has_dvb      = 1,
+               .tuner_gpio   = default_tuner_gpio,
        },
        [EM2870_BOARD_KWORLD_350U] = {
                .name         = "Kworld 350 U DVB-T",
@@ -2368,7 +2372,7 @@ struct usb_device_id em28xx_id_table[] = {
        { USB_DEVICE(0x0ccd, 0x0042),
                        .driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS },
        { USB_DEVICE(0x0ccd, 0x0043),
-                       .driver_info = EM2870_BOARD_TERRATEC_XS },
+                       .driver_info = EM2870_BOARD_TERRATEC_XS_MT2060 },
        { USB_DEVICE(0x0ccd, 0x008e),   /* Cinergy HTC USB XS Rev. 1 */
                        .driver_info = EM2884_BOARD_TERRATEC_HTC_USB_XS },
        { USB_DEVICE(0x0ccd, 0x00ac),   /* Cinergy HTC USB XS Rev. 2 */
@@ -2471,6 +2475,8 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM28178_BOARD_PCTV_461E },
        { USB_DEVICE(0x2013, 0x025f),
                        .driver_info = EM28178_BOARD_PCTV_292E },
+       { USB_DEVICE(0x2040, 0x0264), /* Hauppauge WinTV-soloHD */
+                       .driver_info = EM28178_BOARD_PCTV_292E },
        { USB_DEVICE(0x0413, 0x6f07),
                        .driver_info = EM2861_BOARD_LEADTEK_VC100 },
        { USB_DEVICE(0xeb1a, 0x8179),
index 357be76c7a5523e7e9ff0a11c7f70f1a35571a94..bf5c24467c65bec87b43c14b3f2552cb9dce6aab 100644 (file)
@@ -38,6 +38,7 @@
 #include "lgdt3305.h"
 #include "zl10353.h"
 #include "s5h1409.h"
+#include "mt2060.h"
 #include "mt352.h"
 #include "mt352_priv.h" /* FIXME */
 #include "tda1002x.h"
@@ -815,6 +816,10 @@ static struct zl10353_config em28xx_zl10353_no_i2c_gate_dev = {
        .parallel_ts = 1,
 };
 
+static struct mt2060_config em28xx_mt2060_config = {
+       .i2c_address = 0x60,
+};
+
 static struct qt1010_config em28xx_qt1010_config = {
        .i2c_address = 0x62
 };
@@ -1142,6 +1147,16 @@ static int em28xx_dvb_init(struct em28xx *dev)
                        goto out_free;
                }
                break;
+       case EM2870_BOARD_TERRATEC_XS_MT2060:
+               dvb->fe[0] = dvb_attach(zl10353_attach,
+                                               &em28xx_zl10353_no_i2c_gate_dev,
+                                               &dev->i2c_adap[dev->def_i2c_bus]);
+               if (dvb->fe[0] != NULL) {
+                       dvb_attach(mt2060_attach, dvb->fe[0],
+                                       &dev->i2c_adap[dev->def_i2c_bus],
+                                       &em28xx_mt2060_config, 1220);
+               }
+               break;
        case EM2870_BOARD_KWORLD_355U:
                dvb->fe[0] = dvb_attach(zl10353_attach,
                                           &em28xx_zl10353_no_i2c_gate_dev,
index e23c285b3108f7f687f57b7ec4389ef1195640b2..fe94c9225dd7f18ce413f56347551bc7de961688 100644 (file)
 
 /* ------------------------------------------------------------------ */
 
-static int vbi_queue_setup(struct vb2_queue *vq, const void *parg,
+static int vbi_queue_setup(struct vb2_queue *vq,
                           unsigned int *nbuffers, unsigned int *nplanes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct em28xx *dev = vb2_get_drv_priv(vq);
        struct em28xx_v4l2 *v4l2 = dev->v4l2;
-       unsigned long size;
+       unsigned long size = v4l2->vbi_width * v4l2->vbi_height * 2;
 
-       if (fmt)
-               size = fmt->fmt.pix.sizeimage;
-       else
-               size = v4l2->vbi_width * v4l2->vbi_height * 2;
-
-       if (0 == *nbuffers)
-               *nbuffers = 32;
        if (*nbuffers < 2)
                *nbuffers = 2;
-       if (*nbuffers > 32)
-               *nbuffers = 32;
+
+       if (*nplanes) {
+               if (sizes[0] < size)
+                       return -EINVAL;
+               size = sizes[0];
+       }
 
        *nplanes = 1;
        sizes[0] = size;
index 6a3cf342e087416fc4532a036a3ebcc58b2771bd..0e86ff423c499d196303da2999215e7454d3867f 100644 (file)
@@ -43,7 +43,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-event.h>
 #include <media/v4l2-clk.h>
-#include <media/msp3400.h>
+#include <media/drv-intf/msp3400.h>
 #include <media/tuner.h>
 
 #define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
@@ -438,7 +438,7 @@ static inline void finish_buffer(struct em28xx *dev,
                buf->vb.field = V4L2_FIELD_NONE;
        else
                buf->vb.field = V4L2_FIELD_INTERLACED;
-       v4l2_get_timestamp(&buf->vb.timestamp);
+       buf->vb.vb2_buf.timestamp = ktime_get_ns();
 
        vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
 }
@@ -871,30 +871,19 @@ static void res_free(struct em28xx *dev, enum v4l2_buf_type f_type)
        Videobuf2 operations
    ------------------------------------------------------------------*/
 
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
                       unsigned int *nbuffers, unsigned int *nplanes,
                       unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct em28xx *dev = vb2_get_drv_priv(vq);
        struct em28xx_v4l2 *v4l2 = dev->v4l2;
-       unsigned long size;
-
-       if (fmt)
-               size = fmt->fmt.pix.sizeimage;
-       else
-               size =
+       unsigned long size =
                    (v4l2->width * v4l2->height * v4l2->format->depth + 7) >> 3;
 
-       if (size == 0)
-               return -EINVAL;
-
-       if (0 == *nbuffers)
-               *nbuffers = 32;
-
+       if (*nplanes)
+               return sizes[0] < size ? -EINVAL : 0;
        *nplanes = 1;
        sizes[0] = size;
-
        return 0;
 }
 
index 76bf8ba372b3c6e661547a336a088e0c23655829..8ff066c977d9d3e88b3e32b05cfbd7c6974afaf4 100644 (file)
@@ -40,7 +40,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-fh.h>
-#include <media/ir-kbd-i2c.h>
+#include <media/i2c/ir-kbd-i2c.h>
 #include <media/rc-core.h>
 #include "tuner-xc2028.h"
 #include "xc5000.h"
index ae1cfa792c5891adaf32a15ec169ead42be874bb..05b1126f263ef234015261b010439f9fc6e75bc8 100644 (file)
@@ -466,7 +466,7 @@ static struct go7007_buffer *frame_boundary(struct go7007 *go, struct go7007_buf
        else
                go7007_set_motion_regions(go, vb, 0);
 
-       v4l2_get_timestamp(&vb->vb.timestamp);
+       vb->vb.vb2_buf.timestamp = ktime_get_ns();
        vb_tmp = vb;
        spin_lock(&go->spinlock);
        list_del(&vb->list);
index 4857c467e76cd169e9a626301a94105289f2b461..3dbf14c85c5c847ef8544ec78b96936b76677fd4 100644 (file)
@@ -23,9 +23,9 @@
 #include <linux/usb.h>
 #include <linux/i2c.h>
 #include <asm/byteorder.h>
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
 #include <media/tuner.h>
-#include <media/uda1342.h>
+#include <media/i2c/uda1342.h>
 
 #include "go7007-priv.h"
 
@@ -1289,7 +1289,7 @@ static int go7007_usb_probe(struct usb_interface *intf,
 
        /* Allocate the URBs and buffers for receiving the audio stream */
        if ((board->flags & GO7007_USB_EZUSB) &&
-           (board->flags & GO7007_BOARD_HAS_AUDIO)) {
+           (board->main_info.flags & GO7007_BOARD_HAS_AUDIO)) {
                for (i = 0; i < 8; ++i) {
                        usb->audio_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
                        if (usb->audio_urbs[i] == NULL)
index f3d187db936864d7d8bf713229becc19564c813c..358c1c186d0335aaad237354dd679cd22b7dccf5 100644 (file)
@@ -30,7 +30,7 @@
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-event.h>
 #include <media/videobuf2-vmalloc.h>
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
 
 #include "go7007-priv.h"
 
@@ -369,7 +369,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 }
 
 static int go7007_queue_setup(struct vb2_queue *q,
-               const void *parg,
                unsigned int *num_buffers, unsigned int *num_planes,
                unsigned int sizes[], void *alloc_ctxs[])
 {
index 146071b8e11618a12b480db88ee946c5af11e87b..bfff1d1c70ab0149b79bea42752140e292a9fe19 100644 (file)
@@ -1491,8 +1491,13 @@ static void sd_set_streamparm(struct gspca_dev *gspca_dev,
        struct v4l2_fract *tpf = &cp->timeperframe;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       /* Set requested framerate */
-       sd->frame_rate = tpf->denominator / tpf->numerator;
+       if (tpf->numerator == 0 || tpf->denominator == 0)
+               /* Set default framerate */
+               sd->frame_rate = 30;
+       else
+               /* Set requested framerate */
+               sd->frame_rate = tpf->denominator / tpf->numerator;
+
        if (gspca_dev->streaming)
                set_frame_rate(gspca_dev);
 
index c70ff406b07ac55cf6f48b2741930b39afa2ca2d..c028a5c2438ed19560c5416e4c39b56ad3e3da5a 100644 (file)
@@ -4802,7 +4802,11 @@ static void sd_set_streamparm(struct gspca_dev *gspca_dev,
        struct v4l2_fract *tpf = &cp->timeperframe;
        int fr, i;
 
-       sd->framerate = tpf->denominator / tpf->numerator;
+       if (tpf->numerator == 0 || tpf->denominator == 0)
+               sd->framerate = 30;
+       else
+               sd->framerate = tpf->denominator / tpf->numerator;
+
        if (gspca_dev->streaming)
                setframerate(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure));
 
index 0fe5cb2c260c2f771484d99bf25809cc23943ffb..9e700caf0d663f77b4a9c927de0bb2e32b368c6d 100644 (file)
@@ -526,7 +526,7 @@ static void hackrf_urb_complete_in(struct urb *urb)
                    urb->transfer_buffer, len);
        vb2_set_plane_payload(&buffer->vb.vb2_buf, 0, len);
        buffer->vb.sequence = dev->sequence++;
-       v4l2_get_timestamp(&buffer->vb.timestamp);
+       buffer->vb.vb2_buf.timestamp = ktime_get_ns();
        vb2_buffer_done(&buffer->vb.vb2_buf, VB2_BUF_STATE_DONE);
 exit_usb_submit_urb:
        usb_submit_urb(urb, GFP_ATOMIC);
@@ -571,7 +571,7 @@ static void hackrf_urb_complete_out(struct urb *urb)
                           vb2_plane_vaddr(&buffer->vb.vb2_buf, 0), len);
        urb->actual_length = len;
        buffer->vb.sequence = dev->sequence++;
-       v4l2_get_timestamp(&buffer->vb.timestamp);
+       buffer->vb.vb2_buf.timestamp = ktime_get_ns();
        vb2_buffer_done(&buffer->vb.vb2_buf, VB2_BUF_STATE_DONE);
 exit_usb_submit_urb:
        usb_submit_urb(urb, GFP_ATOMIC);
@@ -759,7 +759,7 @@ static void hackrf_return_all_buffers(struct vb2_queue *vq,
 }
 
 static int hackrf_queue_setup(struct vb2_queue *vq,
-               const void *parg, unsigned int *nbuffers,
+               unsigned int *nbuffers,
                unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
 {
        struct hackrf_dev *dev = vb2_get_drv_priv(vq);
index d8d8c0f519fc2484edc04a4aa07f29154957ad9b..7dee22deebf3d8b5c85ca95a39e7cb30935b1885 100644 (file)
@@ -642,7 +642,7 @@ static int vidioc_s_dv_timings(struct file *file, void *_fh,
        if (dev->status != STATUS_IDLE)
                return -EBUSY;
        for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++)
-               if (v4l2_match_dv_timings(timings, hdpvr_dv_timings + i, 0))
+               if (v4l2_match_dv_timings(timings, hdpvr_dv_timings + i, 0, false))
                        break;
        if (i == ARRAY_SIZE(hdpvr_dv_timings))
                return -EINVAL;
index a3194304182d03b453959d4c068d3ecdc422afac..78e815441f95141af23c2787523f5aad7fac5610 100644 (file)
@@ -17,7 +17,7 @@
 
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
-#include <media/ir-kbd-i2c.h>
+#include <media/i2c/ir-kbd-i2c.h>
 
 #define HDPVR_MAX 8
 #define HDPVR_I2C_MAX_SIZE 128
index e06a21a4fbd9a30bdb3c86f4cfb41f9de3833ddd..c104315fdc17217f4fad27b6c86e017fa126b7b2 100644 (file)
@@ -616,7 +616,6 @@ static int msi2500_querycap(struct file *file, void *fh,
 
 /* Videobuf2 operations */
 static int msi2500_queue_setup(struct vb2_queue *vq,
-                              const void *parg,
                               unsigned int *nbuffers,
                               unsigned int *nplanes, unsigned int sizes[],
                               void *alloc_ctxs[])
index 45276c628482e023f6009c729a90928289f18c16..5f953d837bf1c67c790c5f6821f9423db90f5a3d 100644 (file)
@@ -23,7 +23,7 @@
 #include "pvrusb2-hdw-internal.h"
 #include "pvrusb2-debug.h"
 #include <linux/videodev2.h>
-#include <media/msp3400.h>
+#include <media/drv-intf/msp3400.h>
 #include <media/v4l2-common.h>
 
 
index 1a81aa70509b014757aa223f6254733ade8e4699..7d675fae1846ac6c0532056fec4c6ac649ed9864 100644 (file)
@@ -32,7 +32,7 @@
 
 #include "pvrusb2-hdw-internal.h"
 #include "pvrusb2-debug.h"
-#include <media/cx25840.h>
+#include <media/drv-intf/cx25840.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <linux/errno.h>
index 1f9c02801cee23fcb6b8c2fabca9c4b31b391f92..60141b16d731059b905bc1690b3c6a1b8bd5d1d3 100644 (file)
@@ -39,8 +39,8 @@
 #include "pvrusb2-hdw.h"
 #include "pvrusb2-io.h"
 #include <media/v4l2-device.h>
-#include <media/cx2341x.h>
-#include <media/ir-kbd-i2c.h>
+#include <media/drv-intf/cx2341x.h>
+#include <media/i2c/ir-kbd-i2c.h>
 #include "pvrusb2-devattr.h"
 
 /* Legal values for PVR2_CID_HSM */
index 4baa9d632a4e6cfa8c254b97b3207040736f0004..14321d0a183312ce79ddf13d6117368ef069c9a3 100644 (file)
@@ -20,7 +20,7 @@
 
 #include <linux/i2c.h>
 #include <linux/module.h>
-#include <media/ir-kbd-i2c.h>
+#include <media/i2c/ir-kbd-i2c.h>
 #include "pvrusb2-i2c-core.h"
 #include "pvrusb2-hdw-internal.h"
 #include "pvrusb2-debug.h"
index 1c5f85bf7ed4b49c8c13d0bbae3869928892e698..81f788b7b24297aeb492b70e65c725f599db6b43 100644 (file)
@@ -628,6 +628,7 @@ static int pvr2_g_ext_ctrls(struct file *file, void *priv,
        struct pvr2_v4l2_fh *fh = file->private_data;
        struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
        struct v4l2_ext_control *ctrl;
+       struct pvr2_ctrl *cptr;
        unsigned int idx;
        int val;
        int ret;
@@ -635,8 +636,15 @@ static int pvr2_g_ext_ctrls(struct file *file, void *priv,
        ret = 0;
        for (idx = 0; idx < ctls->count; idx++) {
                ctrl = ctls->controls + idx;
-               ret = pvr2_ctrl_get_value(
-                               pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id), &val);
+               cptr = pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id);
+               if (cptr) {
+                       if (ctls->which == V4L2_CTRL_WHICH_DEF_VAL)
+                               pvr2_ctrl_get_def(cptr, &val);
+                       else
+                               ret = pvr2_ctrl_get_value(cptr, &val);
+               } else
+                       ret = -EINVAL;
+
                if (ret) {
                        ctls->error_idx = idx;
                        return ret;
@@ -658,6 +666,10 @@ static int pvr2_s_ext_ctrls(struct file *file, void *priv,
        unsigned int idx;
        int ret;
 
+       /* Default value cannot be changed */
+       if (ctls->which == V4L2_CTRL_WHICH_DEF_VAL)
+               return -EINVAL;
+
        ret = 0;
        for (idx = 0; idx < ctls->count; idx++) {
                ctrl = ctls->controls + idx;
index 139b3974053407a894dc0e3ea2dd53f549f1b708..105123ab36aa10574738966c2b1574d85c324654 100644 (file)
@@ -35,7 +35,7 @@
 #include "pvrusb2-debug.h"
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
 #include <linux/errno.h>
 
 struct routing_scheme {
index b79c36fd8cd24c66d441c5b807cb65a65b6673f6..086cf1c7bd7d19e0015950bd6af0d02c311bf090 100644 (file)
@@ -316,8 +316,7 @@ static void pwc_isoc_handler(struct urb *urb)
                        struct pwc_frame_buf *fbuf = pdev->fill_buf;
 
                        if (pdev->vsync == 1) {
-                               v4l2_get_timestamp(
-                                       &fbuf->vb.timestamp);
+                               fbuf->vb.vb2_buf.timestamp = ktime_get_ns();
                                pdev->vsync = 2;
                        }
 
@@ -571,7 +570,7 @@ static void pwc_video_release(struct v4l2_device *v)
 /***************************************************************************/
 /* Videobuf2 operations */
 
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
                                unsigned int *nbuffers, unsigned int *nplanes,
                                unsigned int sizes[], void *alloc_ctxs[])
 {
index e7acb12ad21d1e5ae4fe69c4d6eb2cee7b8ddc73..9acdaa3716fbea1503ec90791fa09ad15d750da5 100644 (file)
@@ -574,7 +574,7 @@ static void s2255_got_frame(struct s2255_vc *vc, int jpgsize)
        buf = list_entry(vc->buf_list.next,
                         struct s2255_buffer, list);
        list_del(&buf->list);
-       v4l2_get_timestamp(&buf->vb.timestamp);
+       buf->vb.vb2_buf.timestamp = ktime_get_ns();
        buf->vb.field = vc->field;
        buf->vb.sequence = vc->frame_count;
        spin_unlock_irqrestore(&vc->qlock, flags);
@@ -660,7 +660,7 @@ static void s2255_fillbuff(struct s2255_vc *vc,
    Videobuf operations
    ------------------------------------------------------------------*/
 
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
                       unsigned int *nbuffers, unsigned int *nplanes,
                       unsigned int sizes[], void *alloc_ctxs[])
 {
index 1b6836f15370dab04251c0d36c8931138a94dd81..bc029478065a0f9c029dd024fca1ef4c0b6788fe 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/usb.h>
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
 
 #include "stk1160.h"
 #include "stk1160-reg.h"
index 0bd34f1e7fa95f0c7aad7b6e2a1b466cb2ddf27c..77131fd614a5e763e4fcefedfed81a1154889b00 100644 (file)
@@ -33,7 +33,7 @@
 #include <media/v4l2-event.h>
 #include <media/videobuf2-vmalloc.h>
 
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
 
 #include "stk1160.h"
 #include "stk1160-reg.h"
@@ -664,7 +664,7 @@ static const struct v4l2_ioctl_ops stk1160_ioctl_ops = {
 /*
  * Videobuf2 operations
  */
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
                                unsigned int *nbuffers, unsigned int *nplanes,
                                unsigned int sizes[], void *alloc_ctxs[])
 {
index 75654e676e80c9f9d716830c2802e20281305a18..46191d5262eb07f3efb9fdf87c75c0665abe6687 100644 (file)
@@ -99,7 +99,7 @@ void stk1160_buffer_done(struct stk1160 *dev)
        buf->vb.sequence = dev->sequence++;
        buf->vb.field = V4L2_FIELD_INTERLACED;
        buf->vb.vb2_buf.planes[0].bytesused = buf->bytesused;
-       v4l2_get_timestamp(&buf->vb.timestamp);
+       buf->vb.vb2_buf.timestamp = ktime_get_ns();
 
        vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->bytesused);
        vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
index 2e8c3afe4ec4f2864d0dd34c3db36ff3fb2cd331..8902ee36bc942049d019b545a1c876b674111d79 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/slab.h>
 #include <media/v4l2-common.h>
 #include <media/tuner.h>
-#include <media/tvaudio.h>
+#include <media/i2c/tvaudio.h>
 #include <media/i2c-addr.h>
 #include <media/rc-map.h>
 
index a5de46f04247f82178d60366d8148a4140f7780e..4e36e24cb3a6d758f722250e47c65d2dce3e988b 100644 (file)
@@ -1606,7 +1606,7 @@ static int fe_send_command(struct dvb_frontend* fe, const u8 command,
        return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result);
 }
 
-static struct ttusbdecfe_config fe_config = {
+static const struct ttusbdecfe_config fe_config = {
        .send_command = fe_send_command
 };
 
index e645c9df2d9401919e82d875f73c37389b09f73b..4ebb33943f9a03a5922c408cfef628847a1053d7 100644 (file)
@@ -322,7 +322,7 @@ static void usbtv_image_chunk(struct usbtv *usbtv, __be32 *chunk)
 
                buf->vb.field = V4L2_FIELD_INTERLACED;
                buf->vb.sequence = usbtv->sequence++;
-               v4l2_get_timestamp(&buf->vb.timestamp);
+               buf->vb.vb2_buf.timestamp = ktime_get_ns();
                vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size);
                vb2_buffer_done(&buf->vb.vb2_buf, state);
                list_del(&buf->list);
@@ -599,19 +599,18 @@ static struct v4l2_file_operations usbtv_fops = {
 };
 
 static int usbtv_queue_setup(struct vb2_queue *vq,
-       const void *parg, unsigned int *nbuffers,
+       unsigned int *nbuffers,
        unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct usbtv *usbtv = vb2_get_drv_priv(vq);
        unsigned size = USBTV_CHUNK * usbtv->n_chunks * 2 * sizeof(u32);
 
        if (vq->num_buffers + *nbuffers < 2)
                *nbuffers = 2 - vq->num_buffers;
+       if (*nplanes)
+               return sizes[0] < size ? -EINVAL : 0;
        *nplanes = 1;
-       if (fmt && fmt->fmt.pix.sizeimage < size)
-               return -EINVAL;
-       sizes[0] = fmt ? fmt->fmt.pix.sizeimage : size;
+       sizes[0] = size;
 
        return 0;
 }
index dc3b4d5155c5e391724a8df14abe4cbde3c2c2fb..1ea04e75fb36b0c4416a0e99167342541c52c112 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
 
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
 #include <media/v4l2-common.h>
 #include <media/tuner.h>
 
index b693206f66dd3d05462aa59f88bd6445aaed88f4..de9ff3bb8edd8e7a94826bf58895d009dc420038 100644 (file)
@@ -59,7 +59,7 @@
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
 
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-event.h>
@@ -1461,11 +1461,32 @@ static int usbvision_probe(struct usb_interface *intf,
        printk(KERN_INFO "%s: %s found\n", __func__,
                                usbvision_device_data[model].model_string);
 
+       /*
+        * this is a security check.
+        * an exploit using an incorrect bInterfaceNumber is known
+        */
+       if (ifnum >= USB_MAXINTERFACES || !dev->actconfig->interface[ifnum])
+               return -ENODEV;
+
        if (usbvision_device_data[model].interface >= 0)
                interface = &dev->actconfig->interface[usbvision_device_data[model].interface]->altsetting[0];
-       else
+       else if (ifnum < dev->actconfig->desc.bNumInterfaces)
                interface = &dev->actconfig->interface[ifnum]->altsetting[0];
+       else {
+               dev_err(&intf->dev, "interface %d is invalid, max is %d\n",
+                   ifnum, dev->actconfig->desc.bNumInterfaces - 1);
+               ret = -ENODEV;
+               goto err_usb;
+       }
+
+       if (interface->desc.bNumEndpoints < 2) {
+               dev_err(&intf->dev, "interface %d has %d endpoints, but must"
+                   " have minimum 2\n", ifnum, interface->desc.bNumEndpoints);
+               ret = -ENODEV;
+               goto err_usb;
+       }
        endpoint = &interface->endpoint[1].desc;
+
        if (!usb_endpoint_xfer_isoc(endpoint)) {
                dev_err(&intf->dev, "%s: interface %d. has non-ISO endpoint!\n",
                    __func__, ifnum);
index 3e59b288b8a89cc70d9b4c086c5784e922ff1e65..c2ee6e39fd0ca44708ed4e441275f5fbe0defb1e 100644 (file)
@@ -227,7 +227,8 @@ static struct uvc_control_info uvc_ctrls[] = {
                .size           = 4,
                .flags          = UVC_CTRL_FLAG_SET_CUR
                                | UVC_CTRL_FLAG_GET_RANGE
-                               | UVC_CTRL_FLAG_RESTORE,
+                               | UVC_CTRL_FLAG_RESTORE
+                               | UVC_CTRL_FLAG_AUTO_UPDATE,
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
index d11fd6ac2df050369a06641ade6e91fd2fddc649..39abbafad7966a50868ff4c9fe32e097045142d9 100644 (file)
@@ -2540,7 +2540,8 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_FORCE_Y8 },
        /* Generic USB Video Class */
-       { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
+       { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) },
+       { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) },
        {}
 };
 
index cfb868a48b5f02ad4e76c11072b4ce0b33a2890e..54394722756f16211984b0150d9461c9014d0a5c 100644 (file)
@@ -69,23 +69,19 @@ static void uvc_queue_return_buffers(struct uvc_video_queue *queue,
  * videobuf2 queue operations
  */
 
-static int uvc_queue_setup(struct vb2_queue *vq, const void *parg,
+static int uvc_queue_setup(struct vb2_queue *vq,
                           unsigned int *nbuffers, unsigned int *nplanes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
-       const struct v4l2_format *fmt = parg;
        struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
        struct uvc_streaming *stream = uvc_queue_to_stream(queue);
+       unsigned size = stream->ctrl.dwMaxVideoFrameSize;
 
        /* Make sure the image size is large enough. */
-       if (fmt && fmt->fmt.pix.sizeimage < stream->ctrl.dwMaxVideoFrameSize)
-               return -EINVAL;
-
+       if (*nplanes)
+               return sizes[0] < size ? -EINVAL : 0;
        *nplanes = 1;
-
-       sizes[0] = fmt ? fmt->fmt.pix.sizeimage
-                : stream->ctrl.dwMaxVideoFrameSize;
-
+       sizes[0] = size;
        return 0;
 }
 
index 2764f43607c146a454a4bcbd89e6d5edc472acfc..d7723ce772b3af6b43804a4996656f9b7b58bc34 100644 (file)
@@ -983,6 +983,22 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh,
        unsigned int i;
        int ret;
 
+       if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL) {
+               for (i = 0; i < ctrls->count; ++ctrl, ++i) {
+                       struct v4l2_queryctrl qc = { .id = ctrl->id };
+
+                       ret = uvc_query_v4l2_ctrl(chain, &qc);
+                       if (ret < 0) {
+                               ctrls->error_idx = i;
+                               return ret;
+                       }
+
+                       ctrl->value = qc.default_value;
+               }
+
+               return 0;
+       }
+
        ret = uvc_ctrl_begin(chain);
        if (ret < 0)
                return ret;
@@ -1010,6 +1026,10 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle,
        unsigned int i;
        int ret;
 
+       /* Default value cannot be changed */
+       if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL)
+               return -EINVAL;
+
        ret = uvc_ctrl_begin(chain);
        if (ret < 0)
                return ret;
index 2b276ab7764fc37ec0a2fc0cd5a31f8ac966a7d9..075a0fe774857ca65773432e9c092f2607d93549 100644 (file)
@@ -694,22 +694,19 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
                ts.tv_nsec -= NSEC_PER_SEC;
        }
 
-       uvc_trace(UVC_TRACE_CLOCK, "%s: SOF %u.%06llu y %llu ts %lu.%06lu "
-                 "buf ts %lu.%06lu (x1 %u/%u/%u x2 %u/%u/%u y1 %u y2 %u)\n",
+       uvc_trace(UVC_TRACE_CLOCK, "%s: SOF %u.%06llu y %llu ts %llu "
+                 "buf ts %llu (x1 %u/%u/%u x2 %u/%u/%u y1 %u y2 %u)\n",
                  stream->dev->name,
                  sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536),
-                 y, ts.tv_sec, ts.tv_nsec / NSEC_PER_USEC,
-                 vbuf->timestamp.tv_sec,
-                 (unsigned long)vbuf->timestamp.tv_usec,
+                 y, timespec_to_ns(&ts), vbuf->vb2_buf.timestamp,
                  x1, first->host_sof, first->dev_sof,
                  x2, last->host_sof, last->dev_sof, y1, y2);
 
        /* Update the V4L2 buffer. */
-       vbuf->timestamp.tv_sec = ts.tv_sec;
-       vbuf->timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+       vbuf->vb2_buf.timestamp = timespec_to_ns(&ts);
 
 done:
-       spin_unlock_irqrestore(&stream->clock.lock, flags);
+       spin_unlock_irqrestore(&clock->lock, flags);
 }
 
 /* ------------------------------------------------------------------------
@@ -1034,9 +1031,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
 
                buf->buf.field = V4L2_FIELD_NONE;
                buf->buf.sequence = stream->sequence;
-               buf->buf.timestamp.tv_sec = ts.tv_sec;
-               buf->buf.timestamp.tv_usec =
-                       ts.tv_nsec / NSEC_PER_USEC;
+               buf->buf.vb2_buf.timestamp = timespec_to_ns(&ts);
 
                /* TODO: Handle PTS and SCR. */
                buf->state = UVC_BUF_STATE_ACTIVE;
index 34e416a554f64294e31c5e8c3f967cf94672b7ac..297e10e698986badb620f1edff98315f41ad4cee 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 
@@ -39,6 +40,7 @@ struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id)
 {
        struct v4l2_clk *clk;
        struct clk *ccf_clk = clk_get(dev, id);
+       char clk_name[V4L2_CLK_NAME_SIZE];
 
        if (PTR_ERR(ccf_clk) == -EPROBE_DEFER)
                return ERR_PTR(-EPROBE_DEFER);
@@ -57,6 +59,13 @@ struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id)
        mutex_lock(&clk_lock);
        clk = v4l2_clk_find(dev_name(dev));
 
+       /* if dev_name is not found, try use the OF name to find again  */
+       if (PTR_ERR(clk) == -ENODEV && dev->of_node) {
+               v4l2_clk_name_of(clk_name, sizeof(clk_name),
+                                of_node_full_name(dev->of_node));
+               clk = v4l2_clk_find(clk_name);
+       }
+
        if (!IS_ERR(clk))
                atomic_inc(&clk->use_count);
        mutex_unlock(&clk_lock);
index 327e83ac2469ecad9d7e86aa9ca3c5c0c72cf572..8fd84a67478a77423cc6bc051e0654276561502c 100644 (file)
@@ -630,7 +630,7 @@ static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __
 }
 
 struct v4l2_ext_controls32 {
-       __u32 ctrl_class;
+       __u32 which;
        __u32 count;
        __u32 error_idx;
        __u32 reserved[2];
@@ -673,7 +673,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
        compat_caddr_t p;
 
        if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
-               get_user(kp->ctrl_class, &up->ctrl_class) ||
+               get_user(kp->which, &up->which) ||
                get_user(kp->count, &up->count) ||
                get_user(kp->error_idx, &up->error_idx) ||
                copy_from_user(kp->reserved, up->reserved,
@@ -723,7 +723,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
        compat_caddr_t p;
 
        if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
-               put_user(kp->ctrl_class, &up->ctrl_class) ||
+               put_user(kp->which, &up->which) ||
                put_user(kp->count, &up->count) ||
                put_user(kp->error_idx, &up->error_idx) ||
                copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
index 4a1d9fdd14bb1595ff86eb7b72d56b9d507b6128..c9d5537b6af7a4cc32de8270617237450c47d207 100644 (file)
@@ -1491,6 +1491,17 @@ static int new_to_user(struct v4l2_ext_control *c,
        return ptr_to_user(c, ctrl, ctrl->p_new);
 }
 
+/* Helper function: copy the initial control value back to the caller */
+static int def_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
+{
+       int idx;
+
+       for (idx = 0; idx < ctrl->elems; idx++)
+               ctrl->type_ops->init(ctrl, idx, ctrl->p_new);
+
+       return ptr_to_user(c, ctrl, ctrl->p_new);
+}
+
 /* Helper function: copy the caller-provider value to the given control value */
 static int user_to_ptr(struct v4l2_ext_control *c,
                       struct v4l2_ctrl *ctrl,
@@ -1762,7 +1773,7 @@ static struct v4l2_ctrl_ref *find_private_ref(
        list_for_each_entry(ref, &hdl->ctrl_refs, node) {
                /* Search for private user controls that are compatible with
                   VIDIOC_G/S_CTRL. */
-               if (V4L2_CTRL_ID2CLASS(ref->ctrl->id) == V4L2_CTRL_CLASS_USER &&
+               if (V4L2_CTRL_ID2WHICH(ref->ctrl->id) == V4L2_CTRL_CLASS_USER &&
                    V4L2_CTRL_DRIVER_PRIV(ref->ctrl->id)) {
                        if (!ref->ctrl->is_int)
                                continue;
@@ -1831,7 +1842,7 @@ static int handler_new_ref(struct v4l2_ctrl_handler *hdl,
        struct v4l2_ctrl_ref *ref;
        struct v4l2_ctrl_ref *new_ref;
        u32 id = ctrl->id;
-       u32 class_ctrl = V4L2_CTRL_ID2CLASS(id) | 1;
+       u32 class_ctrl = V4L2_CTRL_ID2WHICH(id) | 1;
        int bucket = id % hdl->nr_of_buckets;   /* which bucket to use */
 
        /*
@@ -2253,9 +2264,9 @@ EXPORT_SYMBOL(v4l2_ctrl_add_handler);
 
 bool v4l2_ctrl_radio_filter(const struct v4l2_ctrl *ctrl)
 {
-       if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_FM_TX)
+       if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_TX)
                return true;
-       if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_FM_RX)
+       if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_RX)
                return true;
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -2710,7 +2721,9 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
 
                cs->error_idx = i;
 
-               if (cs->ctrl_class && V4L2_CTRL_ID2CLASS(id) != cs->ctrl_class)
+               if (cs->which &&
+                   cs->which != V4L2_CTRL_WHICH_DEF_VAL &&
+                   V4L2_CTRL_ID2WHICH(id) != cs->which)
                        return -EINVAL;
 
                /* Old-style private controls are not allowed for
@@ -2787,11 +2800,11 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
 /* Handles the corner case where cs->count == 0. It checks whether the
    specified control class exists. If that class ID is 0, then it checks
    whether there are any controls at all. */
-static int class_check(struct v4l2_ctrl_handler *hdl, u32 ctrl_class)
+static int class_check(struct v4l2_ctrl_handler *hdl, u32 which)
 {
-       if (ctrl_class == 0)
+       if (which == 0 || which == V4L2_CTRL_WHICH_DEF_VAL)
                return list_empty(&hdl->ctrl_refs) ? -EINVAL : 0;
-       return find_ref_lock(hdl, ctrl_class | 1) ? 0 : -EINVAL;
+       return find_ref_lock(hdl, which | 1) ? 0 : -EINVAL;
 }
 
 
@@ -2803,15 +2816,18 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
        struct v4l2_ctrl_helper *helpers = helper;
        int ret;
        int i, j;
+       bool def_value;
+
+       def_value = (cs->which == V4L2_CTRL_WHICH_DEF_VAL);
 
        cs->error_idx = cs->count;
-       cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
+       cs->which = V4L2_CTRL_ID2WHICH(cs->which);
 
        if (hdl == NULL)
                return -EINVAL;
 
        if (cs->count == 0)
-               return class_check(hdl, cs->ctrl_class);
+               return class_check(hdl, cs->which);
 
        if (cs->count > ARRAY_SIZE(helper)) {
                helpers = kmalloc_array(cs->count, sizeof(helper[0]),
@@ -2829,9 +2845,11 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
 
        for (i = 0; !ret && i < cs->count; i++) {
                int (*ctrl_to_user)(struct v4l2_ext_control *c,
-                                   struct v4l2_ctrl *ctrl) = cur_to_user;
+                                   struct v4l2_ctrl *ctrl);
                struct v4l2_ctrl *master;
 
+               ctrl_to_user = def_value ? def_to_user : cur_to_user;
+
                if (helpers[i].mref == NULL)
                        continue;
 
@@ -2841,8 +2859,9 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
                v4l2_ctrl_lock(master);
 
                /* g_volatile_ctrl will update the new control values */
-               if ((master->flags & V4L2_CTRL_FLAG_VOLATILE) ||
-                       (master->has_volatiles && !is_cur_manual(master))) {
+               if (!def_value &&
+                   ((master->flags & V4L2_CTRL_FLAG_VOLATILE) ||
+                   (master->has_volatiles && !is_cur_manual(master)))) {
                        for (j = 0; j < master->ncontrols; j++)
                                cur_to_new(master->cluster[j]);
                        ret = call_op(master, g_volatile_ctrl);
@@ -3064,13 +3083,18 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
        int ret;
 
        cs->error_idx = cs->count;
-       cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
+
+       /* Default value cannot be changed */
+       if (cs->which == V4L2_CTRL_WHICH_DEF_VAL)
+               return -EINVAL;
+
+       cs->which = V4L2_CTRL_ID2WHICH(cs->which);
 
        if (hdl == NULL)
                return -EINVAL;
 
        if (cs->count == 0)
-               return class_check(hdl, cs->ctrl_class);
+               return class_check(hdl, cs->which);
 
        if (cs->count > ARRAY_SIZE(helper)) {
                helpers = kmalloc_array(cs->count, sizeof(helper[0]),
@@ -3300,7 +3324,8 @@ EXPORT_SYMBOL(v4l2_ctrl_notify);
 int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
                        s64 min, s64 max, u64 step, s64 def)
 {
-       bool changed;
+       bool value_changed;
+       bool range_changed = false;
        int ret;
 
        lockdep_assert_held(ctrl->handler->lock);
@@ -3324,10 +3349,14 @@ int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
        default:
                return -EINVAL;
        }
-       ctrl->minimum = min;
-       ctrl->maximum = max;
-       ctrl->step = step;
-       ctrl->default_value = def;
+       if ((ctrl->minimum != min) || (ctrl->maximum != max) ||
+               (ctrl->step != step) || ctrl->default_value != def) {
+               range_changed = true;
+               ctrl->minimum = min;
+               ctrl->maximum = max;
+               ctrl->step = step;
+               ctrl->default_value = def;
+       }
        cur_to_new(ctrl);
        if (validate_new(ctrl, ctrl->p_new)) {
                if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
@@ -3337,12 +3366,12 @@ int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
        }
 
        if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
-               changed = *ctrl->p_new.p_s64 != *ctrl->p_cur.p_s64;
+               value_changed = *ctrl->p_new.p_s64 != *ctrl->p_cur.p_s64;
        else
-               changed = *ctrl->p_new.p_s32 != *ctrl->p_cur.p_s32;
-       if (changed)
+               value_changed = *ctrl->p_new.p_s32 != *ctrl->p_cur.p_s32;
+       if (value_changed)
                ret = set_ctrl(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
-       else
+       else if (range_changed)
                send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
        return ret;
 }
index 5b0a30b9252be2a205fcef2feecaf6fd1f3e57f6..7129e438f29e776fa7ff2a72a0ee4873ababdc94 100644 (file)
@@ -118,11 +118,20 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
                if (sd->flags & V4L2_SUBDEV_FL_IS_I2C) {
                        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-                       /* We need to unregister the i2c client explicitly.
-                          We cannot rely on i2c_del_adapter to always
-                          unregister clients for us, since if the i2c bus
-                          is a platform bus, then it is never deleted. */
-                       if (client)
+                       /*
+                        * We need to unregister the i2c client
+                        * explicitly. We cannot rely on
+                        * i2c_del_adapter to always unregister
+                        * clients for us, since if the i2c bus is a
+                        * platform bus, then it is never deleted.
+                        *
+                        * Device tree or ACPI based devices must not
+                        * be unregistered as they have not been
+                        * registered by us, and would not be
+                        * re-created by just probing the V4L2 driver.
+                        */
+                       if (client &&
+                           !client->dev.of_node && !client->dev.fwnode)
                                i2c_unregister_device(client);
                        continue;
                }
@@ -131,7 +140,7 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
                if (sd->flags & V4L2_SUBDEV_FL_IS_SPI) {
                        struct spi_device *spi = v4l2_get_subdevdata(sd);
 
-                       if (spi)
+                       if (spi && !spi->dev.of_node && !spi->dev.fwnode)
                                spi_unregister_device(spi);
                        continue;
                }
index 6a83d61916840347387f8fa454bbe18e1c3d6f57..ec258b73001a26a96dcdb56d8c76e64b5762f1d9 100644 (file)
@@ -209,8 +209,13 @@ bool v4l2_find_dv_timings_cap(struct v4l2_dv_timings *t,
                if (v4l2_valid_dv_timings(v4l2_dv_timings_presets + i, cap,
                                          fnc, fnc_handle) &&
                    v4l2_match_dv_timings(t, v4l2_dv_timings_presets + i,
-                                         pclock_delta)) {
+                                         pclock_delta, false)) {
+                       u32 flags = t->bt.flags & V4L2_DV_FL_REDUCED_FPS;
+
                        *t = v4l2_dv_timings_presets[i];
+                       if (can_reduce_fps(&t->bt))
+                               t->bt.flags |= flags;
+
                        return true;
                }
        }
@@ -223,12 +228,14 @@ EXPORT_SYMBOL_GPL(v4l2_find_dv_timings_cap);
  * @t1 - compare this v4l2_dv_timings struct...
  * @t2 - with this struct.
  * @pclock_delta - the allowed pixelclock deviation.
+ * @match_reduced_fps - if true, then fail if V4L2_DV_FL_REDUCED_FPS does not
+ * match.
  *
  * Compare t1 with t2 with a given margin of error for the pixelclock.
  */
 bool v4l2_match_dv_timings(const struct v4l2_dv_timings *t1,
                           const struct v4l2_dv_timings *t2,
-                          unsigned pclock_delta)
+                          unsigned pclock_delta, bool match_reduced_fps)
 {
        if (t1->type != t2->type || t1->type != V4L2_DV_BT_656_1120)
                return false;
@@ -239,9 +246,14 @@ bool v4l2_match_dv_timings(const struct v4l2_dv_timings *t1,
            t1->bt.pixelclock >= t2->bt.pixelclock - pclock_delta &&
            t1->bt.pixelclock <= t2->bt.pixelclock + pclock_delta &&
            t1->bt.hfrontporch == t2->bt.hfrontporch &&
+           t1->bt.hsync == t2->bt.hsync &&
+           t1->bt.hbackporch == t2->bt.hbackporch &&
            t1->bt.vfrontporch == t2->bt.vfrontporch &&
            t1->bt.vsync == t2->bt.vsync &&
            t1->bt.vbackporch == t2->bt.vbackporch &&
+           (!match_reduced_fps ||
+            (t1->bt.flags & V4L2_DV_FL_REDUCED_FPS) ==
+               (t2->bt.flags & V4L2_DV_FL_REDUCED_FPS)) &&
            (!t1->bt.interlaced ||
                (t1->bt.il_vfrontporch == t2->bt.il_vfrontporch &&
                 t1->bt.il_vsync == t2->bt.il_vsync &&
index 5bdfb8d5263a0270d940d697ba55b381653f048e..5d673357f75f1ede5af69095d6f273bbc4a01ca7 100644 (file)
@@ -107,10 +107,10 @@ static void v4l2_flash_set_led_brightness(struct v4l2_flash *v4l2_flash,
                if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH)
                        return;
 
-               led_set_brightness(&v4l2_flash->fled_cdev->led_cdev,
+               led_set_brightness_sync(&v4l2_flash->fled_cdev->led_cdev,
                                        brightness);
        } else {
-               led_set_brightness(&v4l2_flash->iled_cdev->led_cdev,
+               led_set_brightness_sync(&v4l2_flash->iled_cdev->led_cdev,
                                        brightness);
        }
 }
@@ -206,11 +206,11 @@ static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c)
        case V4L2_CID_FLASH_LED_MODE:
                switch (c->val) {
                case V4L2_FLASH_LED_MODE_NONE:
-                       led_set_brightness(led_cdev, LED_OFF);
+                       led_set_brightness_sync(led_cdev, LED_OFF);
                        return led_set_flash_strobe(fled_cdev, false);
                case V4L2_FLASH_LED_MODE_FLASH:
                        /* Turn the torch LED off */
-                       led_set_brightness(led_cdev, LED_OFF);
+                       led_set_brightness_sync(led_cdev, LED_OFF);
                        if (ctrls[STROBE_SOURCE]) {
                                external_strobe = (ctrls[STROBE_SOURCE]->val ==
                                        V4L2_FLASH_STROBE_SOURCE_EXTERNAL);
index 7486af2c8ae49241d3aafd3c30f1a90094a63a0f..8a018c6dd16a8eff5812af61368c26054a3ed3b1 100644 (file)
@@ -565,8 +565,8 @@ static void v4l_print_ext_controls(const void *arg, bool write_only)
        const struct v4l2_ext_controls *p = arg;
        int i;
 
-       pr_cont("class=0x%x, count=%d, error_idx=%d",
-                       p->ctrl_class, p->count, p->error_idx);
+       pr_cont("which=0x%x, count=%d, error_idx=%d",
+                       p->which, p->count, p->error_idx);
        for (i = 0; i < p->count; i++) {
                if (!p->controls[i].size)
                        pr_cont(", id/val=0x%x/0x%x",
@@ -902,13 +902,13 @@ static int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
           Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL
           is it allowed for backwards compatibility.
         */
-       if (!allow_priv && c->ctrl_class == V4L2_CID_PRIVATE_BASE)
+       if (!allow_priv && c->which == V4L2_CID_PRIVATE_BASE)
                return 0;
-       if (c->ctrl_class == 0)
+       if (!c->which)
                return 1;
        /* Check that all controls are from the same control class. */
        for (i = 0; i < c->count; i++) {
-               if (V4L2_CTRL_ID2CLASS(c->controls[i].id) != c->ctrl_class) {
+               if (V4L2_CTRL_ID2WHICH(c->controls[i].id) != c->which) {
                        c->error_idx = i;
                        return 0;
                }
@@ -1969,7 +1969,7 @@ static int v4l_g_ctrl(const struct v4l2_ioctl_ops *ops,
        if (ops->vidioc_g_ext_ctrls == NULL)
                return -ENOTTY;
 
-       ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id);
+       ctrls.which = V4L2_CTRL_ID2WHICH(p->id);
        ctrls.count = 1;
        ctrls.controls = &ctrl;
        ctrl.id = p->id;
@@ -2003,7 +2003,7 @@ static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops,
        if (ops->vidioc_s_ext_ctrls == NULL)
                return -ENOTTY;
 
-       ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id);
+       ctrls.which = V4L2_CTRL_ID2WHICH(p->id);
        ctrls.count = 1;
        ctrls.controls = &ctrl;
        ctrl.id = p->id;
index 33bdd81065e81cd66de55fd533d8bda86b0c678f..c5d49d7a0d76d09c1ac5598a21ce7726d03190c1 100644 (file)
 
 #include <trace/events/vb2.h>
 
-#include "videobuf2-internal.h"
+static int debug;
+module_param(debug, int, 0644);
 
-int vb2_debug;
-EXPORT_SYMBOL_GPL(vb2_debug);
-module_param_named(debug, vb2_debug, int, 0644);
+#define dprintk(level, fmt, arg...)                                          \
+       do {                                                                  \
+               if (debug >= level)                                           \
+                       pr_info("vb2-core: %s: " fmt, __func__, ## arg); \
+       } while (0)
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+
+/*
+ * If advanced debugging is on, then count how often each op is called
+ * successfully, which can either be per-buffer or per-queue.
+ *
+ * This makes it easy to check that the 'init' and 'cleanup'
+ * (and variations thereof) stay balanced.
+ */
+
+#define log_memop(vb, op)                                              \
+       dprintk(2, "call_memop(%p, %d, %s)%s\n",                        \
+               (vb)->vb2_queue, (vb)->index, #op,                      \
+               (vb)->vb2_queue->mem_ops->op ? "" : " (nop)")
+
+#define call_memop(vb, op, args...)                                    \
+({                                                                     \
+       struct vb2_queue *_q = (vb)->vb2_queue;                         \
+       int err;                                                        \
+                                                                       \
+       log_memop(vb, op);                                              \
+       err = _q->mem_ops->op ? _q->mem_ops->op(args) : 0;              \
+       if (!err)                                                       \
+               (vb)->cnt_mem_ ## op++;                                 \
+       err;                                                            \
+})
+
+#define call_ptr_memop(vb, op, args...)                                        \
+({                                                                     \
+       struct vb2_queue *_q = (vb)->vb2_queue;                         \
+       void *ptr;                                                      \
+                                                                       \
+       log_memop(vb, op);                                              \
+       ptr = _q->mem_ops->op ? _q->mem_ops->op(args) : NULL;           \
+       if (!IS_ERR_OR_NULL(ptr))                                       \
+               (vb)->cnt_mem_ ## op++;                                 \
+       ptr;                                                            \
+})
+
+#define call_void_memop(vb, op, args...)                               \
+({                                                                     \
+       struct vb2_queue *_q = (vb)->vb2_queue;                         \
+                                                                       \
+       log_memop(vb, op);                                              \
+       if (_q->mem_ops->op)                                            \
+               _q->mem_ops->op(args);                                  \
+       (vb)->cnt_mem_ ## op++;                                         \
+})
+
+#define log_qop(q, op)                                                 \
+       dprintk(2, "call_qop(%p, %s)%s\n", q, #op,                      \
+               (q)->ops->op ? "" : " (nop)")
+
+#define call_qop(q, op, args...)                                       \
+({                                                                     \
+       int err;                                                        \
+                                                                       \
+       log_qop(q, op);                                                 \
+       err = (q)->ops->op ? (q)->ops->op(args) : 0;                    \
+       if (!err)                                                       \
+               (q)->cnt_ ## op++;                                      \
+       err;                                                            \
+})
+
+#define call_void_qop(q, op, args...)                                  \
+({                                                                     \
+       log_qop(q, op);                                                 \
+       if ((q)->ops->op)                                               \
+               (q)->ops->op(args);                                     \
+       (q)->cnt_ ## op++;                                              \
+})
+
+#define log_vb_qop(vb, op, args...)                                    \
+       dprintk(2, "call_vb_qop(%p, %d, %s)%s\n",                       \
+               (vb)->vb2_queue, (vb)->index, #op,                      \
+               (vb)->vb2_queue->ops->op ? "" : " (nop)")
+
+#define call_vb_qop(vb, op, args...)                                   \
+({                                                                     \
+       int err;                                                        \
+                                                                       \
+       log_vb_qop(vb, op);                                             \
+       err = (vb)->vb2_queue->ops->op ?                                \
+               (vb)->vb2_queue->ops->op(args) : 0;                     \
+       if (!err)                                                       \
+               (vb)->cnt_ ## op++;                                     \
+       err;                                                            \
+})
+
+#define call_void_vb_qop(vb, op, args...)                              \
+({                                                                     \
+       log_vb_qop(vb, op);                                             \
+       if ((vb)->vb2_queue->ops->op)                                   \
+               (vb)->vb2_queue->ops->op(args);                         \
+       (vb)->cnt_ ## op++;                                             \
+})
+
+#else
+
+#define call_memop(vb, op, args...)                                    \
+       ((vb)->vb2_queue->mem_ops->op ?                                 \
+               (vb)->vb2_queue->mem_ops->op(args) : 0)
+
+#define call_ptr_memop(vb, op, args...)                                        \
+       ((vb)->vb2_queue->mem_ops->op ?                                 \
+               (vb)->vb2_queue->mem_ops->op(args) : NULL)
+
+#define call_void_memop(vb, op, args...)                               \
+       do {                                                            \
+               if ((vb)->vb2_queue->mem_ops->op)                       \
+                       (vb)->vb2_queue->mem_ops->op(args);             \
+       } while (0)
+
+#define call_qop(q, op, args...)                                       \
+       ((q)->ops->op ? (q)->ops->op(args) : 0)
+
+#define call_void_qop(q, op, args...)                                  \
+       do {                                                            \
+               if ((q)->ops->op)                                       \
+                       (q)->ops->op(args);                             \
+       } while (0)
+
+#define call_vb_qop(vb, op, args...)                                   \
+       ((vb)->vb2_queue->ops->op ? (vb)->vb2_queue->ops->op(args) : 0)
+
+#define call_void_vb_qop(vb, op, args...)                              \
+       do {                                                            \
+               if ((vb)->vb2_queue->ops->op)                           \
+                       (vb)->vb2_queue->ops->op(args);                 \
+       } while (0)
+
+#endif
+
+#define call_bufop(q, op, args...)                                     \
+({                                                                     \
+       int ret = 0;                                                    \
+       if (q && q->buf_ops && q->buf_ops->op)                          \
+               ret = q->buf_ops->op(args);                             \
+       ret;                                                            \
+})
+
+#define call_void_bufop(q, op, args...)                                        \
+({                                                                     \
+       if (q && q->buf_ops && q->buf_ops->op)                          \
+               q->buf_ops->op(args);                                   \
+})
 
 static void __vb2_queue_cancel(struct vb2_queue *q);
 static void __enqueue_in_driver(struct vb2_buffer *vb);
@@ -53,7 +203,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
         * NOTE: mmapped areas should be page aligned
         */
        for (plane = 0; plane < vb->num_planes; ++plane) {
-               unsigned long size = PAGE_ALIGN(q->plane_sizes[plane]);
+               unsigned long size = PAGE_ALIGN(vb->planes[plane].length);
 
                mem_priv = call_ptr_memop(vb, alloc, q->alloc_ctx[plane],
                                      size, dma_dir, q->gfp_flags);
@@ -62,7 +212,6 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
 
                /* Associate allocator private data with this plane */
                vb->planes[plane].mem_priv = mem_priv;
-               vb->planes[plane].length = q->plane_sizes[plane];
        }
 
        return 0;
@@ -136,58 +285,31 @@ static void __vb2_buf_dmabuf_put(struct vb2_buffer *vb)
                __vb2_plane_dmabuf_put(vb, &vb->planes[plane]);
 }
 
-/**
- * __setup_lengths() - setup initial lengths for every plane in
- * every buffer on the queue
- */
-static void __setup_lengths(struct vb2_queue *q, unsigned int n)
-{
-       unsigned int buffer, plane;
-       struct vb2_buffer *vb;
-
-       for (buffer = q->num_buffers; buffer < q->num_buffers + n; ++buffer) {
-               vb = q->bufs[buffer];
-               if (!vb)
-                       continue;
-
-               for (plane = 0; plane < vb->num_planes; ++plane)
-                       vb->planes[plane].length = q->plane_sizes[plane];
-       }
-}
-
 /**
  * __setup_offsets() - setup unique offsets ("cookies") for every plane in
- * every buffer on the queue
+ * the buffer.
  */
-static void __setup_offsets(struct vb2_queue *q, unsigned int n)
+static void __setup_offsets(struct vb2_buffer *vb)
 {
-       unsigned int buffer, plane;
-       struct vb2_buffer *vb;
-       unsigned long off;
+       struct vb2_queue *q = vb->vb2_queue;
+       unsigned int plane;
+       unsigned long off = 0;
+
+       if (vb->index) {
+               struct vb2_buffer *prev = q->bufs[vb->index - 1];
+               struct vb2_plane *p = &prev->planes[prev->num_planes - 1];
 
-       if (q->num_buffers) {
-               struct vb2_plane *p;
-               vb = q->bufs[q->num_buffers - 1];
-               p = &vb->planes[vb->num_planes - 1];
                off = PAGE_ALIGN(p->m.offset + p->length);
-       } else {
-               off = 0;
        }
 
-       for (buffer = q->num_buffers; buffer < q->num_buffers + n; ++buffer) {
-               vb = q->bufs[buffer];
-               if (!vb)
-                       continue;
-
-               for (plane = 0; plane < vb->num_planes; ++plane) {
-                       vb->planes[plane].m.offset = off;
+       for (plane = 0; plane < vb->num_planes; ++plane) {
+               vb->planes[plane].m.offset = off;
 
-                       dprintk(3, "buffer %d, plane %d offset 0x%08lx\n",
-                                       buffer, plane, off);
+               dprintk(3, "buffer %d, plane %d offset 0x%08lx\n",
+                               vb->index, plane, off);
 
-                       off += vb->planes[plane].length;
-                       off = PAGE_ALIGN(off);
-               }
+               off += vb->planes[plane].length;
+               off = PAGE_ALIGN(off);
        }
 }
 
@@ -199,9 +321,10 @@ static void __setup_offsets(struct vb2_queue *q, unsigned int n)
  * Returns the number of buffers successfully allocated.
  */
 static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
-                            unsigned int num_buffers, unsigned int num_planes)
+                            unsigned int num_buffers, unsigned int num_planes,
+                            const unsigned plane_sizes[VB2_MAX_PLANES])
 {
-       unsigned int buffer;
+       unsigned int buffer, plane;
        struct vb2_buffer *vb;
        int ret;
 
@@ -219,6 +342,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
                vb->index = q->num_buffers + buffer;
                vb->type = q->type;
                vb->memory = memory;
+               for (plane = 0; plane < num_planes; ++plane) {
+                       vb->planes[plane].length = plane_sizes[plane];
+                       vb->planes[plane].min_length = plane_sizes[plane];
+               }
+               q->bufs[vb->index] = vb;
 
                /* Allocate video buffer memory for the MMAP type */
                if (memory == VB2_MEMORY_MMAP) {
@@ -226,9 +354,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
                        if (ret) {
                                dprintk(1, "failed allocating memory for "
                                                "buffer %d\n", buffer);
+                               q->bufs[vb->index] = NULL;
                                kfree(vb);
                                break;
                        }
+                       __setup_offsets(vb);
                        /*
                         * Call the driver-provided buffer initialization
                         * callback, if given. An error in initialization
@@ -239,18 +369,13 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
                                dprintk(1, "buffer %d %p initialization"
                                        " failed\n", buffer, vb);
                                __vb2_buf_mem_free(vb);
+                               q->bufs[vb->index] = NULL;
                                kfree(vb);
                                break;
                        }
                }
-
-               q->bufs[q->num_buffers + buffer] = vb;
        }
 
-       __setup_lengths(q, buffer);
-       if (memory == VB2_MEMORY_MMAP)
-               __setup_offsets(q, buffer);
-
        dprintk(1, "allocated %d buffers, %d plane(s) each\n",
                        buffer, num_planes);
 
@@ -330,7 +455,7 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
                bool unbalanced = q->cnt_start_streaming != q->cnt_stop_streaming ||
                                  q->cnt_wait_prepare != q->cnt_wait_finish;
 
-               if (unbalanced || vb2_debug) {
+               if (unbalanced || debug) {
                        pr_info("vb2: counters for queue %p:%s\n", q,
                                unbalanced ? " UNBALANCED!" : "");
                        pr_info("vb2:     setup: %u start_streaming: %u stop_streaming: %u\n",
@@ -356,7 +481,7 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
                                  vb->cnt_buf_prepare != vb->cnt_buf_finish ||
                                  vb->cnt_buf_init != vb->cnt_buf_cleanup;
 
-               if (unbalanced || vb2_debug) {
+               if (unbalanced || debug) {
                        pr_info("vb2:   counters for queue %p, buffer %d:%s\n",
                                q, buffer, unbalanced ? " UNBALANCED!" : "");
                        pr_info("vb2:     buf_init: %u buf_cleanup: %u buf_prepare: %u buf_finish: %u\n",
@@ -442,13 +567,10 @@ static bool __buffers_in_use(struct vb2_queue *q)
  * Should be called from vidioc_querybuf ioctl handler in driver.
  * The passed buffer should have been verified.
  * This function fills the relevant information for the userspace.
- *
- * The return values from this function are intended to be directly returned
- * from vidioc_querybuf handler in driver.
  */
-int vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
+void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
 {
-       return call_bufop(q, fill_user_buffer, q->bufs[index], pb);
+       call_void_bufop(q, fill_user_buffer, q->bufs[index], pb);
 }
 EXPORT_SYMBOL_GPL(vb2_core_querybuf);
 
@@ -570,6 +692,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
                unsigned int *count)
 {
        unsigned int num_buffers, allocated_buffers, num_planes = 0;
+       unsigned plane_sizes[VB2_MAX_PLANES] = { };
        int ret;
 
        if (q->streaming) {
@@ -613,7 +736,6 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
         */
        num_buffers = min_t(unsigned int, *count, VB2_MAX_FRAME);
        num_buffers = max_t(unsigned int, num_buffers, q->min_buffers_needed);
-       memset(q->plane_sizes, 0, sizeof(q->plane_sizes));
        memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
        q->memory = memory;
 
@@ -621,14 +743,14 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
         * Ask the driver how many buffers and planes per buffer it requires.
         * Driver also sets the size and allocator context for each plane.
         */
-       ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes,
-                      q->plane_sizes, q->alloc_ctx);
+       ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes,
+                      plane_sizes, q->alloc_ctx);
        if (ret)
                return ret;
 
        /* Finally, allocate buffers and video memory */
        allocated_buffers =
-               __vb2_queue_alloc(q, memory, num_buffers, num_planes);
+               __vb2_queue_alloc(q, memory, num_buffers, num_planes, plane_sizes);
        if (allocated_buffers == 0) {
                dprintk(1, "memory allocation failed\n");
                return -ENOMEM;
@@ -646,9 +768,16 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
         */
        if (!ret && allocated_buffers < num_buffers) {
                num_buffers = allocated_buffers;
+               /*
+                * num_planes is set by the previous queue_setup(), but since it
+                * signals to queue_setup() whether it is called from create_bufs()
+                * vs reqbufs() we zero it here to signal that queue_setup() is
+                * called for the reqbufs() case.
+                */
+               num_planes = 0;
 
-               ret = call_qop(q, queue_setup, q, NULL, &num_buffers,
-                              &num_planes, q->plane_sizes, q->alloc_ctx);
+               ret = call_qop(q, queue_setup, q, &num_buffers,
+                              &num_planes, plane_sizes, q->alloc_ctx);
 
                if (!ret && allocated_buffers < num_buffers)
                        ret = -ENOMEM;
@@ -701,9 +830,11 @@ EXPORT_SYMBOL_GPL(vb2_core_reqbufs);
  * from vidioc_create_bufs handler in driver.
  */
 int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
-               unsigned int *count, const void *parg)
+               unsigned int *count, unsigned requested_planes,
+               const unsigned requested_sizes[])
 {
        unsigned int num_planes = 0, num_buffers, allocated_buffers;
+       unsigned plane_sizes[VB2_MAX_PLANES] = { };
        int ret;
 
        if (q->num_buffers == VB2_MAX_FRAME) {
@@ -712,7 +843,6 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
        }
 
        if (!q->num_buffers) {
-               memset(q->plane_sizes, 0, sizeof(q->plane_sizes));
                memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
                q->memory = memory;
                q->waiting_for_buffers = !q->is_output;
@@ -720,18 +850,23 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
 
        num_buffers = min(*count, VB2_MAX_FRAME - q->num_buffers);
 
+       if (requested_planes && requested_sizes) {
+               num_planes = requested_planes;
+               memcpy(plane_sizes, requested_sizes, sizeof(plane_sizes));
+       }
+
        /*
         * Ask the driver, whether the requested number of buffers, planes per
         * buffer and their sizes are acceptable
         */
-       ret = call_qop(q, queue_setup, q, parg, &num_buffers,
-                      &num_planes, q->plane_sizes, q->alloc_ctx);
+       ret = call_qop(q, queue_setup, q, &num_buffers,
+                      &num_planes, plane_sizes, q->alloc_ctx);
        if (ret)
                return ret;
 
        /* Finally, allocate buffers and video memory */
        allocated_buffers = __vb2_queue_alloc(q, memory, num_buffers,
-                               num_planes);
+                               num_planes, plane_sizes);
        if (allocated_buffers == 0) {
                dprintk(1, "memory allocation failed\n");
                return -ENOMEM;
@@ -747,8 +882,8 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
                 * q->num_buffers contains the total number of buffers, that the
                 * queue driver has set up
                 */
-               ret = call_qop(q, queue_setup, q, parg, &num_buffers,
-                              &num_planes, q->plane_sizes, q->alloc_ctx);
+               ret = call_qop(q, queue_setup, q, &num_buffers,
+                              &num_planes, plane_sizes, q->alloc_ctx);
 
                if (!ret && allocated_buffers < num_buffers)
                        ret = -ENOMEM;
@@ -964,11 +1099,12 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const void *pb)
                                "reacquiring memory\n", plane);
 
                /* Check if the provided plane buffer is large enough */
-               if (planes[plane].length < q->plane_sizes[plane]) {
+               if (planes[plane].length < vb->planes[plane].min_length) {
                        dprintk(1, "provided buffer size %u is less than "
                                                "setup size %u for plane %d\n",
                                                planes[plane].length,
-                                               q->plane_sizes[plane], plane);
+                                               vb->planes[plane].min_length,
+                                               plane);
                        ret = -EINVAL;
                        goto err;
                }
@@ -1081,7 +1217,7 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const void *pb)
                if (planes[plane].length == 0)
                        planes[plane].length = dbuf->size;
 
-               if (planes[plane].length < q->plane_sizes[plane]) {
+               if (planes[plane].length < vb->planes[plane].min_length) {
                        dprintk(1, "invalid dmabuf length for plane %d\n",
                                plane);
                        ret = -EINVAL;
@@ -1263,9 +1399,7 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
                return ret;
 
        /* Fill buffer information for the userspace */
-       ret = call_bufop(q, fill_user_buffer, vb, pb);
-       if (ret)
-               return ret;
+       call_void_bufop(q, fill_user_buffer, vb, pb);
 
        dprintk(1, "prepare of buffer %d succeeded\n", vb->index);
 
@@ -1386,7 +1520,7 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb)
        q->waiting_for_buffers = false;
        vb->state = VB2_BUF_STATE_QUEUED;
 
-       call_bufop(q, set_timestamp, vb, pb);
+       call_void_bufop(q, copy_timestamp, vb, pb);
 
        trace_vb2_qbuf(q, vb);
 
@@ -1398,9 +1532,7 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb)
                __enqueue_in_driver(vb);
 
        /* Fill buffer information for the userspace */
-       ret = call_bufop(q, fill_user_buffer, vb, pb);
-       if (ret)
-               return ret;
+       call_void_bufop(q, fill_user_buffer, vb, pb);
 
        /*
         * If streamon has been called, and we haven't yet called
@@ -1623,9 +1755,7 @@ int vb2_core_dqbuf(struct vb2_queue *q, void *pb, bool nonblocking)
        call_void_vb_qop(vb, buf_finish, vb);
 
        /* Fill buffer information for the userspace */
-       ret = call_bufop(q, fill_user_buffer, vb, pb);
-       if (ret)
-               return ret;
+       call_void_bufop(q, fill_user_buffer, vb, pb);
 
        /* Remove from videobuf queue */
        list_del(&vb->queued_entry);
@@ -2073,6 +2203,8 @@ int vb2_core_queue_init(struct vb2_queue *q)
 }
 EXPORT_SYMBOL_GPL(vb2_core_queue_init);
 
+static int __vb2_init_fileio(struct vb2_queue *q, int read);
+static int __vb2_cleanup_fileio(struct vb2_queue *q);
 /**
  * vb2_core_queue_release() - stop streaming, release the queue and free memory
  * @q:         videobuf2 queue
@@ -2083,6 +2215,7 @@ EXPORT_SYMBOL_GPL(vb2_core_queue_init);
  */
 void vb2_core_queue_release(struct vb2_queue *q)
 {
+       __vb2_cleanup_fileio(q);
        __vb2_queue_cancel(q);
        mutex_lock(&q->mmap_lock);
        __vb2_queue_free(q, q->num_buffers);
@@ -2090,6 +2223,619 @@ void vb2_core_queue_release(struct vb2_queue *q)
 }
 EXPORT_SYMBOL_GPL(vb2_core_queue_release);
 
-MODULE_DESCRIPTION("Driver helper framework for Video for Linux 2");
+/**
+ * vb2_core_poll() - implements poll userspace operation
+ * @q:         videobuf2 queue
+ * @file:      file argument passed to the poll file operation handler
+ * @wait:      wait argument passed to the poll file operation handler
+ *
+ * This function implements poll file operation handler for a driver.
+ * For CAPTURE queues, if a buffer is ready to be dequeued, the userspace will
+ * be informed that the file descriptor of a video device is available for
+ * reading.
+ * For OUTPUT queues, if a buffer is ready to be dequeued, the file descriptor
+ * will be reported as available for writing.
+ *
+ * The return values from this function are intended to be directly returned
+ * from poll handler in driver.
+ */
+unsigned int vb2_core_poll(struct vb2_queue *q, struct file *file,
+               poll_table *wait)
+{
+       unsigned long req_events = poll_requested_events(wait);
+       struct vb2_buffer *vb = NULL;
+       unsigned long flags;
+
+       if (!q->is_output && !(req_events & (POLLIN | POLLRDNORM)))
+               return 0;
+       if (q->is_output && !(req_events & (POLLOUT | POLLWRNORM)))
+               return 0;
+
+       /*
+        * Start file I/O emulator only if streaming API has not been used yet.
+        */
+       if (q->num_buffers == 0 && !vb2_fileio_is_active(q)) {
+               if (!q->is_output && (q->io_modes & VB2_READ) &&
+                               (req_events & (POLLIN | POLLRDNORM))) {
+                       if (__vb2_init_fileio(q, 1))
+                               return POLLERR;
+               }
+               if (q->is_output && (q->io_modes & VB2_WRITE) &&
+                               (req_events & (POLLOUT | POLLWRNORM))) {
+                       if (__vb2_init_fileio(q, 0))
+                               return POLLERR;
+                       /*
+                        * Write to OUTPUT queue can be done immediately.
+                        */
+                       return POLLOUT | POLLWRNORM;
+               }
+       }
+
+       /*
+        * There is nothing to wait for if the queue isn't streaming, or if the
+        * error flag is set.
+        */
+       if (!vb2_is_streaming(q) || q->error)
+               return POLLERR;
+
+       /*
+        * For output streams you can call write() as long as there are fewer
+        * buffers queued than there are buffers available.
+        */
+       if (q->is_output && q->fileio && q->queued_count < q->num_buffers)
+               return POLLOUT | POLLWRNORM;
+
+       if (list_empty(&q->done_list)) {
+               /*
+                * If the last buffer was dequeued from a capture queue,
+                * return immediately. DQBUF will return -EPIPE.
+                */
+               if (q->last_buffer_dequeued)
+                       return POLLIN | POLLRDNORM;
+
+               poll_wait(file, &q->done_wq, wait);
+       }
+
+       /*
+        * Take first buffer available for dequeuing.
+        */
+       spin_lock_irqsave(&q->done_lock, flags);
+       if (!list_empty(&q->done_list))
+               vb = list_first_entry(&q->done_list, struct vb2_buffer,
+                                       done_entry);
+       spin_unlock_irqrestore(&q->done_lock, flags);
+
+       if (vb && (vb->state == VB2_BUF_STATE_DONE
+                       || vb->state == VB2_BUF_STATE_ERROR)) {
+               return (q->is_output) ?
+                               POLLOUT | POLLWRNORM :
+                               POLLIN | POLLRDNORM;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_core_poll);
+
+/**
+ * struct vb2_fileio_buf - buffer context used by file io emulator
+ *
+ * vb2 provides a compatibility layer and emulator of file io (read and
+ * write) calls on top of streaming API. This structure is used for
+ * tracking context related to the buffers.
+ */
+struct vb2_fileio_buf {
+       void *vaddr;
+       unsigned int size;
+       unsigned int pos;
+       unsigned int queued:1;
+};
+
+/**
+ * struct vb2_fileio_data - queue context used by file io emulator
+ *
+ * @cur_index: the index of the buffer currently being read from or
+ *             written to. If equal to q->num_buffers then a new buffer
+ *             must be dequeued.
+ * @initial_index: in the read() case all buffers are queued up immediately
+ *             in __vb2_init_fileio() and __vb2_perform_fileio() just cycles
+ *             buffers. However, in the write() case no buffers are initially
+ *             queued, instead whenever a buffer is full it is queued up by
+ *             __vb2_perform_fileio(). Only once all available buffers have
+ *             been queued up will __vb2_perform_fileio() start to dequeue
+ *             buffers. This means that initially __vb2_perform_fileio()
+ *             needs to know what buffer index to use when it is queuing up
+ *             the buffers for the first time. That initial index is stored
+ *             in this field. Once it is equal to q->num_buffers all
+ *             available buffers have been queued and __vb2_perform_fileio()
+ *             should start the normal dequeue/queue cycle.
+ *
+ * vb2 provides a compatibility layer and emulator of file io (read and
+ * write) calls on top of streaming API. For proper operation it required
+ * this structure to save the driver state between each call of the read
+ * or write function.
+ */
+struct vb2_fileio_data {
+       unsigned int count;
+       unsigned int type;
+       unsigned int memory;
+       struct vb2_buffer *b;
+       struct vb2_fileio_buf bufs[VB2_MAX_FRAME];
+       unsigned int cur_index;
+       unsigned int initial_index;
+       unsigned int q_count;
+       unsigned int dq_count;
+       unsigned read_once:1;
+       unsigned write_immediately:1;
+};
+
+/**
+ * __vb2_init_fileio() - initialize file io emulator
+ * @q:         videobuf2 queue
+ * @read:      mode selector (1 means read, 0 means write)
+ */
+static int __vb2_init_fileio(struct vb2_queue *q, int read)
+{
+       struct vb2_fileio_data *fileio;
+       int i, ret;
+       unsigned int count = 0;
+
+       /*
+        * Sanity check
+        */
+       if (WARN_ON((read && !(q->io_modes & VB2_READ)) ||
+                   (!read && !(q->io_modes & VB2_WRITE))))
+               return -EINVAL;
+
+       /*
+        * Check if device supports mapping buffers to kernel virtual space.
+        */
+       if (!q->mem_ops->vaddr)
+               return -EBUSY;
+
+       /*
+        * Check if streaming api has not been already activated.
+        */
+       if (q->streaming || q->num_buffers > 0)
+               return -EBUSY;
+
+       /*
+        * Start with count 1, driver can increase it in queue_setup()
+        */
+       count = 1;
+
+       dprintk(3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n",
+               (read) ? "read" : "write", count, q->fileio_read_once,
+               q->fileio_write_immediately);
+
+       fileio = kzalloc(sizeof(*fileio), GFP_KERNEL);
+       if (fileio == NULL)
+               return -ENOMEM;
+
+       fileio->b = kzalloc(q->buf_struct_size, GFP_KERNEL);
+       if (fileio->b == NULL) {
+               kfree(fileio);
+               return -ENOMEM;
+       }
+
+       fileio->read_once = q->fileio_read_once;
+       fileio->write_immediately = q->fileio_write_immediately;
+
+       /*
+        * Request buffers and use MMAP type to force driver
+        * to allocate buffers by itself.
+        */
+       fileio->count = count;
+       fileio->memory = VB2_MEMORY_MMAP;
+       fileio->type = q->type;
+       q->fileio = fileio;
+       ret = vb2_core_reqbufs(q, fileio->memory, &fileio->count);
+       if (ret)
+               goto err_kfree;
+
+       /*
+        * Check if plane_count is correct
+        * (multiplane buffers are not supported).
+        */
+       if (q->bufs[0]->num_planes != 1) {
+               ret = -EBUSY;
+               goto err_reqbufs;
+       }
+
+       /*
+        * Get kernel address of each buffer.
+        */
+       for (i = 0; i < q->num_buffers; i++) {
+               fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0);
+               if (fileio->bufs[i].vaddr == NULL) {
+                       ret = -EINVAL;
+                       goto err_reqbufs;
+               }
+               fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0);
+       }
+
+       /*
+        * Read mode requires pre queuing of all buffers.
+        */
+       if (read) {
+               /*
+                * Queue all buffers.
+                */
+               for (i = 0; i < q->num_buffers; i++) {
+                       struct vb2_buffer *b = fileio->b;
+
+                       memset(b, 0, q->buf_struct_size);
+                       b->type = q->type;
+                       b->memory = q->memory;
+                       b->index = i;
+                       ret = vb2_core_qbuf(q, i, b);
+                       if (ret)
+                               goto err_reqbufs;
+                       fileio->bufs[i].queued = 1;
+               }
+               /*
+                * All buffers have been queued, so mark that by setting
+                * initial_index to q->num_buffers
+                */
+               fileio->initial_index = q->num_buffers;
+               fileio->cur_index = q->num_buffers;
+       }
+
+       /*
+        * Start streaming.
+        */
+       ret = vb2_core_streamon(q, q->type);
+       if (ret)
+               goto err_reqbufs;
+
+       return ret;
+
+err_reqbufs:
+       fileio->count = 0;
+       vb2_core_reqbufs(q, fileio->memory, &fileio->count);
+
+err_kfree:
+       q->fileio = NULL;
+       kfree(fileio);
+       return ret;
+}
+
+/**
+ * __vb2_cleanup_fileio() - free resourced used by file io emulator
+ * @q:         videobuf2 queue
+ */
+static int __vb2_cleanup_fileio(struct vb2_queue *q)
+{
+       struct vb2_fileio_data *fileio = q->fileio;
+
+       if (fileio) {
+               vb2_core_streamoff(q, q->type);
+               q->fileio = NULL;
+               fileio->count = 0;
+               vb2_core_reqbufs(q, fileio->memory, &fileio->count);
+               kfree(fileio->b);
+               kfree(fileio);
+               dprintk(3, "file io emulator closed\n");
+       }
+       return 0;
+}
+
+/**
+ * __vb2_perform_fileio() - perform a single file io (read or write) operation
+ * @q:         videobuf2 queue
+ * @data:      pointed to target userspace buffer
+ * @count:     number of bytes to read or write
+ * @ppos:      file handle position tracking pointer
+ * @nonblock:  mode selector (1 means blocking calls, 0 means nonblocking)
+ * @read:      access mode selector (1 means read, 0 means write)
+ */
+static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count,
+               loff_t *ppos, int nonblock, int read)
+{
+       struct vb2_fileio_data *fileio;
+       struct vb2_fileio_buf *buf;
+       bool is_multiplanar = q->is_multiplanar;
+       /*
+        * When using write() to write data to an output video node the vb2 core
+        * should copy timestamps if V4L2_BUF_FLAG_TIMESTAMP_COPY is set. Nobody
+        * else is able to provide this information with the write() operation.
+        */
+       bool copy_timestamp = !read && q->copy_timestamp;
+       int ret, index;
+
+       dprintk(3, "mode %s, offset %ld, count %zd, %sblocking\n",
+               read ? "read" : "write", (long)*ppos, count,
+               nonblock ? "non" : "");
+
+       if (!data)
+               return -EINVAL;
+
+       /*
+        * Initialize emulator on first call.
+        */
+       if (!vb2_fileio_is_active(q)) {
+               ret = __vb2_init_fileio(q, read);
+               dprintk(3, "vb2_init_fileio result: %d\n", ret);
+               if (ret)
+                       return ret;
+       }
+       fileio = q->fileio;
+
+       /*
+        * Check if we need to dequeue the buffer.
+        */
+       index = fileio->cur_index;
+       if (index >= q->num_buffers) {
+               struct vb2_buffer *b = fileio->b;
+
+               /*
+                * Call vb2_dqbuf to get buffer back.
+                */
+               memset(b, 0, q->buf_struct_size);
+               b->type = q->type;
+               b->memory = q->memory;
+               ret = vb2_core_dqbuf(q, b, nonblock);
+               dprintk(5, "vb2_dqbuf result: %d\n", ret);
+               if (ret)
+                       return ret;
+               fileio->dq_count += 1;
+
+               fileio->cur_index = index = b->index;
+               buf = &fileio->bufs[index];
+
+               /*
+                * Get number of bytes filled by the driver
+                */
+               buf->pos = 0;
+               buf->queued = 0;
+               buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0)
+                                : vb2_plane_size(q->bufs[index], 0);
+               /* Compensate for data_offset on read in the multiplanar case. */
+               if (is_multiplanar && read &&
+                               b->planes[0].data_offset < buf->size) {
+                       buf->pos = b->planes[0].data_offset;
+                       buf->size -= buf->pos;
+               }
+       } else {
+               buf = &fileio->bufs[index];
+       }
+
+       /*
+        * Limit count on last few bytes of the buffer.
+        */
+       if (buf->pos + count > buf->size) {
+               count = buf->size - buf->pos;
+               dprintk(5, "reducing read count: %zd\n", count);
+       }
+
+       /*
+        * Transfer data to userspace.
+        */
+       dprintk(3, "copying %zd bytes - buffer %d, offset %u\n",
+               count, index, buf->pos);
+       if (read)
+               ret = copy_to_user(data, buf->vaddr + buf->pos, count);
+       else
+               ret = copy_from_user(buf->vaddr + buf->pos, data, count);
+       if (ret) {
+               dprintk(3, "error copying data\n");
+               return -EFAULT;
+       }
+
+       /*
+        * Update counters.
+        */
+       buf->pos += count;
+       *ppos += count;
+
+       /*
+        * Queue next buffer if required.
+        */
+       if (buf->pos == buf->size || (!read && fileio->write_immediately)) {
+               struct vb2_buffer *b = fileio->b;
+
+               /*
+                * Check if this is the last buffer to read.
+                */
+               if (read && fileio->read_once && fileio->dq_count == 1) {
+                       dprintk(3, "read limit reached\n");
+                       return __vb2_cleanup_fileio(q);
+               }
+
+               /*
+                * Call vb2_qbuf and give buffer to the driver.
+                */
+               memset(b, 0, q->buf_struct_size);
+               b->type = q->type;
+               b->memory = q->memory;
+               b->index = index;
+               b->planes[0].bytesused = buf->pos;
+
+               if (copy_timestamp)
+                       b->timestamp = ktime_get_ns();
+               ret = vb2_core_qbuf(q, index, b);
+               dprintk(5, "vb2_dbuf result: %d\n", ret);
+               if (ret)
+                       return ret;
+
+               /*
+                * Buffer has been queued, update the status
+                */
+               buf->pos = 0;
+               buf->queued = 1;
+               buf->size = vb2_plane_size(q->bufs[index], 0);
+               fileio->q_count += 1;
+               /*
+                * If we are queuing up buffers for the first time, then
+                * increase initial_index by one.
+                */
+               if (fileio->initial_index < q->num_buffers)
+                       fileio->initial_index++;
+               /*
+                * The next buffer to use is either a buffer that's going to be
+                * queued for the first time (initial_index < q->num_buffers)
+                * or it is equal to q->num_buffers, meaning that the next
+                * time we need to dequeue a buffer since we've now queued up
+                * all the 'first time' buffers.
+                */
+               fileio->cur_index = fileio->initial_index;
+       }
+
+       /*
+        * Return proper number of bytes processed.
+        */
+       if (ret == 0)
+               ret = count;
+       return ret;
+}
+
+size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
+               loff_t *ppos, int nonblocking)
+{
+       return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 1);
+}
+EXPORT_SYMBOL_GPL(vb2_read);
+
+size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count,
+               loff_t *ppos, int nonblocking)
+{
+       return __vb2_perform_fileio(q, (char __user *) data, count,
+                                                       ppos, nonblocking, 0);
+}
+EXPORT_SYMBOL_GPL(vb2_write);
+
+struct vb2_threadio_data {
+       struct task_struct *thread;
+       vb2_thread_fnc fnc;
+       void *priv;
+       bool stop;
+};
+
+static int vb2_thread(void *data)
+{
+       struct vb2_queue *q = data;
+       struct vb2_threadio_data *threadio = q->threadio;
+       struct vb2_fileio_data *fileio = q->fileio;
+       bool copy_timestamp = false;
+       int prequeue = 0;
+       int index = 0;
+       int ret = 0;
+
+       if (q->is_output) {
+               prequeue = q->num_buffers;
+               copy_timestamp = q->copy_timestamp;
+       }
+
+       set_freezable();
+
+       for (;;) {
+               struct vb2_buffer *vb;
+               struct vb2_buffer *b = fileio->b;
+
+               /*
+                * Call vb2_dqbuf to get buffer back.
+                */
+               memset(b, 0, q->buf_struct_size);
+               b->type = q->type;
+               b->memory = q->memory;
+               if (prequeue) {
+                       b->index = index++;
+                       prequeue--;
+               } else {
+                       call_void_qop(q, wait_finish, q);
+                       if (!threadio->stop)
+                               ret = vb2_core_dqbuf(q, b, 0);
+                       call_void_qop(q, wait_prepare, q);
+                       dprintk(5, "file io: vb2_dqbuf result: %d\n", ret);
+               }
+               if (ret || threadio->stop)
+                       break;
+               try_to_freeze();
+
+               vb = q->bufs[b->index];
+               if (b->state == VB2_BUF_STATE_DONE)
+                       if (threadio->fnc(vb, threadio->priv))
+                               break;
+               call_void_qop(q, wait_finish, q);
+               if (copy_timestamp)
+                       b->timestamp = ktime_get_ns();;
+               if (!threadio->stop)
+                       ret = vb2_core_qbuf(q, b->index, b);
+               call_void_qop(q, wait_prepare, q);
+               if (ret || threadio->stop)
+                       break;
+       }
+
+       /* Hmm, linux becomes *very* unhappy without this ... */
+       while (!kthread_should_stop()) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule();
+       }
+       return 0;
+}
+
+/*
+ * This function should not be used for anything else but the videobuf2-dvb
+ * support. If you think you have another good use-case for this, then please
+ * contact the linux-media mailinglist first.
+ */
+int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv,
+                    const char *thread_name)
+{
+       struct vb2_threadio_data *threadio;
+       int ret = 0;
+
+       if (q->threadio)
+               return -EBUSY;
+       if (vb2_is_busy(q))
+               return -EBUSY;
+       if (WARN_ON(q->fileio))
+               return -EBUSY;
+
+       threadio = kzalloc(sizeof(*threadio), GFP_KERNEL);
+       if (threadio == NULL)
+               return -ENOMEM;
+       threadio->fnc = fnc;
+       threadio->priv = priv;
+
+       ret = __vb2_init_fileio(q, !q->is_output);
+       dprintk(3, "file io: vb2_init_fileio result: %d\n", ret);
+       if (ret)
+               goto nomem;
+       q->threadio = threadio;
+       threadio->thread = kthread_run(vb2_thread, q, "vb2-%s", thread_name);
+       if (IS_ERR(threadio->thread)) {
+               ret = PTR_ERR(threadio->thread);
+               threadio->thread = NULL;
+               goto nothread;
+       }
+       return 0;
+
+nothread:
+       __vb2_cleanup_fileio(q);
+nomem:
+       kfree(threadio);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(vb2_thread_start);
+
+int vb2_thread_stop(struct vb2_queue *q)
+{
+       struct vb2_threadio_data *threadio = q->threadio;
+       int err;
+
+       if (threadio == NULL)
+               return 0;
+       threadio->stop = true;
+       /* Wake up all pending sleeps in the thread */
+       vb2_queue_error(q);
+       err = kthread_stop(threadio->thread);
+       __vb2_cleanup_fileio(q);
+       threadio->thread = NULL;
+       kfree(threadio);
+       q->threadio = NULL;
+       return err;
+}
+EXPORT_SYMBOL_GPL(vb2_thread_stop);
+
+MODULE_DESCRIPTION("Media buffer core framework");
 MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>, Marek Szyprowski");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/v4l2-core/videobuf2-internal.h b/drivers/media/v4l2-core/videobuf2-internal.h
deleted file mode 100644 (file)
index 79018c7..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-#ifndef _MEDIA_VIDEOBUF2_INTERNAL_H
-#define _MEDIA_VIDEOBUF2_INTERNAL_H
-
-#include <linux/err.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <media/videobuf2-core.h>
-
-extern int vb2_debug;
-
-#define dprintk(level, fmt, arg...)                                          \
-       do {                                                                  \
-               if (vb2_debug >= level)                                       \
-                       pr_info("vb2: %s: " fmt, __func__, ## arg); \
-       } while (0)
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-
-/*
- * If advanced debugging is on, then count how often each op is called
- * successfully, which can either be per-buffer or per-queue.
- *
- * This makes it easy to check that the 'init' and 'cleanup'
- * (and variations thereof) stay balanced.
- */
-
-#define log_memop(vb, op)                                              \
-       dprintk(2, "call_memop(%p, %d, %s)%s\n",                        \
-               (vb)->vb2_queue, (vb)->index, #op,                      \
-               (vb)->vb2_queue->mem_ops->op ? "" : " (nop)")
-
-#define call_memop(vb, op, args...)                                    \
-({                                                                     \
-       struct vb2_queue *_q = (vb)->vb2_queue;                         \
-       int err;                                                        \
-                                                                       \
-       log_memop(vb, op);                                              \
-       err = _q->mem_ops->op ? _q->mem_ops->op(args) : 0;              \
-       if (!err)                                                       \
-               (vb)->cnt_mem_ ## op++;                                 \
-       err;                                                            \
-})
-
-#define call_ptr_memop(vb, op, args...)                                        \
-({                                                                     \
-       struct vb2_queue *_q = (vb)->vb2_queue;                         \
-       void *ptr;                                                      \
-                                                                       \
-       log_memop(vb, op);                                              \
-       ptr = _q->mem_ops->op ? _q->mem_ops->op(args) : NULL;           \
-       if (!IS_ERR_OR_NULL(ptr))                                       \
-               (vb)->cnt_mem_ ## op++;                                 \
-       ptr;                                                            \
-})
-
-#define call_void_memop(vb, op, args...)                               \
-({                                                                     \
-       struct vb2_queue *_q = (vb)->vb2_queue;                         \
-                                                                       \
-       log_memop(vb, op);                                              \
-       if (_q->mem_ops->op)                                            \
-               _q->mem_ops->op(args);                                  \
-       (vb)->cnt_mem_ ## op++;                                         \
-})
-
-#define log_qop(q, op)                                                 \
-       dprintk(2, "call_qop(%p, %s)%s\n", q, #op,                      \
-               (q)->ops->op ? "" : " (nop)")
-
-#define call_qop(q, op, args...)                                       \
-({                                                                     \
-       int err;                                                        \
-                                                                       \
-       log_qop(q, op);                                                 \
-       err = (q)->ops->op ? (q)->ops->op(args) : 0;                    \
-       if (!err)                                                       \
-               (q)->cnt_ ## op++;                                      \
-       err;                                                            \
-})
-
-#define call_void_qop(q, op, args...)                                  \
-({                                                                     \
-       log_qop(q, op);                                                 \
-       if ((q)->ops->op)                                               \
-               (q)->ops->op(args);                                     \
-       (q)->cnt_ ## op++;                                              \
-})
-
-#define log_vb_qop(vb, op, args...)                                    \
-       dprintk(2, "call_vb_qop(%p, %d, %s)%s\n",                       \
-               (vb)->vb2_queue, (vb)->index, #op,                      \
-               (vb)->vb2_queue->ops->op ? "" : " (nop)")
-
-#define call_vb_qop(vb, op, args...)                                   \
-({                                                                     \
-       int err;                                                        \
-                                                                       \
-       log_vb_qop(vb, op);                                             \
-       err = (vb)->vb2_queue->ops->op ?                                \
-               (vb)->vb2_queue->ops->op(args) : 0;                     \
-       if (!err)                                                       \
-               (vb)->cnt_ ## op++;                                     \
-       err;                                                            \
-})
-
-#define call_void_vb_qop(vb, op, args...)                              \
-({                                                                     \
-       log_vb_qop(vb, op);                                             \
-       if ((vb)->vb2_queue->ops->op)                                   \
-               (vb)->vb2_queue->ops->op(args);                         \
-       (vb)->cnt_ ## op++;                                             \
-})
-
-#else
-
-#define call_memop(vb, op, args...)                                    \
-       ((vb)->vb2_queue->mem_ops->op ?                                 \
-               (vb)->vb2_queue->mem_ops->op(args) : 0)
-
-#define call_ptr_memop(vb, op, args...)                                        \
-       ((vb)->vb2_queue->mem_ops->op ?                                 \
-               (vb)->vb2_queue->mem_ops->op(args) : NULL)
-
-#define call_void_memop(vb, op, args...)                               \
-       do {                                                            \
-               if ((vb)->vb2_queue->mem_ops->op)                       \
-                       (vb)->vb2_queue->mem_ops->op(args);             \
-       } while (0)
-
-#define call_qop(q, op, args...)                                       \
-       ((q)->ops->op ? (q)->ops->op(args) : 0)
-
-#define call_void_qop(q, op, args...)                                  \
-       do {                                                            \
-               if ((q)->ops->op)                                       \
-                       (q)->ops->op(args);                             \
-       } while (0)
-
-#define call_vb_qop(vb, op, args...)                                   \
-       ((vb)->vb2_queue->ops->op ? (vb)->vb2_queue->ops->op(args) : 0)
-
-#define call_void_vb_qop(vb, op, args...)                              \
-       do {                                                            \
-               if ((vb)->vb2_queue->ops->op)                           \
-                       (vb)->vb2_queue->ops->op(args);                 \
-       } while (0)
-
-#endif
-
-#define call_bufop(q, op, args...)                                     \
-({                                                                     \
-       int ret = 0;                                                    \
-       if (q && q->buf_ops && q->buf_ops->op)                          \
-               ret = q->buf_ops->op(args);                             \
-       ret;                                                            \
-})
-
-bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb);
-int vb2_verify_memory_type(struct vb2_queue *q,
-               enum vb2_memory memory, unsigned int type);
-#endif /* _MEDIA_VIDEOBUF2_INTERNAL_H */
index 27b4b9e7c0c2f63c65c0fdaa1f515fc949a4dee2..c9a28605511a71166af35a4ef11fb95ff0eb8fbd 100644 (file)
 
 #include <media/videobuf2-v4l2.h>
 
-#include "videobuf2-internal.h"
+static int debug;
+module_param(debug, int, 0644);
+
+#define dprintk(level, fmt, arg...)                                          \
+       do {                                                                  \
+               if (debug >= level)                                           \
+                       pr_info("vb2-v4l2: %s: " fmt, __func__, ## arg); \
+       } while (0)
 
 /* Flags that are set by the vb2 core */
 #define V4L2_BUFFER_MASK_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \
@@ -52,7 +59,7 @@ static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer
                return 0;
 
        /* Is memory for copying plane information present? */
-       if (NULL == b->m.planes) {
+       if (b->m.planes == NULL) {
                dprintk(1, "multi-planar buffer passed but "
                           "planes array not provided\n");
                return -EINVAL;
@@ -107,7 +114,7 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b)
        return 0;
 }
 
-static int __set_timestamp(struct vb2_buffer *vb, const void *pb)
+static void __copy_timestamp(struct vb2_buffer *vb, const void *pb)
 {
        const struct v4l2_buffer *b = pb;
        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
@@ -118,14 +125,12 @@ static int __set_timestamp(struct vb2_buffer *vb, const void *pb)
                 * For output buffers copy the timestamp if needed,
                 * and the timecode field and flag if needed.
                 */
-               if ((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) ==
-                               V4L2_BUF_FLAG_TIMESTAMP_COPY)
-                       vbuf->timestamp = b->timestamp;
+               if (q->copy_timestamp)
+                       vb->timestamp = timeval_to_ns(&b->timestamp);
                vbuf->flags |= b->flags & V4L2_BUF_FLAG_TIMECODE;
                if (b->flags & V4L2_BUF_FLAG_TIMECODE)
                        vbuf->timecode = b->timecode;
        }
-       return 0;
 };
 
 static void vb2_warn_zero_bytesused(struct vb2_buffer *vb)
@@ -176,7 +181,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b,
  * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be
  * returned to userspace
  */
-static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
+static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
 {
        struct v4l2_buffer *b = pb;
        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
@@ -191,7 +196,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
 
        b->flags = vbuf->flags;
        b->field = vbuf->field;
-       b->timestamp = vbuf->timestamp;
+       b->timestamp = ns_to_timeval(vb->timestamp);
        b->timecode = vbuf->timecode;
        b->sequence = vbuf->sequence;
        b->reserved2 = 0;
@@ -238,8 +243,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
         */
        b->flags &= ~V4L2_BUFFER_MASK_FLAGS;
        b->flags |= q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK;
-       if ((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) !=
-           V4L2_BUF_FLAG_TIMESTAMP_COPY) {
+       if (!q->copy_timestamp) {
                /*
                 * For non-COPY timestamps, drop timestamp source bits
                 * and obtain the timestamp source from the queue.
@@ -272,7 +276,10 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
        if (vb2_buffer_in_use(q, vb))
                b->flags |= V4L2_BUF_FLAG_MAPPED;
 
-       return 0;
+       if (!q->is_output &&
+               b->flags & V4L2_BUF_FLAG_DONE &&
+               b->flags & V4L2_BUF_FLAG_LAST)
+               q->last_buffer_dequeued = true;
 }
 
 /**
@@ -308,8 +315,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb,
                                        "for an output buffer\n");
                return -EINVAL;
        }
-       vbuf->timestamp.tv_sec = 0;
-       vbuf->timestamp.tv_usec = 0;
+       vb->timestamp = 0;
        vbuf->sequence = 0;
 
        if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
@@ -404,8 +410,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb,
 
        /* Zero flags that the vb2 core handles */
        vbuf->flags = b->flags & ~V4L2_BUFFER_MASK_FLAGS;
-       if ((vb->vb2_queue->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) !=
-           V4L2_BUF_FLAG_TIMESTAMP_COPY || !V4L2_TYPE_IS_OUTPUT(b->type)) {
+       if (!vb->vb2_queue->copy_timestamp || !V4L2_TYPE_IS_OUTPUT(b->type)) {
                /*
                 * Non-COPY timestamps and non-OUTPUT queues will get
                 * their timestamp and timestamp source flags from the
@@ -434,7 +439,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb,
 static const struct vb2_buf_ops v4l2_buf_ops = {
        .fill_user_buffer       = __fill_v4l2_buffer,
        .fill_vb2_buffer        = __fill_vb2_buffer,
-       .set_timestamp          = __set_timestamp,
+       .copy_timestamp         = __copy_timestamp,
 };
 
 /**
@@ -466,8 +471,9 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
        }
        vb = q->bufs[b->index];
        ret = __verify_planes_array(vb, b);
-
-       return ret ? ret : vb2_core_querybuf(q, b->index, b);
+       if (!ret)
+               vb2_core_querybuf(q, b->index, b);
+       return ret;
 }
 EXPORT_SYMBOL(vb2_querybuf);
 
@@ -525,14 +531,52 @@ EXPORT_SYMBOL_GPL(vb2_prepare_buf);
  */
 int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
 {
-       int ret = vb2_verify_memory_type(q, create->memory,
-                       create->format.type);
+       unsigned requested_planes = 1;
+       unsigned requested_sizes[VIDEO_MAX_PLANES];
+       struct v4l2_format *f = &create->format;
+       int ret = vb2_verify_memory_type(q, create->memory, f->type);
+       unsigned i;
 
        create->index = q->num_buffers;
        if (create->count == 0)
                return ret != -EBUSY ? ret : 0;
+
+       switch (f->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+               requested_planes = f->fmt.pix_mp.num_planes;
+               if (requested_planes == 0 ||
+                   requested_planes > VIDEO_MAX_PLANES)
+                       return -EINVAL;
+               for (i = 0; i < requested_planes; i++)
+                       requested_sizes[i] =
+                               f->fmt.pix_mp.plane_fmt[i].sizeimage;
+               break;
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+               requested_sizes[0] = f->fmt.pix.sizeimage;
+               break;
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_VBI_OUTPUT:
+               requested_sizes[0] = f->fmt.vbi.samples_per_line *
+                       (f->fmt.vbi.count[0] + f->fmt.vbi.count[1]);
+               break;
+       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+               requested_sizes[0] = f->fmt.sliced.io_size;
+               break;
+       case V4L2_BUF_TYPE_SDR_CAPTURE:
+       case V4L2_BUF_TYPE_SDR_OUTPUT:
+               requested_sizes[0] = f->fmt.sdr.buffersize;
+               break;
+       default:
+               return -EINVAL;
+       }
+       for (i = 0; i < requested_planes; i++)
+               if (requested_sizes[i] == 0)
+                       return -EINVAL;
        return ret ? ret : vb2_core_create_bufs(q, create->memory,
-               &create->count, &create->format);
+               &create->count, requested_planes, requested_sizes);
 }
 EXPORT_SYMBOL_GPL(vb2_create_bufs);
 
@@ -583,10 +627,6 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b,
 
        ret = vb2_core_dqbuf(q, b, nonblocking);
 
-       if (!ret && !q->is_output &&
-                       b->flags & V4L2_BUF_FLAG_LAST)
-               q->last_buffer_dequeued = true;
-
        return ret;
 }
 
@@ -723,14 +763,13 @@ int vb2_queue_init(struct vb2_queue *q)
        q->buf_ops = &v4l2_buf_ops;
        q->is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(q->type);
        q->is_output = V4L2_TYPE_IS_OUTPUT(q->type);
+       q->copy_timestamp = (q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK)
+                       == V4L2_BUF_FLAG_TIMESTAMP_COPY;
 
        return vb2_core_queue_init(q);
 }
 EXPORT_SYMBOL_GPL(vb2_queue_init);
 
-static int __vb2_init_fileio(struct vb2_queue *q, int read);
-static int __vb2_cleanup_fileio(struct vb2_queue *q);
-
 /**
  * vb2_queue_release() - stop streaming, release the queue and free memory
  * @q:         videobuf2 queue
@@ -741,7 +780,6 @@ static int __vb2_cleanup_fileio(struct vb2_queue *q);
  */
 void vb2_queue_release(struct vb2_queue *q)
 {
-       __vb2_cleanup_fileio(q);
        vb2_core_queue_release(q);
 }
 EXPORT_SYMBOL_GPL(vb2_queue_release);
@@ -769,9 +807,7 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
 {
        struct video_device *vfd = video_devdata(file);
        unsigned long req_events = poll_requested_events(wait);
-       struct vb2_buffer *vb = NULL;
        unsigned int res = 0;
-       unsigned long flags;
 
        if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) {
                struct v4l2_fh *fh = file->private_data;
@@ -782,611 +818,18 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
                        poll_wait(file, &fh->wait, wait);
        }
 
-       if (!q->is_output && !(req_events & (POLLIN | POLLRDNORM)))
-               return res;
-       if (q->is_output && !(req_events & (POLLOUT | POLLWRNORM)))
-               return res;
-
-       /*
-        * Start file I/O emulator only if streaming API has not been used yet.
-        */
-       if (q->num_buffers == 0 && !vb2_fileio_is_active(q)) {
-               if (!q->is_output && (q->io_modes & VB2_READ) &&
-                               (req_events & (POLLIN | POLLRDNORM))) {
-                       if (__vb2_init_fileio(q, 1))
-                               return res | POLLERR;
-               }
-               if (q->is_output && (q->io_modes & VB2_WRITE) &&
-                               (req_events & (POLLOUT | POLLWRNORM))) {
-                       if (__vb2_init_fileio(q, 0))
-                               return res | POLLERR;
-                       /*
-                        * Write to OUTPUT queue can be done immediately.
-                        */
-                       return res | POLLOUT | POLLWRNORM;
-               }
-       }
-
-       /*
-        * There is nothing to wait for if the queue isn't streaming, or if the
-        * error flag is set.
-        */
-       if (!vb2_is_streaming(q) || q->error)
-               return res | POLLERR;
        /*
         * For compatibility with vb1: if QBUF hasn't been called yet, then
         * return POLLERR as well. This only affects capture queues, output
         * queues will always initialize waiting_for_buffers to false.
         */
-       if (q->waiting_for_buffers)
-               return res | POLLERR;
-
-       /*
-        * For output streams you can write as long as there are fewer buffers
-        * queued than there are buffers available.
-        */
-       if (q->is_output && q->queued_count < q->num_buffers)
-               return res | POLLOUT | POLLWRNORM;
-
-       if (list_empty(&q->done_list)) {
-               /*
-                * If the last buffer was dequeued from a capture queue,
-                * return immediately. DQBUF will return -EPIPE.
-                */
-               if (q->last_buffer_dequeued)
-                       return res | POLLIN | POLLRDNORM;
-
-               poll_wait(file, &q->done_wq, wait);
-       }
+       if (q->waiting_for_buffers && (req_events & (POLLIN | POLLRDNORM)))
+               return POLLERR;
 
-       /*
-        * Take first buffer available for dequeuing.
-        */
-       spin_lock_irqsave(&q->done_lock, flags);
-       if (!list_empty(&q->done_list))
-               vb = list_first_entry(&q->done_list, struct vb2_buffer,
-                                       done_entry);
-       spin_unlock_irqrestore(&q->done_lock, flags);
-
-       if (vb && (vb->state == VB2_BUF_STATE_DONE
-                       || vb->state == VB2_BUF_STATE_ERROR)) {
-               return (q->is_output) ?
-                               res | POLLOUT | POLLWRNORM :
-                               res | POLLIN | POLLRDNORM;
-       }
-       return res;
+       return res | vb2_core_poll(q, file, wait);
 }
 EXPORT_SYMBOL_GPL(vb2_poll);
 
-/**
- * struct vb2_fileio_buf - buffer context used by file io emulator
- *
- * vb2 provides a compatibility layer and emulator of file io (read and
- * write) calls on top of streaming API. This structure is used for
- * tracking context related to the buffers.
- */
-struct vb2_fileio_buf {
-       void *vaddr;
-       unsigned int size;
-       unsigned int pos;
-       unsigned int queued:1;
-};
-
-/**
- * struct vb2_fileio_data - queue context used by file io emulator
- *
- * @cur_index: the index of the buffer currently being read from or
- *             written to. If equal to q->num_buffers then a new buffer
- *             must be dequeued.
- * @initial_index: in the read() case all buffers are queued up immediately
- *             in __vb2_init_fileio() and __vb2_perform_fileio() just cycles
- *             buffers. However, in the write() case no buffers are initially
- *             queued, instead whenever a buffer is full it is queued up by
- *             __vb2_perform_fileio(). Only once all available buffers have
- *             been queued up will __vb2_perform_fileio() start to dequeue
- *             buffers. This means that initially __vb2_perform_fileio()
- *             needs to know what buffer index to use when it is queuing up
- *             the buffers for the first time. That initial index is stored
- *             in this field. Once it is equal to q->num_buffers all
- *             available buffers have been queued and __vb2_perform_fileio()
- *             should start the normal dequeue/queue cycle.
- *
- * vb2 provides a compatibility layer and emulator of file io (read and
- * write) calls on top of streaming API. For proper operation it required
- * this structure to save the driver state between each call of the read
- * or write function.
- */
-struct vb2_fileio_data {
-       struct v4l2_requestbuffers req;
-       struct v4l2_plane p;
-       struct v4l2_buffer b;
-       struct vb2_fileio_buf bufs[VB2_MAX_FRAME];
-       unsigned int cur_index;
-       unsigned int initial_index;
-       unsigned int q_count;
-       unsigned int dq_count;
-       unsigned read_once:1;
-       unsigned write_immediately:1;
-};
-
-/**
- * __vb2_init_fileio() - initialize file io emulator
- * @q:         videobuf2 queue
- * @read:      mode selector (1 means read, 0 means write)
- */
-static int __vb2_init_fileio(struct vb2_queue *q, int read)
-{
-       struct vb2_fileio_data *fileio;
-       int i, ret;
-       unsigned int count = 0;
-
-       /*
-        * Sanity check
-        */
-       if (WARN_ON((read && !(q->io_modes & VB2_READ)) ||
-                   (!read && !(q->io_modes & VB2_WRITE))))
-               return -EINVAL;
-
-       /*
-        * Check if device supports mapping buffers to kernel virtual space.
-        */
-       if (!q->mem_ops->vaddr)
-               return -EBUSY;
-
-       /*
-        * Check if streaming api has not been already activated.
-        */
-       if (q->streaming || q->num_buffers > 0)
-               return -EBUSY;
-
-       /*
-        * Start with count 1, driver can increase it in queue_setup()
-        */
-       count = 1;
-
-       dprintk(3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n",
-               (read) ? "read" : "write", count, q->fileio_read_once,
-               q->fileio_write_immediately);
-
-       fileio = kzalloc(sizeof(struct vb2_fileio_data), GFP_KERNEL);
-       if (fileio == NULL)
-               return -ENOMEM;
-
-       fileio->read_once = q->fileio_read_once;
-       fileio->write_immediately = q->fileio_write_immediately;
-
-       /*
-        * Request buffers and use MMAP type to force driver
-        * to allocate buffers by itself.
-        */
-       fileio->req.count = count;
-       fileio->req.memory = VB2_MEMORY_MMAP;
-       fileio->req.type = q->type;
-       q->fileio = fileio;
-       ret = vb2_core_reqbufs(q, fileio->req.memory, &fileio->req.count);
-       if (ret)
-               goto err_kfree;
-
-       /*
-        * Check if plane_count is correct
-        * (multiplane buffers are not supported).
-        */
-       if (q->bufs[0]->num_planes != 1) {
-               ret = -EBUSY;
-               goto err_reqbufs;
-       }
-
-       /*
-        * Get kernel address of each buffer.
-        */
-       for (i = 0; i < q->num_buffers; i++) {
-               fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0);
-               if (fileio->bufs[i].vaddr == NULL) {
-                       ret = -EINVAL;
-                       goto err_reqbufs;
-               }
-               fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0);
-       }
-
-       /*
-        * Read mode requires pre queuing of all buffers.
-        */
-       if (read) {
-               bool is_multiplanar = q->is_multiplanar;
-
-               /*
-                * Queue all buffers.
-                */
-               for (i = 0; i < q->num_buffers; i++) {
-                       struct v4l2_buffer *b = &fileio->b;
-
-                       memset(b, 0, sizeof(*b));
-                       b->type = q->type;
-                       if (is_multiplanar) {
-                               memset(&fileio->p, 0, sizeof(fileio->p));
-                               b->m.planes = &fileio->p;
-                               b->length = 1;
-                       }
-                       b->memory = q->memory;
-                       b->index = i;
-                       ret = vb2_internal_qbuf(q, b);
-                       if (ret)
-                               goto err_reqbufs;
-                       fileio->bufs[i].queued = 1;
-               }
-               /*
-                * All buffers have been queued, so mark that by setting
-                * initial_index to q->num_buffers
-                */
-               fileio->initial_index = q->num_buffers;
-               fileio->cur_index = q->num_buffers;
-       }
-
-       /*
-        * Start streaming.
-        */
-       ret = vb2_core_streamon(q, q->type);
-       if (ret)
-               goto err_reqbufs;
-
-       return ret;
-
-err_reqbufs:
-       fileio->req.count = 0;
-       vb2_core_reqbufs(q, fileio->req.memory, &fileio->req.count);
-
-err_kfree:
-       q->fileio = NULL;
-       kfree(fileio);
-       return ret;
-}
-
-/**
- * __vb2_cleanup_fileio() - free resourced used by file io emulator
- * @q:         videobuf2 queue
- */
-static int __vb2_cleanup_fileio(struct vb2_queue *q)
-{
-       struct vb2_fileio_data *fileio = q->fileio;
-
-       if (fileio) {
-               vb2_core_streamoff(q, q->type);
-               q->fileio = NULL;
-               fileio->req.count = 0;
-               vb2_reqbufs(q, &fileio->req);
-               kfree(fileio);
-               dprintk(3, "file io emulator closed\n");
-       }
-       return 0;
-}
-
-/**
- * __vb2_perform_fileio() - perform a single file io (read or write) operation
- * @q:         videobuf2 queue
- * @data:      pointed to target userspace buffer
- * @count:     number of bytes to read or write
- * @ppos:      file handle position tracking pointer
- * @nonblock:  mode selector (1 means blocking calls, 0 means nonblocking)
- * @read:      access mode selector (1 means read, 0 means write)
- */
-static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count,
-               loff_t *ppos, int nonblock, int read)
-{
-       struct vb2_fileio_data *fileio;
-       struct vb2_fileio_buf *buf;
-       bool is_multiplanar = q->is_multiplanar;
-       /*
-        * When using write() to write data to an output video node the vb2 core
-        * should set timestamps if V4L2_BUF_FLAG_TIMESTAMP_COPY is set. Nobody
-        * else is able to provide this information with the write() operation.
-        */
-       bool set_timestamp = !read &&
-               (q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) ==
-               V4L2_BUF_FLAG_TIMESTAMP_COPY;
-       int ret, index;
-
-       dprintk(3, "mode %s, offset %ld, count %zd, %sblocking\n",
-               read ? "read" : "write", (long)*ppos, count,
-               nonblock ? "non" : "");
-
-       if (!data)
-               return -EINVAL;
-
-       /*
-        * Initialize emulator on first call.
-        */
-       if (!vb2_fileio_is_active(q)) {
-               ret = __vb2_init_fileio(q, read);
-               dprintk(3, "vb2_init_fileio result: %d\n", ret);
-               if (ret)
-                       return ret;
-       }
-       fileio = q->fileio;
-
-       /*
-        * Check if we need to dequeue the buffer.
-        */
-       index = fileio->cur_index;
-       if (index >= q->num_buffers) {
-               /*
-                * Call vb2_dqbuf to get buffer back.
-                */
-               memset(&fileio->b, 0, sizeof(fileio->b));
-               fileio->b.type = q->type;
-               fileio->b.memory = q->memory;
-               if (is_multiplanar) {
-                       memset(&fileio->p, 0, sizeof(fileio->p));
-                       fileio->b.m.planes = &fileio->p;
-                       fileio->b.length = 1;
-               }
-               ret = vb2_internal_dqbuf(q, &fileio->b, nonblock);
-               dprintk(5, "vb2_dqbuf result: %d\n", ret);
-               if (ret)
-                       return ret;
-               fileio->dq_count += 1;
-
-               fileio->cur_index = index = fileio->b.index;
-               buf = &fileio->bufs[index];
-
-               /*
-                * Get number of bytes filled by the driver
-                */
-               buf->pos = 0;
-               buf->queued = 0;
-               buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0)
-                                : vb2_plane_size(q->bufs[index], 0);
-               /* Compensate for data_offset on read in the multiplanar case. */
-               if (is_multiplanar && read &&
-                   fileio->b.m.planes[0].data_offset < buf->size) {
-                       buf->pos = fileio->b.m.planes[0].data_offset;
-                       buf->size -= buf->pos;
-               }
-       } else {
-               buf = &fileio->bufs[index];
-       }
-
-       /*
-        * Limit count on last few bytes of the buffer.
-        */
-       if (buf->pos + count > buf->size) {
-               count = buf->size - buf->pos;
-               dprintk(5, "reducing read count: %zd\n", count);
-       }
-
-       /*
-        * Transfer data to userspace.
-        */
-       dprintk(3, "copying %zd bytes - buffer %d, offset %u\n",
-               count, index, buf->pos);
-       if (read)
-               ret = copy_to_user(data, buf->vaddr + buf->pos, count);
-       else
-               ret = copy_from_user(buf->vaddr + buf->pos, data, count);
-       if (ret) {
-               dprintk(3, "error copying data\n");
-               return -EFAULT;
-       }
-
-       /*
-        * Update counters.
-        */
-       buf->pos += count;
-       *ppos += count;
-
-       /*
-        * Queue next buffer if required.
-        */
-       if (buf->pos == buf->size || (!read && fileio->write_immediately)) {
-               /*
-                * Check if this is the last buffer to read.
-                */
-               if (read && fileio->read_once && fileio->dq_count == 1) {
-                       dprintk(3, "read limit reached\n");
-                       return __vb2_cleanup_fileio(q);
-               }
-
-               /*
-                * Call vb2_qbuf and give buffer to the driver.
-                */
-               memset(&fileio->b, 0, sizeof(fileio->b));
-               fileio->b.type = q->type;
-               fileio->b.memory = q->memory;
-               fileio->b.index = index;
-               fileio->b.bytesused = buf->pos;
-               if (is_multiplanar) {
-                       memset(&fileio->p, 0, sizeof(fileio->p));
-                       fileio->p.bytesused = buf->pos;
-                       fileio->b.m.planes = &fileio->p;
-                       fileio->b.length = 1;
-               }
-               if (set_timestamp)
-                       v4l2_get_timestamp(&fileio->b.timestamp);
-               ret = vb2_internal_qbuf(q, &fileio->b);
-               dprintk(5, "vb2_dbuf result: %d\n", ret);
-               if (ret)
-                       return ret;
-
-               /*
-                * Buffer has been queued, update the status
-                */
-               buf->pos = 0;
-               buf->queued = 1;
-               buf->size = vb2_plane_size(q->bufs[index], 0);
-               fileio->q_count += 1;
-               /*
-                * If we are queuing up buffers for the first time, then
-                * increase initial_index by one.
-                */
-               if (fileio->initial_index < q->num_buffers)
-                       fileio->initial_index++;
-               /*
-                * The next buffer to use is either a buffer that's going to be
-                * queued for the first time (initial_index < q->num_buffers)
-                * or it is equal to q->num_buffers, meaning that the next
-                * time we need to dequeue a buffer since we've now queued up
-                * all the 'first time' buffers.
-                */
-               fileio->cur_index = fileio->initial_index;
-       }
-
-       /*
-        * Return proper number of bytes processed.
-        */
-       if (ret == 0)
-               ret = count;
-       return ret;
-}
-
-size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
-               loff_t *ppos, int nonblocking)
-{
-       return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 1);
-}
-EXPORT_SYMBOL_GPL(vb2_read);
-
-size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count,
-               loff_t *ppos, int nonblocking)
-{
-       return __vb2_perform_fileio(q, (char __user *) data, count,
-                                                       ppos, nonblocking, 0);
-}
-EXPORT_SYMBOL_GPL(vb2_write);
-
-struct vb2_threadio_data {
-       struct task_struct *thread;
-       vb2_thread_fnc fnc;
-       void *priv;
-       bool stop;
-};
-
-static int vb2_thread(void *data)
-{
-       struct vb2_queue *q = data;
-       struct vb2_threadio_data *threadio = q->threadio;
-       struct vb2_fileio_data *fileio = q->fileio;
-       bool set_timestamp = false;
-       int prequeue = 0;
-       int index = 0;
-       int ret = 0;
-
-       if (q->is_output) {
-               prequeue = q->num_buffers;
-               set_timestamp =
-                       (q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) ==
-                       V4L2_BUF_FLAG_TIMESTAMP_COPY;
-       }
-
-       set_freezable();
-
-       for (;;) {
-               struct vb2_buffer *vb;
-
-               /*
-                * Call vb2_dqbuf to get buffer back.
-                */
-               memset(&fileio->b, 0, sizeof(fileio->b));
-               fileio->b.type = q->type;
-               fileio->b.memory = q->memory;
-               if (prequeue) {
-                       fileio->b.index = index++;
-                       prequeue--;
-               } else {
-                       call_void_qop(q, wait_finish, q);
-                       if (!threadio->stop)
-                               ret = vb2_internal_dqbuf(q, &fileio->b, 0);
-                       call_void_qop(q, wait_prepare, q);
-                       dprintk(5, "file io: vb2_dqbuf result: %d\n", ret);
-               }
-               if (ret || threadio->stop)
-                       break;
-               try_to_freeze();
-
-               vb = q->bufs[fileio->b.index];
-               if (!(fileio->b.flags & V4L2_BUF_FLAG_ERROR))
-                       if (threadio->fnc(vb, threadio->priv))
-                               break;
-               call_void_qop(q, wait_finish, q);
-               if (set_timestamp)
-                       v4l2_get_timestamp(&fileio->b.timestamp);
-               if (!threadio->stop)
-                       ret = vb2_internal_qbuf(q, &fileio->b);
-               call_void_qop(q, wait_prepare, q);
-               if (ret || threadio->stop)
-                       break;
-       }
-
-       /* Hmm, linux becomes *very* unhappy without this ... */
-       while (!kthread_should_stop()) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule();
-       }
-       return 0;
-}
-
-/*
- * This function should not be used for anything else but the videobuf2-dvb
- * support. If you think you have another good use-case for this, then please
- * contact the linux-media mailinglist first.
- */
-int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv,
-                    const char *thread_name)
-{
-       struct vb2_threadio_data *threadio;
-       int ret = 0;
-
-       if (q->threadio)
-               return -EBUSY;
-       if (vb2_is_busy(q))
-               return -EBUSY;
-       if (WARN_ON(q->fileio))
-               return -EBUSY;
-
-       threadio = kzalloc(sizeof(*threadio), GFP_KERNEL);
-       if (threadio == NULL)
-               return -ENOMEM;
-       threadio->fnc = fnc;
-       threadio->priv = priv;
-
-       ret = __vb2_init_fileio(q, !q->is_output);
-       dprintk(3, "file io: vb2_init_fileio result: %d\n", ret);
-       if (ret)
-               goto nomem;
-       q->threadio = threadio;
-       threadio->thread = kthread_run(vb2_thread, q, "vb2-%s", thread_name);
-       if (IS_ERR(threadio->thread)) {
-               ret = PTR_ERR(threadio->thread);
-               threadio->thread = NULL;
-               goto nothread;
-       }
-       return 0;
-
-nothread:
-       __vb2_cleanup_fileio(q);
-nomem:
-       kfree(threadio);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(vb2_thread_start);
-
-int vb2_thread_stop(struct vb2_queue *q)
-{
-       struct vb2_threadio_data *threadio = q->threadio;
-       int err;
-
-       if (threadio == NULL)
-               return 0;
-       threadio->stop = true;
-       /* Wake up all pending sleeps in the thread */
-       vb2_queue_error(q);
-       err = kthread_stop(threadio->thread);
-       __vb2_cleanup_fileio(q);
-       threadio->thread = NULL;
-       kfree(threadio);
-       q->threadio = NULL;
-       return err;
-}
-EXPORT_SYMBOL_GPL(vb2_thread_stop);
-
 /*
  * The following functions are not part of the vb2 core API, but are helper
  * functions that plug into struct v4l2_ioctl_ops, struct v4l2_file_operations
@@ -1440,8 +883,8 @@ int vb2_ioctl_create_bufs(struct file *file, void *priv,
                return res;
        if (vb2_queue_is_busy(vdev, file))
                return -EBUSY;
-       res = vb2_core_create_bufs(vdev->queue, p->memory, &p->count,
-                       &p->format);
+
+       res = vb2_create_bufs(vdev->queue, p);
        if (res == 0)
                vdev->queue->owner = file->private_data;
        return res;
index 6ce36d6970a4104484d0ac1fa118df96e27dedfe..c9339f85359b74482358f1d15328e0d03c4f732c 100644 (file)
@@ -39,8 +39,8 @@
 #include <linux/spi/max7301.h>
 #include <linux/spi/mc33880.h>
 
-#include <media/timb_radio.h>
-#include <media/timb_video.h>
+#include <linux/platform_data/media/timb_radio.h>
+#include <linux/platform_data/media/timb_video.h>
 
 #include <linux/timb_dma.h>
 
index d8486168415ae1123f6a31d7126cfc9192fe884b..5914263090fc81447e26130baab143802504c088 100644 (file)
@@ -171,11 +171,7 @@ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
 
 static inline int mmc_get_devidx(struct gendisk *disk)
 {
-       int devmaj = MAJOR(disk_devt(disk));
-       int devidx = MINOR(disk_devt(disk)) / perdev_minors;
-
-       if (!devmaj)
-               devidx = disk->first_minor / perdev_minors;
+       int devidx = disk->first_minor / perdev_minors;
        return devidx;
 }
 
@@ -344,7 +340,7 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
        struct mmc_blk_ioc_data *idata;
        int err;
 
-       idata = kzalloc(sizeof(*idata), GFP_KERNEL);
+       idata = kmalloc(sizeof(*idata), GFP_KERNEL);
        if (!idata) {
                err = -ENOMEM;
                goto out;
@@ -364,7 +360,7 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
        if (!idata->buf_bytes)
                return idata;
 
-       idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL);
+       idata->buf = kmalloc(idata->buf_bytes, GFP_KERNEL);
        if (!idata->buf) {
                err = -ENOMEM;
                goto idata_err;
@@ -2244,6 +2240,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
        md->disk->queue = md->queue.queue;
        md->disk->driverfs_dev = parent;
        set_disk_ro(md->disk, md->read_only || default_ro);
+       md->disk->flags = GENHD_FL_EXT_DEVT;
        if (area_type & (MMC_BLK_DATA_AREA_RPMB | MMC_BLK_DATA_AREA_BOOT))
                md->disk->flags |= GENHD_FL_NO_PART_SCAN;
 
index 972ff844cf5a3ef6ff0c7cd9fe8914beb5d021b2..4bc48f10452fb02dc7ada8d6a8fd4cef11fde41f 100644 (file)
@@ -349,6 +349,8 @@ int mmc_add_card(struct mmc_card *card)
 
        card->dev.of_node = mmc_of_find_child_device(card->host, 0);
 
+       device_enable_async_suspend(&card->dev);
+
        ret = device_add(&card->dev);
        if (ret)
                return ret;
index 5ae89e48fd85b575cf743363b3a298b49872b7db..f95d41ffc766e5038059d0be82eaeb6aa4b0fe7a 100644 (file)
@@ -55,7 +55,6 @@
  */
 #define MMC_BKOPS_MAX_TIMEOUT  (4 * 60 * 1000) /* max time to wait in ms */
 
-static struct workqueue_struct *workqueue;
 static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
 
 /*
@@ -66,21 +65,16 @@ static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
 bool use_spi_crc = 1;
 module_param(use_spi_crc, bool, 0);
 
-/*
- * Internal function. Schedule delayed work in the MMC work queue.
- */
 static int mmc_schedule_delayed_work(struct delayed_work *work,
                                     unsigned long delay)
 {
-       return queue_delayed_work(workqueue, work, delay);
-}
-
-/*
- * Internal function. Flush all scheduled work from the MMC work queue.
- */
-static void mmc_flush_scheduled_work(void)
-{
-       flush_workqueue(workqueue);
+       /*
+        * We use the system_freezable_wq, because of two reasons.
+        * First, it allows several works (not the same work item) to be
+        * executed simultaneously. Second, the queue becomes frozen when
+        * userspace becomes frozen during system PM.
+        */
+       return queue_delayed_work(system_freezable_wq, work, delay);
 }
 
 #ifdef CONFIG_FAIL_MMC_REQUEST
@@ -1485,7 +1479,7 @@ int mmc_regulator_get_supply(struct mmc_host *mmc)
        if (IS_ERR(mmc->supply.vmmc)) {
                if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
-               dev_info(dev, "No vmmc regulator found\n");
+               dev_dbg(dev, "No vmmc regulator found\n");
        } else {
                ret = mmc_regulator_get_ocrmask(mmc->supply.vmmc);
                if (ret > 0)
@@ -1497,7 +1491,7 @@ int mmc_regulator_get_supply(struct mmc_host *mmc)
        if (IS_ERR(mmc->supply.vqmmc)) {
                if (PTR_ERR(mmc->supply.vqmmc) == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
-               dev_info(dev, "No vqmmc regulator found\n");
+               dev_dbg(dev, "No vqmmc regulator found\n");
        }
 
        return 0;
@@ -2476,15 +2470,20 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
         * sdio_reset sends CMD52 to reset card.  Since we do not know
         * if the card is being re-initialized, just send it.  CMD52
         * should be ignored by SD/eMMC cards.
+        * Skip it if we already know that we do not support SDIO commands
         */
-       sdio_reset(host);
+       if (!(host->caps2 & MMC_CAP2_NO_SDIO))
+               sdio_reset(host);
+
        mmc_go_idle(host);
 
        mmc_send_if_cond(host, host->ocr_avail);
 
        /* Order's important: probe SDIO, then SD, then MMC */
-       if (!mmc_attach_sdio(host))
-               return 0;
+       if (!(host->caps2 & MMC_CAP2_NO_SDIO))
+               if (!mmc_attach_sdio(host))
+                       return 0;
+
        if (!mmc_attach_sd(host))
                return 0;
        if (!mmc_attach_mmc(host))
@@ -2498,9 +2497,6 @@ int _mmc_detect_card_removed(struct mmc_host *host)
 {
        int ret;
 
-       if (host->caps & MMC_CAP_NONREMOVABLE)
-               return 0;
-
        if (!host->card || mmc_card_removed(host->card))
                return 1;
 
@@ -2536,6 +2532,9 @@ int mmc_detect_card_removed(struct mmc_host *host)
        if (!card)
                return 1;
 
+       if (host->caps & MMC_CAP_NONREMOVABLE)
+               return 0;
+
        ret = mmc_card_removed(card);
        /*
         * The card will be considered unchanged unless we have been asked to
@@ -2567,11 +2566,6 @@ void mmc_rescan(struct work_struct *work)
                container_of(work, struct mmc_host, detect.work);
        int i;
 
-       if (host->trigger_card_event && host->ops->card_event) {
-               host->ops->card_event(host);
-               host->trigger_card_event = false;
-       }
-
        if (host->rescan_disable)
                return;
 
@@ -2580,6 +2574,13 @@ void mmc_rescan(struct work_struct *work)
                return;
        host->rescan_entered = 1;
 
+       if (host->trigger_card_event && host->ops->card_event) {
+               mmc_claim_host(host);
+               host->ops->card_event(host);
+               mmc_release_host(host);
+               host->trigger_card_event = false;
+       }
+
        mmc_bus_get(host);
 
        /*
@@ -2611,15 +2612,14 @@ void mmc_rescan(struct work_struct *work)
         */
        mmc_bus_put(host);
 
+       mmc_claim_host(host);
        if (!(host->caps & MMC_CAP_NONREMOVABLE) && host->ops->get_cd &&
                        host->ops->get_cd(host) == 0) {
-               mmc_claim_host(host);
                mmc_power_off(host);
                mmc_release_host(host);
                goto out;
        }
 
-       mmc_claim_host(host);
        for (i = 0; i < ARRAY_SIZE(freqs); i++) {
                if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))
                        break;
@@ -2663,7 +2663,6 @@ void mmc_stop_host(struct mmc_host *host)
 
        host->rescan_disable = 1;
        cancel_delayed_work_sync(&host->detect);
-       mmc_flush_scheduled_work();
 
        /* clear pm flags now and let card drivers set them as needed */
        host->pm_flags = 0;
@@ -2759,14 +2758,13 @@ int mmc_flush_cache(struct mmc_card *card)
 }
 EXPORT_SYMBOL(mmc_flush_cache);
 
-#ifdef CONFIG_PM
-
+#ifdef CONFIG_PM_SLEEP
 /* Do the card removal on suspend if card is assumed removeable
  * Do that in pm notifier while userspace isn't yet frozen, so we will be able
    to sync the card.
 */
-int mmc_pm_notify(struct notifier_block *notify_block,
-                                       unsigned long mode, void *unused)
+static int mmc_pm_notify(struct notifier_block *notify_block,
+                       unsigned long mode, void *unused)
 {
        struct mmc_host *host = container_of(
                notify_block, struct mmc_host, pm_notify);
@@ -2813,6 +2811,17 @@ int mmc_pm_notify(struct notifier_block *notify_block,
 
        return 0;
 }
+
+void mmc_register_pm_notifier(struct mmc_host *host)
+{
+       host->pm_notify.notifier_call = mmc_pm_notify;
+       register_pm_notifier(&host->pm_notify);
+}
+
+void mmc_unregister_pm_notifier(struct mmc_host *host)
+{
+       unregister_pm_notifier(&host->pm_notify);
+}
 #endif
 
 /**
@@ -2836,13 +2845,9 @@ static int __init mmc_init(void)
 {
        int ret;
 
-       workqueue = alloc_ordered_workqueue("kmmcd", 0);
-       if (!workqueue)
-               return -ENOMEM;
-
        ret = mmc_register_bus();
        if (ret)
-               goto destroy_workqueue;
+               return ret;
 
        ret = mmc_register_host_class();
        if (ret)
@@ -2858,9 +2863,6 @@ unregister_host_class:
        mmc_unregister_host_class();
 unregister_bus:
        mmc_unregister_bus();
-destroy_workqueue:
-       destroy_workqueue(workqueue);
-
        return ret;
 }
 
@@ -2869,7 +2871,6 @@ static void __exit mmc_exit(void)
        sdio_unregister_bus();
        mmc_unregister_host_class();
        mmc_unregister_bus();
-       destroy_workqueue(workqueue);
 }
 
 subsys_initcall(mmc_init);
index 09241e56d62872ec3b4c3b6cc24ef815e29ed3d8..0fa86a2afc265e7224520f22892e12cfc652a2e2 100644 (file)
@@ -90,5 +90,13 @@ int mmc_execute_tuning(struct mmc_card *card);
 int mmc_hs200_to_hs400(struct mmc_card *card);
 int mmc_hs400_to_hs200(struct mmc_card *card);
 
+#ifdef CONFIG_PM_SLEEP
+void mmc_register_pm_notifier(struct mmc_host *host);
+void mmc_unregister_pm_notifier(struct mmc_host *host);
+#else
+static inline void mmc_register_pm_notifier(struct mmc_host *host) { }
+static inline void mmc_unregister_pm_notifier(struct mmc_host *host) { }
+#endif
+
 #endif
 
index da950c44204d27d6db8cd5a2d56b6b3e88e27c09..0aecd5c00b866571a852c19c91af766591d4025e 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/export.h>
 #include <linux/leds.h>
 #include <linux/slab.h>
-#include <linux/suspend.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
@@ -275,7 +274,8 @@ int mmc_of_parse(struct mmc_host *host)
                host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
        if (of_property_read_bool(np, "keep-power-in-suspend"))
                host->pm_caps |= MMC_PM_KEEP_POWER;
-       if (of_property_read_bool(np, "enable-sdio-wakeup"))
+       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-1_8v"))
                host->caps |= MMC_CAP_1_8V_DDR;
@@ -348,9 +348,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
        spin_lock_init(&host->lock);
        init_waitqueue_head(&host->wq);
        INIT_DELAYED_WORK(&host->detect, mmc_rescan);
-#ifdef CONFIG_PM
-       host->pm_notify.notifier_call = mmc_pm_notify;
-#endif
        setup_timer(&host->retune_timer, mmc_retune_timer, (unsigned long)host);
 
        /*
@@ -395,7 +392,7 @@ int mmc_add_host(struct mmc_host *host)
 #endif
 
        mmc_start_host(host);
-       register_pm_notifier(&host->pm_notify);
+       mmc_register_pm_notifier(host);
 
        return 0;
 }
@@ -412,7 +409,7 @@ EXPORT_SYMBOL(mmc_add_host);
  */
 void mmc_remove_host(struct mmc_host *host)
 {
-       unregister_pm_notifier(&host->pm_notify);
+       mmc_unregister_pm_notifier(host);
        mmc_stop_host(host);
 
 #ifdef CONFIG_DEBUG_FS
index 3a9a79ec4343cd0f9f71158768e5707340def684..bf49e44571f20a21b88cda5c1f35a5c222cfcf32 100644 (file)
@@ -1076,8 +1076,7 @@ static int mmc_select_hs400(struct mmc_card *card)
        mmc_set_clock(host, max_dtr);
 
        /* Switch card to HS mode */
-       val = EXT_CSD_TIMING_HS |
-             card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
+       val = EXT_CSD_TIMING_HS;
        err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                           EXT_CSD_HS_TIMING, val,
                           card->ext_csd.generic_cmd6_time,
@@ -1160,8 +1159,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
        mmc_set_clock(host, max_dtr);
 
        /* Switch HS400 to HS DDR */
-       val = EXT_CSD_TIMING_HS |
-             card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
+       val = EXT_CSD_TIMING_HS;
        err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
                           val, card->ext_csd.generic_cmd6_time,
                           true, send_status, true);
@@ -1907,16 +1905,8 @@ static int mmc_shutdown(struct mmc_host *host)
  */
 static int mmc_resume(struct mmc_host *host)
 {
-       int err = 0;
-
-       if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) {
-               err = _mmc_resume(host);
-               pm_runtime_set_active(&host->card->dev);
-               pm_runtime_mark_last_busy(&host->card->dev);
-       }
        pm_runtime_enable(&host->card->dev);
-
-       return err;
+       return 0;
 }
 
 /*
@@ -1944,12 +1934,9 @@ static int mmc_runtime_resume(struct mmc_host *host)
 {
        int err;
 
-       if (!(host->caps & (MMC_CAP_AGGRESSIVE_PM | MMC_CAP_RUNTIME_RESUME)))
-               return 0;
-
        err = _mmc_resume(host);
-       if (err)
-               pr_err("%s: error %d doing aggressive resume\n",
+       if (err && err != -ENOMEDIUM)
+               pr_err("%s: error %d doing runtime resume\n",
                        mmc_hostname(host), err);
 
        return 0;
index 1f444269ebbe66027831757403d1bdd53d1b6a8d..2c90635c89afbb3782a48145fe830828dca4ec27 100644 (file)
@@ -489,6 +489,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
        unsigned long timeout;
        u32 status = 0;
        bool use_r1b_resp = use_busy_signal;
+       bool expired = false;
 
        mmc_retune_hold(host);
 
@@ -545,6 +546,12 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
        timeout = jiffies + msecs_to_jiffies(timeout_ms);
        do {
                if (send_status) {
+                       /*
+                        * Due to the possibility of being preempted after
+                        * sending the status command, check the expiration
+                        * time first.
+                        */
+                       expired = time_after(jiffies, timeout);
                        err = __mmc_send_status(card, &status, ignore_crc);
                        if (err)
                                goto out;
@@ -565,7 +572,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                }
 
                /* Timeout if the device never leaves the program state. */
-               if (time_after(jiffies, timeout)) {
+               if (expired && R1_CURRENT_STATE(status) == R1_STATE_PRG) {
                        pr_err("%s: Card stuck in programming state! %s\n",
                                mmc_hostname(host), __func__);
                        err = -ETIMEDOUT;
index 096da48c6a7ecbb0ba294e6fd1bf9513b02bca36..133de042668786c2617417c091db2edba3ce0418 100644 (file)
@@ -16,7 +16,7 @@ struct mmc_pwrseq_ops {
 };
 
 struct mmc_pwrseq {
-       struct mmc_pwrseq_ops *ops;
+       const struct mmc_pwrseq_ops *ops;
 };
 
 #ifdef CONFIG_OF
index ad4f94ec7e8d465a4e4e45ba9388fb7d97231f4a..4a82bc77fe4978115bc3dfd4c4ccf5b44afb673c 100644 (file)
@@ -51,7 +51,7 @@ static void mmc_pwrseq_emmc_free(struct mmc_host *host)
        kfree(pwrseq);
 }
 
-static struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = {
+static const struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = {
        .post_power_on = mmc_pwrseq_emmc_reset,
        .free = mmc_pwrseq_emmc_free,
 };
index d10538bb5e07ac298fcadad3003bd84c02fa00d5..2b16263458af001723636f7770bbf4906b16b07c 100644 (file)
@@ -87,7 +87,7 @@ static void mmc_pwrseq_simple_free(struct mmc_host *host)
        kfree(pwrseq);
 }
 
-static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
+static const struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
        .pre_power_on = mmc_pwrseq_simple_pre_power_on,
        .post_power_on = mmc_pwrseq_simple_post_power_on,
        .power_off = mmc_pwrseq_simple_power_off,
index 141eaa923e18eecc140039d34604d5f2969c023b..f2b164b214ae289dd313a0945cbbd5dd7e1dc532 100644 (file)
@@ -1128,16 +1128,8 @@ out:
  */
 static int mmc_sd_resume(struct mmc_host *host)
 {
-       int err = 0;
-
-       if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) {
-               err = _mmc_sd_resume(host);
-               pm_runtime_set_active(&host->card->dev);
-               pm_runtime_mark_last_busy(&host->card->dev);
-       }
        pm_runtime_enable(&host->card->dev);
-
-       return err;
+       return 0;
 }
 
 /*
@@ -1165,12 +1157,9 @@ static int mmc_sd_runtime_resume(struct mmc_host *host)
 {
        int err;
 
-       if (!(host->caps & (MMC_CAP_AGGRESSIVE_PM | MMC_CAP_RUNTIME_RESUME)))
-               return 0;
-
        err = _mmc_sd_resume(host);
-       if (err)
-               pr_err("%s: error %d doing aggressive resume\n",
+       if (err && err != -ENOMEDIUM)
+               pr_err("%s: error %d doing runtime resume\n",
                        mmc_hostname(host), err);
 
        return 0;
index 16d838e6d623be3968a7a900e85348d17a642fe3..d61ba1a0495ebe828ba8c110da3d9053b506079b 100644 (file)
@@ -630,7 +630,7 @@ try_again:
         */
        if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) {
                err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
-                                       ocr);
+                                       ocr_card);
                if (err == -EAGAIN) {
                        sdio_reset(host);
                        mmc_go_idle(host);
index 7e327a6dd53da304cc59b9012e311504bfaf67df..86f5b3223aaeec29a110fa0b2851b652b66d0dc5 100644 (file)
@@ -322,6 +322,7 @@ int sdio_add_func(struct sdio_func *func)
 
        sdio_set_of_node(func);
        sdio_acpi_set_handle(func);
+       device_enable_async_suspend(&func->dev);
        ret = device_add(&func->dev);
        if (ret == 0)
                sdio_func_set_present(func);
index 1dee533634c986d71176917f4d510a4c7214bf5a..1526b8a10b094e88e52275e46446ff3e8b66afdf 100644 (file)
@@ -455,6 +455,7 @@ config MMC_TIFM_SD
 config MMC_MVSDIO
        tristate "Marvell MMC/SD/SDIO host driver"
        depends on PLAT_ORION
+       depends on OF
        ---help---
          This selects the Marvell SDIO host driver.
          SDIO may currently be found on the Kirkwood 88F6281 and 88F6192
diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h
deleted file mode 100644 (file)
index 0aa44e6..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Atmel MultiMedia Card Interface driver
- *
- * Copyright (C) 2004-2006 Atmel 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.
- */
-
-/*
- * Superset of MCI IP registers integrated in Atmel AVR32 and AT91 Processors
- * Registers and bitfields marked with [2] are only available in MCI2
- */
-
-#ifndef __DRIVERS_MMC_ATMEL_MCI_H__
-#define __DRIVERS_MMC_ATMEL_MCI_H__
-
-/* MCI Register Definitions */
-#define ATMCI_CR                       0x0000  /* Control */
-# define ATMCI_CR_MCIEN                        (  1 <<  0)     /* MCI Enable */
-# define ATMCI_CR_MCIDIS               (  1 <<  1)     /* MCI Disable */
-# define ATMCI_CR_PWSEN                        (  1 <<  2)     /* Power Save Enable */
-# define ATMCI_CR_PWSDIS               (  1 <<  3)     /* Power Save Disable */
-# define ATMCI_CR_SWRST                        (  1 <<  7)     /* Software Reset */
-#define ATMCI_MR                       0x0004  /* Mode */
-# define ATMCI_MR_CLKDIV(x)            ((x) <<  0)     /* Clock Divider */
-# define ATMCI_MR_PWSDIV(x)            ((x) <<  8)     /* Power Saving Divider */
-# define ATMCI_MR_RDPROOF              (  1 << 11)     /* Read Proof */
-# define ATMCI_MR_WRPROOF              (  1 << 12)     /* Write Proof */
-# define ATMCI_MR_PDCFBYTE             (  1 << 13)     /* Force Byte Transfer */
-# define ATMCI_MR_PDCPADV              (  1 << 14)     /* Padding Value */
-# define ATMCI_MR_PDCMODE              (  1 << 15)     /* PDC-oriented Mode */
-# define ATMCI_MR_CLKODD(x)            ((x) << 16)     /* LSB of Clock Divider */
-#define ATMCI_DTOR                     0x0008  /* Data Timeout */
-# define ATMCI_DTOCYC(x)               ((x) <<  0)     /* Data Timeout Cycles */
-# define ATMCI_DTOMUL(x)               ((x) <<  4)     /* Data Timeout Multiplier */
-#define ATMCI_SDCR                     0x000c  /* SD Card / SDIO */
-# define ATMCI_SDCSEL_SLOT_A           (  0 <<  0)     /* Select SD slot A */
-# define ATMCI_SDCSEL_SLOT_B           (  1 <<  0)     /* Select SD slot A */
-# define ATMCI_SDCSEL_MASK             (  3 <<  0)
-# define ATMCI_SDCBUS_1BIT             (  0 <<  6)     /* 1-bit data bus */
-# define ATMCI_SDCBUS_4BIT             (  2 <<  6)     /* 4-bit data bus */
-# define ATMCI_SDCBUS_8BIT             (  3 <<  6)     /* 8-bit data bus[2] */
-# define ATMCI_SDCBUS_MASK             (  3 <<  6)
-#define ATMCI_ARGR                     0x0010  /* Command Argument */
-#define ATMCI_CMDR                     0x0014  /* Command */
-# define ATMCI_CMDR_CMDNB(x)           ((x) <<  0)     /* Command Opcode */
-# define ATMCI_CMDR_RSPTYP_NONE                (  0 <<  6)     /* No response */
-# define ATMCI_CMDR_RSPTYP_48BIT       (  1 <<  6)     /* 48-bit response */
-# define ATMCI_CMDR_RSPTYP_136BIT      (  2 <<  6)     /* 136-bit response */
-# define ATMCI_CMDR_SPCMD_INIT         (  1 <<  8)     /* Initialization command */
-# define ATMCI_CMDR_SPCMD_SYNC         (  2 <<  8)     /* Synchronized command */
-# define ATMCI_CMDR_SPCMD_INT          (  4 <<  8)     /* Interrupt command */
-# define ATMCI_CMDR_SPCMD_INTRESP      (  5 <<  8)     /* Interrupt response */
-# define ATMCI_CMDR_OPDCMD             (  1 << 11)     /* Open Drain */
-# define ATMCI_CMDR_MAXLAT_5CYC                (  0 << 12)     /* Max latency 5 cycles */
-# define ATMCI_CMDR_MAXLAT_64CYC       (  1 << 12)     /* Max latency 64 cycles */
-# define ATMCI_CMDR_START_XFER         (  1 << 16)     /* Start data transfer */
-# define ATMCI_CMDR_STOP_XFER          (  2 << 16)     /* Stop data transfer */
-# define ATMCI_CMDR_TRDIR_WRITE                (  0 << 18)     /* Write data */
-# define ATMCI_CMDR_TRDIR_READ         (  1 << 18)     /* Read data */
-# define ATMCI_CMDR_BLOCK              (  0 << 19)     /* Single-block transfer */
-# define ATMCI_CMDR_MULTI_BLOCK                (  1 << 19)     /* Multi-block transfer */
-# define ATMCI_CMDR_STREAM             (  2 << 19)     /* MMC Stream transfer */
-# define ATMCI_CMDR_SDIO_BYTE          (  4 << 19)     /* SDIO Byte transfer */
-# define ATMCI_CMDR_SDIO_BLOCK         (  5 << 19)     /* SDIO Block transfer */
-# define ATMCI_CMDR_SDIO_SUSPEND       (  1 << 24)     /* SDIO Suspend Command */
-# define ATMCI_CMDR_SDIO_RESUME                (  2 << 24)     /* SDIO Resume Command */
-#define ATMCI_BLKR                     0x0018  /* Block */
-# define ATMCI_BCNT(x)                 ((x) <<  0)     /* Data Block Count */
-# define ATMCI_BLKLEN(x)               ((x) << 16)     /* Data Block Length */
-#define ATMCI_CSTOR                    0x001c  /* Completion Signal Timeout[2] */
-# define ATMCI_CSTOCYC(x)              ((x) <<  0)     /* CST cycles */
-# define ATMCI_CSTOMUL(x)              ((x) <<  4)     /* CST multiplier */
-#define ATMCI_RSPR                     0x0020  /* Response 0 */
-#define ATMCI_RSPR1                    0x0024  /* Response 1 */
-#define ATMCI_RSPR2                    0x0028  /* Response 2 */
-#define ATMCI_RSPR3                    0x002c  /* Response 3 */
-#define ATMCI_RDR                      0x0030  /* Receive Data */
-#define ATMCI_TDR                      0x0034  /* Transmit Data */
-#define ATMCI_SR                       0x0040  /* Status */
-#define ATMCI_IER                      0x0044  /* Interrupt Enable */
-#define ATMCI_IDR                      0x0048  /* Interrupt Disable */
-#define ATMCI_IMR                      0x004c  /* Interrupt Mask */
-# define ATMCI_CMDRDY                  (  1 <<   0)    /* Command Ready */
-# define ATMCI_RXRDY                   (  1 <<   1)    /* Receiver Ready */
-# define ATMCI_TXRDY                   (  1 <<   2)    /* Transmitter Ready */
-# define ATMCI_BLKE                    (  1 <<   3)    /* Data Block Ended */
-# define ATMCI_DTIP                    (  1 <<   4)    /* Data Transfer In Progress */
-# define ATMCI_NOTBUSY                 (  1 <<   5)    /* Data Not Busy */
-# define ATMCI_ENDRX                   (  1 <<   6)    /* End of RX Buffer */
-# define ATMCI_ENDTX                   (  1 <<   7)    /* End of TX Buffer */
-# define ATMCI_SDIOIRQA                        (  1 <<   8)    /* SDIO IRQ in slot A */
-# define ATMCI_SDIOIRQB                        (  1 <<   9)    /* SDIO IRQ in slot B */
-# define ATMCI_SDIOWAIT                        (  1 <<  12)    /* SDIO Read Wait Operation Status */
-# define ATMCI_CSRCV                   (  1 <<  13)    /* CE-ATA Completion Signal Received */
-# define ATMCI_RXBUFF                  (  1 <<  14)    /* RX Buffer Full */
-# define ATMCI_TXBUFE                  (  1 <<  15)    /* TX Buffer Empty */
-# define ATMCI_RINDE                   (  1 <<  16)    /* Response Index Error */
-# define ATMCI_RDIRE                   (  1 <<  17)    /* Response Direction Error */
-# define ATMCI_RCRCE                   (  1 <<  18)    /* Response CRC Error */
-# define ATMCI_RENDE                   (  1 <<  19)    /* Response End Bit Error */
-# define ATMCI_RTOE                    (  1 <<  20)    /* Response Time-Out Error */
-# define ATMCI_DCRCE                   (  1 <<  21)    /* Data CRC Error */
-# define ATMCI_DTOE                    (  1 <<  22)    /* Data Time-Out Error */
-# define ATMCI_CSTOE                   (  1 <<  23)    /* Completion Signal Time-out Error */
-# define ATMCI_BLKOVRE                 (  1 <<  24)    /* DMA Block Overrun Error */
-# define ATMCI_DMADONE                 (  1 <<  25)    /* DMA Transfer Done */
-# define ATMCI_FIFOEMPTY               (  1 <<  26)    /* FIFO Empty Flag */
-# define ATMCI_XFRDONE                 (  1 <<  27)    /* Transfer Done Flag */
-# define ATMCI_ACKRCV                  (  1 <<  28)    /* Boot Operation Acknowledge Received */
-# define ATMCI_ACKRCVE                 (  1 <<  29)    /* Boot Operation Acknowledge Error */
-# define ATMCI_OVRE                    (  1 <<  30)    /* RX Overrun Error */
-# define ATMCI_UNRE                    (  1 <<  31)    /* TX Underrun Error */
-#define ATMCI_DMA                      0x0050  /* DMA Configuration[2] */
-# define ATMCI_DMA_OFFSET(x)           ((x) <<  0)     /* DMA Write Buffer Offset */
-# define ATMCI_DMA_CHKSIZE(x)          ((x) <<  4)     /* DMA Channel Read and Write Chunk Size */
-# define ATMCI_DMAEN                   (  1 <<  8)     /* DMA Hardware Handshaking Enable */
-#define ATMCI_CFG                      0x0054  /* Configuration[2] */
-# define ATMCI_CFG_FIFOMODE_1DATA      (  1 <<  0)     /* MCI Internal FIFO control mode */
-# define ATMCI_CFG_FERRCTRL_COR                (  1 <<  4)     /* Flow Error flag reset control mode */
-# define ATMCI_CFG_HSMODE              (  1 <<  8)     /* High Speed Mode */
-# define ATMCI_CFG_LSYNC               (  1 << 12)     /* Synchronize on the last block */
-#define ATMCI_WPMR                     0x00e4  /* Write Protection Mode[2] */
-# define ATMCI_WP_EN                   (  1 <<  0)     /* WP Enable */
-# define ATMCI_WP_KEY                  (0x4d4349 << 8) /* WP Key */
-#define ATMCI_WPSR                     0x00e8  /* Write Protection Status[2] */
-# define ATMCI_GET_WP_VS(x)            ((x) & 0x0f)
-# define ATMCI_GET_WP_VSRC(x)          (((x) >> 8) & 0xffff)
-#define ATMCI_VERSION                  0x00FC  /* Version */
-#define ATMCI_FIFO_APERTURE            0x0200  /* FIFO Aperture[2] */
-
-/* This is not including the FIFO Aperture on MCI2 */
-#define ATMCI_REGS_SIZE                0x100
-
-/* Register access macros */
-#ifdef CONFIG_AVR32
-#define atmci_readl(port, reg)                 \
-       __raw_readl((port)->regs + reg)
-#define atmci_writel(port, reg, value)                 \
-       __raw_writel((value), (port)->regs + reg)
-#else
-#define atmci_readl(port, reg)                 \
-       readl_relaxed((port)->regs + reg)
-#define atmci_writel(port, reg, value)                 \
-       writel_relaxed((value), (port)->regs + reg)
-#endif
-
-/* On AVR chips the Peripheral DMA Controller is not connected to MCI. */
-#ifdef CONFIG_AVR32
-#      define ATMCI_PDC_CONNECTED      0
-#else
-#      define ATMCI_PDC_CONNECTED      1
-#endif
-
-/*
- * Fix sconfig's burst size according to atmel MCI. We need to convert them as:
- * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
- *
- * This can be done by finding most significant bit set.
- */
-static inline unsigned int atmci_convert_chksize(unsigned int maxburst)
-{
-       if (maxburst > 1)
-               return fls(maxburst) - 2;
-       else
-               return 0;
-}
-
-#endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */
index bf62e429f7fcc1902d2275677d41cebca8ff5cb5..a36ebdae238834a9160ceeed51b28d2f828a8bbc 100644 (file)
 #include <asm/io.h>
 #include <asm/unaligned.h>
 
-#include "atmel-mci-regs.h"
+/*
+ * Superset of MCI IP registers integrated in Atmel AVR32 and AT91 Processors
+ * Registers and bitfields marked with [2] are only available in MCI2
+ */
+
+/* MCI Register Definitions */
+#define        ATMCI_CR                        0x0000  /* Control */
+#define                ATMCI_CR_MCIEN                  BIT(0)          /* MCI Enable */
+#define                ATMCI_CR_MCIDIS                 BIT(1)          /* MCI Disable */
+#define                ATMCI_CR_PWSEN                  BIT(2)          /* Power Save Enable */
+#define                ATMCI_CR_PWSDIS                 BIT(3)          /* Power Save Disable */
+#define                ATMCI_CR_SWRST                  BIT(7)          /* Software Reset */
+#define        ATMCI_MR                        0x0004  /* Mode */
+#define                ATMCI_MR_CLKDIV(x)              ((x) <<  0)     /* Clock Divider */
+#define                ATMCI_MR_PWSDIV(x)              ((x) <<  8)     /* Power Saving Divider */
+#define                ATMCI_MR_RDPROOF                BIT(11)         /* Read Proof */
+#define                ATMCI_MR_WRPROOF                BIT(12)         /* Write Proof */
+#define                ATMCI_MR_PDCFBYTE               BIT(13)         /* Force Byte Transfer */
+#define                ATMCI_MR_PDCPADV                BIT(14)         /* Padding Value */
+#define                ATMCI_MR_PDCMODE                BIT(15)         /* PDC-oriented Mode */
+#define                ATMCI_MR_CLKODD(x)              ((x) << 16)     /* LSB of Clock Divider */
+#define        ATMCI_DTOR                      0x0008  /* Data Timeout */
+#define                ATMCI_DTOCYC(x)                 ((x) <<  0)     /* Data Timeout Cycles */
+#define                ATMCI_DTOMUL(x)                 ((x) <<  4)     /* Data Timeout Multiplier */
+#define        ATMCI_SDCR                      0x000c  /* SD Card / SDIO */
+#define                ATMCI_SDCSEL_SLOT_A             (0 <<  0)       /* Select SD slot A */
+#define                ATMCI_SDCSEL_SLOT_B             (1 <<  0)       /* Select SD slot A */
+#define                ATMCI_SDCSEL_MASK               (3 <<  0)
+#define                ATMCI_SDCBUS_1BIT               (0 <<  6)       /* 1-bit data bus */
+#define                ATMCI_SDCBUS_4BIT               (2 <<  6)       /* 4-bit data bus */
+#define                ATMCI_SDCBUS_8BIT               (3 <<  6)       /* 8-bit data bus[2] */
+#define                ATMCI_SDCBUS_MASK               (3 <<  6)
+#define        ATMCI_ARGR                      0x0010  /* Command Argument */
+#define        ATMCI_CMDR                      0x0014  /* Command */
+#define                ATMCI_CMDR_CMDNB(x)             ((x) <<  0)     /* Command Opcode */
+#define                ATMCI_CMDR_RSPTYP_NONE          (0 <<  6)       /* No response */
+#define                ATMCI_CMDR_RSPTYP_48BIT         (1 <<  6)       /* 48-bit response */
+#define                ATMCI_CMDR_RSPTYP_136BIT        (2 <<  6)       /* 136-bit response */
+#define                ATMCI_CMDR_SPCMD_INIT           (1 <<  8)       /* Initialization command */
+#define                ATMCI_CMDR_SPCMD_SYNC           (2 <<  8)       /* Synchronized command */
+#define                ATMCI_CMDR_SPCMD_INT            (4 <<  8)       /* Interrupt command */
+#define                ATMCI_CMDR_SPCMD_INTRESP        (5 <<  8)       /* Interrupt response */
+#define                ATMCI_CMDR_OPDCMD               (1 << 11)       /* Open Drain */
+#define                ATMCI_CMDR_MAXLAT_5CYC          (0 << 12)       /* Max latency 5 cycles */
+#define                ATMCI_CMDR_MAXLAT_64CYC         (1 << 12)       /* Max latency 64 cycles */
+#define                ATMCI_CMDR_START_XFER           (1 << 16)       /* Start data transfer */
+#define                ATMCI_CMDR_STOP_XFER            (2 << 16)       /* Stop data transfer */
+#define                ATMCI_CMDR_TRDIR_WRITE          (0 << 18)       /* Write data */
+#define                ATMCI_CMDR_TRDIR_READ           (1 << 18)       /* Read data */
+#define                ATMCI_CMDR_BLOCK                (0 << 19)       /* Single-block transfer */
+#define                ATMCI_CMDR_MULTI_BLOCK          (1 << 19)       /* Multi-block transfer */
+#define                ATMCI_CMDR_STREAM               (2 << 19)       /* MMC Stream transfer */
+#define                ATMCI_CMDR_SDIO_BYTE            (4 << 19)       /* SDIO Byte transfer */
+#define                ATMCI_CMDR_SDIO_BLOCK           (5 << 19)       /* SDIO Block transfer */
+#define                ATMCI_CMDR_SDIO_SUSPEND         (1 << 24)       /* SDIO Suspend Command */
+#define                ATMCI_CMDR_SDIO_RESUME          (2 << 24)       /* SDIO Resume Command */
+#define        ATMCI_BLKR                      0x0018  /* Block */
+#define                ATMCI_BCNT(x)                   ((x) <<  0)     /* Data Block Count */
+#define                ATMCI_BLKLEN(x)                 ((x) << 16)     /* Data Block Length */
+#define        ATMCI_CSTOR                     0x001c  /* Completion Signal Timeout[2] */
+#define                ATMCI_CSTOCYC(x)                ((x) <<  0)     /* CST cycles */
+#define                ATMCI_CSTOMUL(x)                ((x) <<  4)     /* CST multiplier */
+#define        ATMCI_RSPR                      0x0020  /* Response 0 */
+#define        ATMCI_RSPR1                     0x0024  /* Response 1 */
+#define        ATMCI_RSPR2                     0x0028  /* Response 2 */
+#define        ATMCI_RSPR3                     0x002c  /* Response 3 */
+#define        ATMCI_RDR                       0x0030  /* Receive Data */
+#define        ATMCI_TDR                       0x0034  /* Transmit Data */
+#define        ATMCI_SR                        0x0040  /* Status */
+#define        ATMCI_IER                       0x0044  /* Interrupt Enable */
+#define        ATMCI_IDR                       0x0048  /* Interrupt Disable */
+#define        ATMCI_IMR                       0x004c  /* Interrupt Mask */
+#define                ATMCI_CMDRDY                    BIT(0)          /* Command Ready */
+#define                ATMCI_RXRDY                     BIT(1)          /* Receiver Ready */
+#define                ATMCI_TXRDY                     BIT(2)          /* Transmitter Ready */
+#define                ATMCI_BLKE                      BIT(3)          /* Data Block Ended */
+#define                ATMCI_DTIP                      BIT(4)          /* Data Transfer In Progress */
+#define                ATMCI_NOTBUSY                   BIT(5)          /* Data Not Busy */
+#define                ATMCI_ENDRX                     BIT(6)          /* End of RX Buffer */
+#define                ATMCI_ENDTX                     BIT(7)          /* End of TX Buffer */
+#define                ATMCI_SDIOIRQA                  BIT(8)          /* SDIO IRQ in slot A */
+#define                ATMCI_SDIOIRQB                  BIT(9)          /* SDIO IRQ in slot B */
+#define                ATMCI_SDIOWAIT                  BIT(12)         /* SDIO Read Wait Operation Status */
+#define                ATMCI_CSRCV                     BIT(13)         /* CE-ATA Completion Signal Received */
+#define                ATMCI_RXBUFF                    BIT(14)         /* RX Buffer Full */
+#define                ATMCI_TXBUFE                    BIT(15)         /* TX Buffer Empty */
+#define                ATMCI_RINDE                     BIT(16)         /* Response Index Error */
+#define                ATMCI_RDIRE                     BIT(17)         /* Response Direction Error */
+#define                ATMCI_RCRCE                     BIT(18)         /* Response CRC Error */
+#define                ATMCI_RENDE                     BIT(19)         /* Response End Bit Error */
+#define                ATMCI_RTOE                      BIT(20)         /* Response Time-Out Error */
+#define                ATMCI_DCRCE                     BIT(21)         /* Data CRC Error */
+#define                ATMCI_DTOE                      BIT(22)         /* Data Time-Out Error */
+#define                ATMCI_CSTOE                     BIT(23)         /* Completion Signal Time-out Error */
+#define                ATMCI_BLKOVRE                   BIT(24)         /* DMA Block Overrun Error */
+#define                ATMCI_DMADONE                   BIT(25)         /* DMA Transfer Done */
+#define                ATMCI_FIFOEMPTY                 BIT(26)         /* FIFO Empty Flag */
+#define                ATMCI_XFRDONE                   BIT(27)         /* Transfer Done Flag */
+#define                ATMCI_ACKRCV                    BIT(28)         /* Boot Operation Acknowledge Received */
+#define                ATMCI_ACKRCVE                   BIT(29)         /* Boot Operation Acknowledge Error */
+#define                ATMCI_OVRE                      BIT(30)         /* RX Overrun Error */
+#define                ATMCI_UNRE                      BIT(31)         /* TX Underrun Error */
+#define        ATMCI_DMA                       0x0050  /* DMA Configuration[2] */
+#define                ATMCI_DMA_OFFSET(x)             ((x) <<  0)     /* DMA Write Buffer Offset */
+#define                ATMCI_DMA_CHKSIZE(x)            ((x) <<  4)     /* DMA Channel Read and Write Chunk Size */
+#define                ATMCI_DMAEN                     BIT(8)  /* DMA Hardware Handshaking Enable */
+#define        ATMCI_CFG                       0x0054  /* Configuration[2] */
+#define                ATMCI_CFG_FIFOMODE_1DATA        BIT(0)          /* MCI Internal FIFO control mode */
+#define                ATMCI_CFG_FERRCTRL_COR          BIT(4)          /* Flow Error flag reset control mode */
+#define                ATMCI_CFG_HSMODE                BIT(8)          /* High Speed Mode */
+#define                ATMCI_CFG_LSYNC                 BIT(12)         /* Synchronize on the last block */
+#define        ATMCI_WPMR                      0x00e4  /* Write Protection Mode[2] */
+#define                ATMCI_WP_EN                     BIT(0)          /* WP Enable */
+#define                ATMCI_WP_KEY                    (0x4d4349 << 8) /* WP Key */
+#define        ATMCI_WPSR                      0x00e8  /* Write Protection Status[2] */
+#define                ATMCI_GET_WP_VS(x)              ((x) & 0x0f)
+#define                ATMCI_GET_WP_VSRC(x)            (((x) >> 8) & 0xffff)
+#define        ATMCI_VERSION                   0x00FC  /* Version */
+#define        ATMCI_FIFO_APERTURE             0x0200  /* FIFO Aperture[2] */
+
+/* This is not including the FIFO Aperture on MCI2 */
+#define        ATMCI_REGS_SIZE         0x100
+
+/* Register access macros */
+#define        atmci_readl(port, reg)                          \
+       __raw_readl((port)->regs + reg)
+#define        atmci_writel(port, reg, value)                  \
+       __raw_writel((value), (port)->regs + reg)
+
+/* On AVR chips the Peripheral DMA Controller is not connected to MCI. */
+#ifdef CONFIG_AVR32
+#      define ATMCI_PDC_CONNECTED      0
+#else
+#      define ATMCI_PDC_CONNECTED      1
+#endif
 
 #define AUTOSUSPEND_DELAY      50
 
@@ -584,6 +718,29 @@ static inline unsigned int atmci_get_version(struct atmel_mci *host)
        return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
 }
 
+/*
+ * Fix sconfig's burst size according to atmel MCI. We need to convert them as:
+ * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
+ * With version 0x600, we need to convert them as: 1 -> 0, 2 -> 1, 4 -> 2,
+ * 8 -> 3, 16 -> 4.
+ *
+ * This can be done by finding most significant bit set.
+ */
+static inline unsigned int atmci_convert_chksize(struct atmel_mci *host,
+                                                unsigned int maxburst)
+{
+       unsigned int version = atmci_get_version(host);
+       unsigned int offset = 2;
+
+       if (version >= 0x600)
+               offset = 1;
+
+       if (maxburst > 1)
+               return fls(maxburst) - offset;
+       else
+               return 0;
+}
+
 static void atmci_timeout_timer(unsigned long data)
 {
        struct atmel_mci *host;
@@ -1034,11 +1191,13 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
        if (data->flags & MMC_DATA_READ) {
                direction = DMA_FROM_DEVICE;
                host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM;
-               maxburst = atmci_convert_chksize(host->dma_conf.src_maxburst);
+               maxburst = atmci_convert_chksize(host,
+                                                host->dma_conf.src_maxburst);
        } else {
                direction = DMA_TO_DEVICE;
                host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV;
-               maxburst = atmci_convert_chksize(host->dma_conf.dst_maxburst);
+               maxburst = atmci_convert_chksize(host,
+                                                host->dma_conf.dst_maxburst);
        }
 
        if (host->caps.has_dma_conf_reg)
index 8984ec878fc9a05849d54728db15d6b4c7853cbd..8ecd9e56636a1b2e873cae16cd4b6821b15adeeb 100644 (file)
@@ -29,8 +29,7 @@ static inline struct mmc_host *cb710_slot_to_mmc(struct cb710_slot *slot)
 
 static inline struct cb710_slot *cb710_mmc_to_slot(struct mmc_host *mmc)
 {
-       struct platform_device *pdev = container_of(mmc_dev(mmc),
-               struct platform_device, dev);
+       struct platform_device *pdev = to_platform_device(mmc_dev(mmc));
        return cb710_pdev_to_slot(pdev);
 }
 
index 7e1d13b68b062b4199e65d914c7cac464e2b0daf..81bdeeb05a4d23426ecf39119a54d544eb8342f9 100644 (file)
@@ -60,7 +60,7 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
 
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        /* Get registers' physical base address */
-       host->phy_regs = (void *)(regs->start);
+       host->phy_regs = regs->start;
        host->regs = devm_ioremap_resource(&pdev->dev, regs);
        if (IS_ERR(host->regs))
                return PTR_ERR(host->regs);
index 9becebeeccd17c925d933aa4bff36954a217ff9c..d9c92f31da641e1c5d98e6d446f174ee61d6552a 100644 (file)
@@ -239,20 +239,12 @@ static int dw_mci_rockchip_init(struct dw_mci *host)
        return 0;
 }
 
-/* Common capabilities of RK3288 SoC */
-static unsigned long dw_mci_rk3288_dwmmc_caps[4] = {
-       MMC_CAP_RUNTIME_RESUME, /* emmc */
-       MMC_CAP_RUNTIME_RESUME, /* sdmmc */
-       MMC_CAP_RUNTIME_RESUME, /* sdio0 */
-       MMC_CAP_RUNTIME_RESUME, /* sdio1 */
-};
 static const struct dw_mci_drv_data rk2928_drv_data = {
        .prepare_command        = dw_mci_rockchip_prepare_command,
        .init                   = dw_mci_rockchip_init,
 };
 
 static const struct dw_mci_drv_data rk3288_drv_data = {
-       .caps                   = dw_mci_rk3288_dwmmc_caps,
        .prepare_command        = dw_mci_rockchip_prepare_command,
        .set_ios                = dw_mci_rk3288_set_ios,
        .execute_tuning         = dw_mci_rk3288_execute_tuning,
index 7a6cedbe48a837e7fd5800c9fe1da131d569df51..712835177e8b7ef0b49ff59155be3fef2bf5c678 100644 (file)
@@ -699,7 +699,7 @@ static int dw_mci_edmac_start_dma(struct dw_mci *host,
        int ret = 0;
 
        /* Set external dma config: burst size, burst width */
-       cfg.dst_addr = (dma_addr_t)(host->phy_regs + fifo_offset);
+       cfg.dst_addr = host->phy_regs + fifo_offset;
        cfg.src_addr = cfg.dst_addr;
        cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
        cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
@@ -1634,12 +1634,6 @@ static int dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd)
        else
                cmd->error = 0;
 
-       if (cmd->error) {
-               /* newer ip versions need a delay between retries */
-               if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY)
-                       mdelay(20);
-       }
-
        return cmd->error;
 }
 
@@ -2355,16 +2349,6 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
 
        pending = mci_readl(host, MINTSTS); /* read-only mask reg */
 
-       /*
-        * DTO fix - version 2.10a and below, and only if internal DMA
-        * is configured.
-        */
-       if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) {
-               if (!pending &&
-                   ((mci_readl(host, STATUS) >> 17) & 0x1fff))
-                       pending |= SDMMC_INT_DATA_OVER;
-       }
-
        if (pending) {
                /* Check volt switch first, since it can look like an error */
                if ((host->state == STATE_SENDING_CMD11) &&
@@ -3165,9 +3149,6 @@ int dw_mci_probe(struct dw_mci *host)
        /* Now that slots are all setup, we can enable card detect */
        dw_mci_enable_cd(host);
 
-       if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
-               dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");
-
        return 0;
 
 err_dmaunmap:
index 33dfd7e72516c3920b7ec641efb930668f0e15f5..82a97ac4e956f64941e2a9890728ea9831844550 100644 (file)
@@ -972,7 +972,7 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events,
                if ((events & MSDC_INT_XFER_COMPL) && (!stop || !stop->error)) {
                        data->bytes_xfered = data->blocks * data->blksz;
                } else {
-                       dev_err(host->dev, "interrupt events: %x\n", events);
+                       dev_dbg(host->dev, "interrupt events: %x\n", events);
                        msdc_reset_hw(host);
                        host->error |= REQ_DAT_ERR;
                        data->bytes_xfered = 0;
@@ -982,10 +982,10 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events,
                        else if (events & MSDC_INT_DATCRCERR)
                                data->error = -EILSEQ;
 
-                       dev_err(host->dev, "%s: cmd=%d; blocks=%d",
+                       dev_dbg(host->dev, "%s: cmd=%d; blocks=%d",
                                __func__, mrq->cmd->opcode, data->blocks);
-                       dev_err(host->dev, "data_error=%d xfer_size=%d\n",
-                                       (int)data->error, data->bytes_xfered);
+                       dev_dbg(host->dev, "data_error=%d xfer_size=%d\n",
+                               (int)data->error, data->bytes_xfered);
                }
 
                msdc_data_xfer_next(host, mrq, data);
@@ -1543,7 +1543,6 @@ static int msdc_drv_probe(struct platform_device *pdev)
        mmc->f_min = host->src_clk_freq / (4 * 255);
 
        mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23;
-       mmc->caps |= MMC_CAP_RUNTIME_RESUME;
        /* MMC core transfer sizes tunable parameters */
        mmc->max_segs = MAX_BD_NUM;
        mmc->max_seg_size = BDMA_DESC_BUFLEN;
index a448498e3af2fc3ce0b173dc404fe7ccefcee0d1..42296e55b9de5d36e4ca19e2655329ef72f85c5b 100644 (file)
 #include <linux/scatterlist.h>
 #include <linux/irq.h>
 #include <linux/clk.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
 #include <linux/of_irq.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/slot-gpio.h>
 
 #include <asm/sizes.h>
 #include <asm/unaligned.h>
-#include <linux/platform_data/mmc-mvsdio.h>
 
 #include "mvsdio.h"
 
@@ -704,6 +701,10 @@ static int mvsd_probe(struct platform_device *pdev)
        struct resource *r;
        int ret, irq;
 
+       if (!np) {
+               dev_err(&pdev->dev, "no DT node\n");
+               return -ENODEV;
+       }
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq = platform_get_irq(pdev, 0);
        if (!r || irq < 0)
@@ -727,8 +728,12 @@ static int mvsd_probe(struct platform_device *pdev)
         * fixed rate clock).
         */
        host->clk = devm_clk_get(&pdev->dev, NULL);
-       if (!IS_ERR(host->clk))
-               clk_prepare_enable(host->clk);
+       if (IS_ERR(host->clk)) {
+               dev_err(&pdev->dev, "no clock associated\n");
+               ret = -EINVAL;
+               goto out;
+       }
+       clk_prepare_enable(host->clk);
 
        mmc->ops = &mvsd_ops;
 
@@ -744,45 +749,10 @@ static int mvsd_probe(struct platform_device *pdev)
        mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count;
        mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
 
-       if (np) {
-               if (IS_ERR(host->clk)) {
-                       dev_err(&pdev->dev, "DT platforms must have a clock associated\n");
-                       ret = -EINVAL;
-                       goto out;
-               }
-
-               host->base_clock = clk_get_rate(host->clk) / 2;
-               ret = mmc_of_parse(mmc);
-               if (ret < 0)
-                       goto out;
-       } else {
-               const struct mvsdio_platform_data *mvsd_data;
-
-               mvsd_data = pdev->dev.platform_data;
-               if (!mvsd_data) {
-                       ret = -ENXIO;
-                       goto out;
-               }
-               mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ |
-                           MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
-               host->base_clock = mvsd_data->clock / 2;
-               /* GPIO 0 regarded as invalid for backward compatibility */
-               if (mvsd_data->gpio_card_detect &&
-                   gpio_is_valid(mvsd_data->gpio_card_detect)) {
-                       ret = mmc_gpio_request_cd(mmc,
-                                                 mvsd_data->gpio_card_detect,
-                                                 0);
-                       if (ret)
-                               goto out;
-               } else {
-                       mmc->caps |= MMC_CAP_NEEDS_POLL;
-               }
-
-               if (mvsd_data->gpio_write_protect &&
-                   gpio_is_valid(mvsd_data->gpio_write_protect))
-                       mmc_gpio_request_ro(mmc, mvsd_data->gpio_write_protect);
-       }
-
+       host->base_clock = clk_get_rate(host->clk) / 2;
+       ret = mmc_of_parse(mmc);
+       if (ret < 0)
+               goto out;
        if (maxfreq)
                mmc->f_max = maxfreq;
 
index 6e218fb1a669428ea6d2b5ddc2728f7d2f080e33..660170cd04d9f51c7253d18272f1113ca1e1b89b 100644 (file)
@@ -55,8 +55,8 @@ static int of_mmc_spi_init(struct device *dev,
 {
        struct of_mmc_spi *oms = to_of_mmc_spi(dev);
 
-       return request_threaded_irq(oms->detect_irq, NULL, irqhandler, 0,
-                                   dev_name(dev), mmc);
+       return request_threaded_irq(oms->detect_irq, NULL, irqhandler,
+                                       IRQF_ONESHOT, dev_name(dev), mmc);
 }
 
 static void of_mmc_spi_exit(struct device *dev, void *mmc)
index 7fb0753abe3041bc1814ebc14c1136d103b254e1..b6639ea0bf18dbd37ccf0d639073119353b418b6 100644 (file)
@@ -2250,10 +2250,8 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
        pm_runtime_get_sync(host->dev);
        mmc_remove_host(host->mmc);
 
-       if (host->tx_chan)
-               dma_release_channel(host->tx_chan);
-       if (host->rx_chan)
-               dma_release_channel(host->rx_chan);
+       dma_release_channel(host->tx_chan);
+       dma_release_channel(host->rx_chan);
 
        pm_runtime_put_sync(host->dev);
        pm_runtime_disable(host->dev);
index 1f1582f6cccbb3454f0824e9dcf39e170a76f395..f25f29253595b33b47c75bd30f94d642d37cdf60 100644 (file)
@@ -76,6 +76,7 @@
 #define ESDHC_STD_TUNING_EN            (1 << 24)
 /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
 #define ESDHC_TUNING_START_TAP         0x1
+#define ESDHC_TUNING_STEP_MASK         0x00070000
 #define ESDHC_TUNING_STEP_SHIFT                16
 
 /* pinctrl state */
@@ -489,9 +490,11 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
                                m |= ESDHC_MIX_CTRL_FBCLK_SEL;
                                tuning_ctrl = readl(host->ioaddr + ESDHC_TUNING_CTRL);
                                tuning_ctrl |= ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP;
-                               if (imx_data->boarddata.tuning_step)
+                               if (imx_data->boarddata.tuning_step) {
+                                       tuning_ctrl &= ~ESDHC_TUNING_STEP_MASK;
                                        tuning_ctrl |= imx_data->boarddata.tuning_step << ESDHC_TUNING_STEP_SHIFT;
-                                       writel(tuning_ctrl, host->ioaddr + ESDHC_TUNING_CTRL);
+                               }
+                               writel(tuning_ctrl, host->ioaddr + ESDHC_TUNING_CTRL);
                        } else {
                                v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
                        }
index 06d0b50dfe71d2ece8e7d8ee662af4c159860200..7e7d8f0c9438fe4ac41bfb1f1759ff4fde776089 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
 
 #include "sdhci-pltfm.h"
 
@@ -51,6 +53,60 @@ static const struct of_device_id sdhci_at91_dt_match[] = {
        {}
 };
 
+#ifdef CONFIG_PM
+static int sdhci_at91_runtime_suspend(struct device *dev)
+{
+       struct sdhci_host *host = dev_get_drvdata(dev);
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_at91_priv *priv = pltfm_host->priv;
+       int ret;
+
+       ret = sdhci_runtime_suspend_host(host);
+
+       clk_disable_unprepare(priv->gck);
+       clk_disable_unprepare(priv->hclock);
+       clk_disable_unprepare(priv->mainck);
+
+       return ret;
+}
+
+static int sdhci_at91_runtime_resume(struct device *dev)
+{
+       struct sdhci_host *host = dev_get_drvdata(dev);
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_at91_priv *priv = pltfm_host->priv;
+       int ret;
+
+       ret = clk_prepare_enable(priv->mainck);
+       if (ret) {
+               dev_err(dev, "can't enable mainck\n");
+               return ret;
+       }
+
+       ret = clk_prepare_enable(priv->hclock);
+       if (ret) {
+               dev_err(dev, "can't enable hclock\n");
+               return ret;
+       }
+
+       ret = clk_prepare_enable(priv->gck);
+       if (ret) {
+               dev_err(dev, "can't enable gck\n");
+               return ret;
+       }
+
+       return sdhci_runtime_resume_host(host);
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops sdhci_at91_dev_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+       SET_RUNTIME_PM_OPS(sdhci_at91_runtime_suspend,
+                          sdhci_at91_runtime_resume,
+                          NULL)
+};
+
 static int sdhci_at91_probe(struct platform_device *pdev)
 {
        const struct of_device_id       *match;
@@ -144,12 +200,23 @@ static int sdhci_at91_probe(struct platform_device *pdev)
 
        sdhci_get_of_property(pdev);
 
+       pm_runtime_get_noresume(&pdev->dev);
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
+       pm_runtime_use_autosuspend(&pdev->dev);
+
        ret = sdhci_add_host(host);
        if (ret)
-               goto clocks_disable_unprepare;
+               goto pm_runtime_disable;
+
+       pm_runtime_put_autosuspend(&pdev->dev);
 
        return 0;
 
+pm_runtime_disable:
+       pm_runtime_disable(&pdev->dev);
+       pm_runtime_set_suspended(&pdev->dev);
 clocks_disable_unprepare:
        clk_disable_unprepare(priv->gck);
        clk_disable_unprepare(priv->mainck);
@@ -165,6 +232,10 @@ static int sdhci_at91_remove(struct platform_device *pdev)
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_at91_priv  *priv = pltfm_host->priv;
 
+       pm_runtime_get_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+       pm_runtime_put_noidle(&pdev->dev);
+
        sdhci_pltfm_unregister(pdev);
 
        clk_disable_unprepare(priv->gck);
@@ -178,7 +249,7 @@ static struct platform_driver sdhci_at91_driver = {
        .driver         = {
                .name   = "sdhci-at91",
                .of_match_table = sdhci_at91_dt_match,
-               .pm     = SDHCI_PLTFM_PMOPS,
+               .pm     = &sdhci_at91_dev_pm_ops,
        },
        .probe          = sdhci_at91_probe,
        .remove         = sdhci_at91_remove,
index 90e94a028a49a39169b754d43050d4937d4b52eb..83b1226471c186cff0fb22cf92c7c43294f5581e 100644 (file)
@@ -584,6 +584,8 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
 {
        struct sdhci_host *host;
        struct device_node *np;
+       struct sdhci_pltfm_host *pltfm_host;
+       struct sdhci_esdhc *esdhc;
        int ret;
 
        np = pdev->dev.of_node;
@@ -600,6 +602,14 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
 
        sdhci_get_of_property(pdev);
 
+       pltfm_host = sdhci_priv(host);
+       esdhc = pltfm_host->priv;
+       if (esdhc->vendor_ver == VENDOR_V_22)
+               host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23;
+
+       if (esdhc->vendor_ver > VENDOR_V_22)
+               host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
+
        if (of_device_is_compatible(np, "fsl,p5040-esdhc") ||
            of_device_is_compatible(np, "fsl,p5020-esdhc") ||
            of_device_is_compatible(np, "fsl,p4080-esdhc") ||
index cf7ad458b4f44fe60beb0a614882fbb985aede37..cc851b065d0ae685d5297f7e4b8ac7a40b3e3465 100644 (file)
@@ -277,7 +277,7 @@ static int spt_select_drive_strength(struct sdhci_host *host,
        if (sdhci_pci_spt_drive_strength > 0)
                drive_strength = sdhci_pci_spt_drive_strength & 0xf;
        else
-               drive_strength = 1; /* 33-ohm */
+               drive_strength = 0; /* Default 50-ohm */
 
        if ((mmc_driver_type_mask(drive_strength) & card_drv) == 0)
                drive_strength = 0; /* Default 50-ohm */
@@ -1464,7 +1464,7 @@ static int sdhci_pci_resume(struct device *dev)
 
 static int sdhci_pci_runtime_suspend(struct device *dev)
 {
-       struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+       struct pci_dev *pdev = to_pci_dev(dev);
        struct sdhci_pci_chip *chip;
        struct sdhci_pci_slot *slot;
        int i, ret;
@@ -1500,7 +1500,7 @@ err_pci_runtime_suspend:
 
 static int sdhci_pci_runtime_resume(struct device *dev)
 {
-       struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+       struct pci_dev *pdev = to_pci_dev(dev);
        struct sdhci_pci_chip *chip;
        struct sdhci_pci_slot *slot;
        int i, ret;
index 87fb5ea8ebe7cae575b8281f07c630ce03ce2223..072bb27a65cfac36086f2b9b65994e257ed96d59 100644 (file)
@@ -104,7 +104,8 @@ void sdhci_get_of_property(struct platform_device *pdev)
        if (of_find_property(np, "keep-power-in-suspend", NULL))
                host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
 
-       if (of_find_property(np, "enable-sdio-wakeup", NULL))
+       if (of_property_read_bool(np, "wakeup-source") ||
+           of_property_read_bool(np, "enable-sdio-wakeup")) /* legacy */
                host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
 }
 #else
index ad28b49f0203f5d734ef7325aba081c4c4b5ce4e..83c4bf7bc16ccfa476bf3d02ca9bce9022b582b7 100644 (file)
 #include <linux/of_device.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
 #include <linux/mmc/slot-gpio.h>
 #include <linux/gpio/consumer.h>
 
 #include "sdhci-pltfm.h"
 
 /* Tegra SDHOST controller vendor register definitions */
+#define SDHCI_TEGRA_VENDOR_CLOCK_CTRL                  0x100
+#define SDHCI_CLOCK_CTRL_TAP_MASK                      0x00ff0000
+#define SDHCI_CLOCK_CTRL_TAP_SHIFT                     16
+#define SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE         BIT(5)
+#define SDHCI_CLOCK_CTRL_PADPIPE_CLKEN_OVERRIDE                BIT(3)
+#define SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE       BIT(2)
+
 #define SDHCI_TEGRA_VENDOR_MISC_CTRL           0x120
 #define SDHCI_MISC_CTRL_ENABLE_SDR104          0x8
 #define SDHCI_MISC_CTRL_ENABLE_SDR50           0x10
@@ -37,9 +45,9 @@
 #define NVQUIRK_FORCE_SDHCI_SPEC_200   BIT(0)
 #define NVQUIRK_ENABLE_BLOCK_GAP_DET   BIT(1)
 #define NVQUIRK_ENABLE_SDHCI_SPEC_300  BIT(2)
-#define NVQUIRK_DISABLE_SDR50          BIT(3)
-#define NVQUIRK_DISABLE_SDR104         BIT(4)
-#define NVQUIRK_DISABLE_DDR50          BIT(5)
+#define NVQUIRK_ENABLE_SDR50           BIT(3)
+#define NVQUIRK_ENABLE_SDR104          BIT(4)
+#define NVQUIRK_ENABLE_DDR50           BIT(5)
 
 struct sdhci_tegra_soc_data {
        const struct sdhci_pltfm_data *pdata;
@@ -49,6 +57,7 @@ struct sdhci_tegra_soc_data {
 struct sdhci_tegra {
        const struct sdhci_tegra_soc_data *soc_data;
        struct gpio_desc *power_gpio;
+       bool ddr_signaling;
 };
 
 static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
@@ -124,25 +133,33 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_tegra *tegra_host = pltfm_host->priv;
        const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
-       u32 misc_ctrl;
+       u32 misc_ctrl, clk_ctrl;
 
        sdhci_reset(host, mask);
 
        if (!(mask & SDHCI_RESET_ALL))
                return;
 
-       misc_ctrl = sdhci_readw(host, SDHCI_TEGRA_VENDOR_MISC_CTRL);
+       misc_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_MISC_CTRL);
        /* Erratum: Enable SDHCI spec v3.00 support */
        if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300)
                misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300;
-       /* Don't advertise UHS modes which aren't supported yet */
-       if (soc_data->nvquirks & NVQUIRK_DISABLE_SDR50)
-               misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR50;
-       if (soc_data->nvquirks & NVQUIRK_DISABLE_DDR50)
-               misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_DDR50;
-       if (soc_data->nvquirks & NVQUIRK_DISABLE_SDR104)
-               misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR104;
-       sdhci_writew(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL);
+       /* Advertise UHS modes as supported by host */
+       if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50)
+               misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR50;
+       if (soc_data->nvquirks & NVQUIRK_ENABLE_DDR50)
+               misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50;
+       if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104)
+               misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104;
+       sdhci_writel(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL);
+
+       clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
+       clk_ctrl &= ~SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE;
+       if (soc_data->nvquirks & SDHCI_MISC_CTRL_ENABLE_SDR50)
+               clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE;
+       sdhci_writel(host, clk_ctrl, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
+
+       tegra_host->ddr_signaling = false;
 }
 
 static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width)
@@ -164,15 +181,99 @@ static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width)
        sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 }
 
+static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_tegra *tegra_host = pltfm_host->priv;
+       unsigned long host_clk;
+
+       if (!clock)
+               return;
+
+       host_clk = tegra_host->ddr_signaling ? clock * 2 : clock;
+       clk_set_rate(pltfm_host->clk, host_clk);
+       host->max_clk = clk_get_rate(pltfm_host->clk);
+
+       return sdhci_set_clock(host, clock);
+}
+
+static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,
+                                         unsigned timing)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_tegra *tegra_host = pltfm_host->priv;
+
+       if (timing == MMC_TIMING_UHS_DDR50)
+               tegra_host->ddr_signaling = true;
+
+       return sdhci_set_uhs_signaling(host, timing);
+}
+
+static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+       /*
+        * DDR modes require the host to run at double the card frequency, so
+        * the maximum rate we can support is half of the module input clock.
+        */
+       return clk_round_rate(pltfm_host->clk, UINT_MAX) / 2;
+}
+
+static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap)
+{
+       u32 reg;
+
+       reg = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
+       reg &= ~SDHCI_CLOCK_CTRL_TAP_MASK;
+       reg |= tap << SDHCI_CLOCK_CTRL_TAP_SHIFT;
+       sdhci_writel(host, reg, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
+}
+
+static int tegra_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
+{
+       unsigned int min, max;
+
+       /*
+        * Start search for minimum tap value at 10, as smaller values are
+        * may wrongly be reported as working but fail at higher speeds,
+        * according to the TRM.
+        */
+       min = 10;
+       while (min < 255) {
+               tegra_sdhci_set_tap(host, min);
+               if (!mmc_send_tuning(host->mmc, opcode, NULL))
+                       break;
+               min++;
+       }
+
+       /* Find the maximum tap value that still passes. */
+       max = min + 1;
+       while (max < 255) {
+               tegra_sdhci_set_tap(host, max);
+               if (mmc_send_tuning(host->mmc, opcode, NULL)) {
+                       max--;
+                       break;
+               }
+               max++;
+       }
+
+       /* The TRM states the ideal tap value is at 75% in the passing range. */
+       tegra_sdhci_set_tap(host, min + ((max - min) * 3 / 4));
+
+       return mmc_send_tuning(host->mmc, opcode, NULL);
+}
+
 static const struct sdhci_ops tegra_sdhci_ops = {
        .get_ro     = tegra_sdhci_get_ro,
        .read_w     = tegra_sdhci_readw,
        .write_l    = tegra_sdhci_writel,
-       .set_clock  = sdhci_set_clock,
+       .set_clock  = tegra_sdhci_set_clock,
        .set_bus_width = tegra_sdhci_set_bus_width,
        .reset      = tegra_sdhci_reset,
-       .set_uhs_signaling = sdhci_set_uhs_signaling,
-       .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+       .platform_execute_tuning = tegra_sdhci_execute_tuning,
+       .set_uhs_signaling = tegra_sdhci_set_uhs_signaling,
+       .get_max_clock = tegra_sdhci_get_max_clock,
 };
 
 static const struct sdhci_pltfm_data sdhci_tegra20_pdata = {
@@ -184,7 +285,7 @@ static const struct sdhci_pltfm_data sdhci_tegra20_pdata = {
        .ops  = &tegra_sdhci_ops,
 };
 
-static struct sdhci_tegra_soc_data soc_data_tegra20 = {
+static const struct sdhci_tegra_soc_data soc_data_tegra20 = {
        .pdata = &sdhci_tegra20_pdata,
        .nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 |
                    NVQUIRK_ENABLE_BLOCK_GAP_DET,
@@ -197,14 +298,15 @@ static const struct sdhci_pltfm_data sdhci_tegra30_pdata = {
                  SDHCI_QUIRK_NO_HISPD_BIT |
                  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
                  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+       .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
        .ops  = &tegra_sdhci_ops,
 };
 
-static struct sdhci_tegra_soc_data soc_data_tegra30 = {
+static const struct sdhci_tegra_soc_data soc_data_tegra30 = {
        .pdata = &sdhci_tegra30_pdata,
        .nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300 |
-                   NVQUIRK_DISABLE_SDR50 |
-                   NVQUIRK_DISABLE_SDR104,
+                   NVQUIRK_ENABLE_SDR50 |
+                   NVQUIRK_ENABLE_SDR104,
 };
 
 static const struct sdhci_ops tegra114_sdhci_ops = {
@@ -212,11 +314,12 @@ static const struct sdhci_ops tegra114_sdhci_ops = {
        .read_w     = tegra_sdhci_readw,
        .write_w    = tegra_sdhci_writew,
        .write_l    = tegra_sdhci_writel,
-       .set_clock  = sdhci_set_clock,
+       .set_clock  = tegra_sdhci_set_clock,
        .set_bus_width = tegra_sdhci_set_bus_width,
        .reset      = tegra_sdhci_reset,
-       .set_uhs_signaling = sdhci_set_uhs_signaling,
-       .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+       .platform_execute_tuning = tegra_sdhci_execute_tuning,
+       .set_uhs_signaling = tegra_sdhci_set_uhs_signaling,
+       .get_max_clock = tegra_sdhci_get_max_clock,
 };
 
 static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {
@@ -226,17 +329,34 @@ static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {
                  SDHCI_QUIRK_NO_HISPD_BIT |
                  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
                  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+       .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
        .ops  = &tegra114_sdhci_ops,
 };
 
-static struct sdhci_tegra_soc_data soc_data_tegra114 = {
+static const struct sdhci_tegra_soc_data soc_data_tegra114 = {
        .pdata = &sdhci_tegra114_pdata,
-       .nvquirks = NVQUIRK_DISABLE_SDR50 |
-                   NVQUIRK_DISABLE_DDR50 |
-                   NVQUIRK_DISABLE_SDR104,
+       .nvquirks = NVQUIRK_ENABLE_SDR50 |
+                   NVQUIRK_ENABLE_DDR50 |
+                   NVQUIRK_ENABLE_SDR104,
+};
+
+static const struct sdhci_pltfm_data sdhci_tegra210_pdata = {
+       .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
+                 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
+                 SDHCI_QUIRK_SINGLE_POWER_WRITE |
+                 SDHCI_QUIRK_NO_HISPD_BIT |
+                 SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
+                 SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+       .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+       .ops  = &tegra114_sdhci_ops,
+};
+
+static const struct sdhci_tegra_soc_data soc_data_tegra210 = {
+       .pdata = &sdhci_tegra210_pdata,
 };
 
 static const struct of_device_id sdhci_tegra_dt_match[] = {
+       { .compatible = "nvidia,tegra210-sdhci", .data = &soc_data_tegra210 },
        { .compatible = "nvidia,tegra124-sdhci", .data = &soc_data_tegra114 },
        { .compatible = "nvidia,tegra114-sdhci", .data = &soc_data_tegra114 },
        { .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 },
@@ -271,6 +391,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
                rc = -ENOMEM;
                goto err_alloc_tegra_host;
        }
+       tegra_host->ddr_signaling = false;
        tegra_host->soc_data = soc_data;
        pltfm_host->priv = tegra_host;
 
@@ -278,6 +399,9 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
        if (rc)
                goto err_parse_dt;
 
+       if (tegra_host->soc_data->nvquirks & NVQUIRK_ENABLE_DDR50)
+               host->mmc->caps |= MMC_CAP_1_8V_DDR;
+
        tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power",
                                                         GPIOD_OUT_HIGH);
        if (IS_ERR(tegra_host->power_gpio)) {
index b48565ed5616c79302008963a05aa7e1e18d742c..d622435d1bcc71e47e54cdb42cb847660b009a55 100644 (file)
@@ -492,7 +492,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
                host->align_buffer, host->align_buffer_sz, direction);
        if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
                goto fail;
-       BUG_ON(host->align_addr & host->align_mask);
+       BUG_ON(host->align_addr & SDHCI_ADMA2_MASK);
 
        host->sg_count = sdhci_pre_dma_transfer(host, data);
        if (host->sg_count < 0)
@@ -514,8 +514,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
                 * the (up to three) bytes that screw up the
                 * alignment.
                 */
-               offset = (host->align_sz - (addr & host->align_mask)) &
-                        host->align_mask;
+               offset = (SDHCI_ADMA2_ALIGN - (addr & SDHCI_ADMA2_MASK)) &
+                        SDHCI_ADMA2_MASK;
                if (offset) {
                        if (data->flags & MMC_DATA_WRITE) {
                                buffer = sdhci_kmap_atomic(sg, &flags);
@@ -529,8 +529,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
 
                        BUG_ON(offset > 65536);
 
-                       align += host->align_sz;
-                       align_addr += host->align_sz;
+                       align += SDHCI_ADMA2_ALIGN;
+                       align_addr += SDHCI_ADMA2_ALIGN;
 
                        desc += host->desc_sz;
 
@@ -540,9 +540,12 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
 
                BUG_ON(len > 65536);
 
-               /* tran, valid */
-               sdhci_adma_write_desc(host, desc, addr, len, ADMA2_TRAN_VALID);
-               desc += host->desc_sz;
+               if (len) {
+                       /* tran, valid */
+                       sdhci_adma_write_desc(host, desc, addr, len,
+                                             ADMA2_TRAN_VALID);
+                       desc += host->desc_sz;
+               }
 
                /*
                 * If this triggers then we have a calculation bug
@@ -608,7 +611,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
        /* Do a quick scan of the SG list for any unaligned mappings */
        has_unaligned = false;
        for_each_sg(data->sg, sg, host->sg_count, i)
-               if (sg_dma_address(sg) & host->align_mask) {
+               if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) {
                        has_unaligned = true;
                        break;
                }
@@ -620,15 +623,15 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
                align = host->align_buffer;
 
                for_each_sg(data->sg, sg, host->sg_count, i) {
-                       if (sg_dma_address(sg) & host->align_mask) {
-                               size = host->align_sz -
-                                      (sg_dma_address(sg) & host->align_mask);
+                       if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) {
+                               size = SDHCI_ADMA2_ALIGN -
+                                      (sg_dma_address(sg) & SDHCI_ADMA2_MASK);
 
                                buffer = sdhci_kmap_atomic(sg, &flags);
                                memcpy(buffer, align, size);
                                sdhci_kunmap_atomic(buffer, &flags);
 
-                               align += host->align_sz;
+                               align += SDHCI_ADMA2_ALIGN;
                        }
                }
        }
@@ -768,8 +771,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
                if (unlikely(broken)) {
                        for_each_sg(data->sg, sg, data->sg_len, i) {
                                if (sg->length & 0x3) {
-                                       DBG("Reverting to PIO because of "
-                                               "transfer size (%d)\n",
+                                       DBG("Reverting to PIO because of transfer size (%d)\n",
                                                sg->length);
                                        host->flags &= ~SDHCI_REQ_USE_DMA;
                                        break;
@@ -803,8 +805,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
                if (unlikely(broken)) {
                        for_each_sg(data->sg, sg, data->sg_len, i) {
                                if (sg->offset & 0x3) {
-                                       DBG("Reverting to PIO because of "
-                                               "bad alignment\n");
+                                       DBG("Reverting to PIO because of bad alignment\n");
                                        host->flags &= ~SDHCI_REQ_USE_DMA;
                                        break;
                                }
@@ -1016,8 +1017,8 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 
        while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
                if (timeout == 0) {
-                       pr_err("%s: Controller never released "
-                               "inhibit bit(s).\n", mmc_hostname(host->mmc));
+                       pr_err("%s: Controller never released inhibit bit(s).\n",
+                              mmc_hostname(host->mmc));
                        sdhci_dumpregs(host);
                        cmd->error = -EIO;
                        tasklet_schedule(&host->finish_tasklet);
@@ -1254,8 +1255,8 @@ clock_set:
        while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
                & SDHCI_CLOCK_INT_STABLE)) {
                if (timeout == 0) {
-                       pr_err("%s: Internal clock never "
-                               "stabilised.\n", mmc_hostname(host->mmc));
+                       pr_err("%s: Internal clock never stabilised.\n",
+                              mmc_hostname(host->mmc));
                        sdhci_dumpregs(host);
                        return;
                }
@@ -1274,19 +1275,6 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
        struct mmc_host *mmc = host->mmc;
        u8 pwr = 0;
 
-       if (!IS_ERR(mmc->supply.vmmc)) {
-               spin_unlock_irq(&host->lock);
-               mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
-               spin_lock_irq(&host->lock);
-
-               if (mode != MMC_POWER_OFF)
-                       sdhci_writeb(host, SDHCI_POWER_ON, SDHCI_POWER_CONTROL);
-               else
-                       sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
-
-               return;
-       }
-
        if (mode != MMC_POWER_OFF) {
                switch (1 << vdd) {
                case MMC_VDD_165_195:
@@ -1301,7 +1289,9 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
                        pwr = SDHCI_POWER_330;
                        break;
                default:
-                       BUG();
+                       WARN(1, "%s: Invalid vdd %#x\n",
+                            mmc_hostname(host->mmc), vdd);
+                       break;
                }
        }
 
@@ -1345,6 +1335,12 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
                if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
                        mdelay(10);
        }
+
+       if (!IS_ERR(mmc->supply.vmmc)) {
+               spin_unlock_irq(&host->lock);
+               mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
+               spin_lock_irq(&host->lock);
+       }
 }
 
 /*****************************************************************************\
@@ -1540,8 +1536,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                        else if (ios->drv_type == MMC_SET_DRIVER_TYPE_D)
                                ctrl_2 |= SDHCI_CTRL_DRV_TYPE_D;
                        else {
-                               pr_warn("%s: invalid driver type, default to "
-                                       "driver type B\n", mmc_hostname(mmc));
+                               pr_warn("%s: invalid driver type, default to driver type B\n",
+                                       mmc_hostname(mmc));
                                ctrl_2 |= SDHCI_CTRL_DRV_TYPE_B;
                        }
 
@@ -2015,10 +2011,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
                spin_lock_irqsave(&host->lock, flags);
 
                if (!host->tuning_done) {
-                       pr_info(DRIVER_NAME ": Timeout waiting for "
-                               "Buffer Read Ready interrupt during tuning "
-                               "procedure, falling back to fixed sampling "
-                               "clock\n");
+                       pr_info(DRIVER_NAME ": Timeout waiting for Buffer Read Ready interrupt during tuning procedure, falling back to fixed sampling clock\n");
                        ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
                        ctrl &= ~SDHCI_CTRL_TUNED_CLK;
                        ctrl &= ~SDHCI_CTRL_EXEC_TUNING;
@@ -2046,9 +2039,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
                sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
        }
        if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
-               pr_info(DRIVER_NAME ": Tuning procedure"
-                       " failed, falling back to fixed sampling"
-                       " clock\n");
+               pr_info(DRIVER_NAME ": Tuning procedure failed, falling back to fixed sampling clock\n");
                err = -EIO;
        }
 
@@ -2293,8 +2284,8 @@ static void sdhci_timeout_timer(unsigned long data)
        spin_lock_irqsave(&host->lock, flags);
 
        if (host->mrq) {
-               pr_err("%s: Timeout waiting for hardware "
-                       "interrupt.\n", mmc_hostname(host->mmc));
+               pr_err("%s: Timeout waiting for hardware interrupt.\n",
+                      mmc_hostname(host->mmc));
                sdhci_dumpregs(host);
 
                if (host->data) {
@@ -2325,9 +2316,8 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask)
        BUG_ON(intmask == 0);
 
        if (!host->cmd) {
-               pr_err("%s: Got command interrupt 0x%08x even "
-                       "though no command operation was in progress.\n",
-                       mmc_hostname(host->mmc), (unsigned)intmask);
+               pr_err("%s: Got command interrupt 0x%08x even though no command operation was in progress.\n",
+                      mmc_hostname(host->mmc), (unsigned)intmask);
                sdhci_dumpregs(host);
                return;
        }
@@ -2356,8 +2346,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask)
         */
        if (host->cmd->flags & MMC_RSP_BUSY) {
                if (host->cmd->data)
-                       DBG("Cannot wait for busy signal when also "
-                               "doing a data transfer");
+                       DBG("Cannot wait for busy signal when also doing a data transfer");
                else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ)
                                && !host->busy_handle) {
                        /* Mark that command complete before busy is ended */
@@ -2451,9 +2440,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
                        }
                }
 
-               pr_err("%s: Got data interrupt 0x%08x even "
-                       "though no data operation was in progress.\n",
-                       mmc_hostname(host->mmc), (unsigned)intmask);
+               pr_err("%s: Got data interrupt 0x%08x even though no data operation was in progress.\n",
+                      mmc_hostname(host->mmc), (unsigned)intmask);
                sdhci_dumpregs(host);
 
                return;
@@ -2760,7 +2748,7 @@ static int sdhci_runtime_pm_put(struct sdhci_host *host)
 
 static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
 {
-       if (host->runtime_suspended || host->bus_on)
+       if (host->bus_on)
                return;
        host->bus_on = true;
        pm_runtime_get_noresume(host->mmc->parent);
@@ -2768,7 +2756,7 @@ static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
 
 static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
 {
-       if (host->runtime_suspended || !host->bus_on)
+       if (!host->bus_on)
                return;
        host->bus_on = false;
        pm_runtime_put_noidle(host->mmc->parent);
@@ -2896,9 +2884,8 @@ int sdhci_add_host(struct sdhci_host *host)
        host->version = (host->version & SDHCI_SPEC_VER_MASK)
                                >> SDHCI_SPEC_VER_SHIFT;
        if (host->version > SDHCI_SPEC_300) {
-               pr_err("%s: Unknown controller version (%d). "
-                       "You may experience problems.\n", mmc_hostname(mmc),
-                       host->version);
+               pr_err("%s: Unknown controller version (%d). You may experience problems.\n",
+                      mmc_hostname(mmc), host->version);
        }
 
        caps[0] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
@@ -2967,24 +2954,17 @@ int sdhci_add_host(struct sdhci_host *host)
                if (host->flags & SDHCI_USE_64_BIT_DMA) {
                        host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
                                              SDHCI_ADMA2_64_DESC_SZ;
-                       host->align_buffer_sz = SDHCI_MAX_SEGS *
-                                               SDHCI_ADMA2_64_ALIGN;
                        host->desc_sz = SDHCI_ADMA2_64_DESC_SZ;
-                       host->align_sz = SDHCI_ADMA2_64_ALIGN;
-                       host->align_mask = SDHCI_ADMA2_64_ALIGN - 1;
                } else {
                        host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
                                              SDHCI_ADMA2_32_DESC_SZ;
-                       host->align_buffer_sz = SDHCI_MAX_SEGS *
-                                               SDHCI_ADMA2_32_ALIGN;
                        host->desc_sz = SDHCI_ADMA2_32_DESC_SZ;
-                       host->align_sz = SDHCI_ADMA2_32_ALIGN;
-                       host->align_mask = SDHCI_ADMA2_32_ALIGN - 1;
                }
                host->adma_table = dma_alloc_coherent(mmc_dev(mmc),
                                                      host->adma_table_sz,
                                                      &host->adma_addr,
                                                      GFP_KERNEL);
+               host->align_buffer_sz = SDHCI_MAX_SEGS * SDHCI_ADMA2_ALIGN;
                host->align_buffer = kmalloc(host->align_buffer_sz, GFP_KERNEL);
                if (!host->adma_table || !host->align_buffer) {
                        if (host->adma_table)
@@ -2998,7 +2978,7 @@ int sdhci_add_host(struct sdhci_host *host)
                        host->flags &= ~SDHCI_USE_ADMA;
                        host->adma_table = NULL;
                        host->align_buffer = NULL;
-               } else if (host->adma_addr & host->align_mask) {
+               } else if (host->adma_addr & (SDHCI_ADMA2_DESC_ALIGN - 1)) {
                        pr_warn("%s: unable to allocate aligned ADMA descriptor\n",
                                mmc_hostname(mmc));
                        host->flags &= ~SDHCI_USE_ADMA;
@@ -3031,8 +3011,8 @@ int sdhci_add_host(struct sdhci_host *host)
        if (host->max_clk == 0 || host->quirks &
                        SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) {
                if (!host->ops->get_max_clock) {
-                       pr_err("%s: Hardware doesn't specify base clock "
-                              "frequency.\n", mmc_hostname(mmc));
+                       pr_err("%s: Hardware doesn't specify base clock frequency.\n",
+                              mmc_hostname(mmc));
                        return -ENODEV;
                }
                host->max_clk = host->ops->get_max_clock(host);
@@ -3294,8 +3274,8 @@ int sdhci_add_host(struct sdhci_host *host)
                mmc->ocr_avail_mmc &= host->ocr_avail_mmc;
 
        if (mmc->ocr_avail == 0) {
-               pr_err("%s: Hardware doesn't report any "
-                       "support voltages.\n", mmc_hostname(mmc));
+               pr_err("%s: Hardware doesn't report any support voltages.\n",
+                      mmc_hostname(mmc));
                return -ENODEV;
        }
 
index 9d4aa31b683ac2d64e16f31f88d8d0893162a225..7654ae5d2b4e11b8b1814fa99b514223d4475d50 100644 (file)
 /* ADMA2 32-bit DMA descriptor size */
 #define SDHCI_ADMA2_32_DESC_SZ 8
 
-/* ADMA2 32-bit DMA alignment */
-#define SDHCI_ADMA2_32_ALIGN   4
-
 /* ADMA2 32-bit descriptor */
 struct sdhci_adma2_32_desc {
        __le16  cmd;
        __le16  len;
        __le32  addr;
-}  __packed __aligned(SDHCI_ADMA2_32_ALIGN);
+}  __packed __aligned(4);
+
+/* ADMA2 data alignment */
+#define SDHCI_ADMA2_ALIGN      4
+#define SDHCI_ADMA2_MASK       (SDHCI_ADMA2_ALIGN - 1)
+
+/*
+ * ADMA2 descriptor alignment.  Some controllers (e.g. Intel) require 8 byte
+ * alignment for the descriptor table even in 32-bit DMA mode.  Memory
+ * allocation is at least 8 byte aligned anyway, so just stipulate 8 always.
+ */
+#define SDHCI_ADMA2_DESC_ALIGN 8
 
 /* ADMA2 64-bit DMA descriptor size */
 #define SDHCI_ADMA2_64_DESC_SZ 12
 
-/* ADMA2 64-bit DMA alignment */
-#define SDHCI_ADMA2_64_ALIGN   8
-
 /*
  * ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte
  * aligned.
@@ -482,8 +487,6 @@ struct sdhci_host {
        dma_addr_t align_addr;  /* Mapped bounce buffer */
 
        unsigned int desc_sz;   /* ADMA descriptor size */
-       unsigned int align_sz;  /* ADMA alignment */
-       unsigned int align_mask;        /* ADMA alignment mask */
 
        struct tasklet_struct finish_tasklet;   /* Tasklet structures */
 
index ad9ffea7d659d28e057f13c1b7912ca7243743ac..1ca8a1359cbc1efd6a35cefb596c1c4534c77920 100644 (file)
@@ -397,38 +397,26 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host)
 }
 
 static struct dma_chan *
-sh_mmcif_request_dma_one(struct sh_mmcif_host *host,
-                        struct sh_mmcif_plat_data *pdata,
-                        enum dma_transfer_direction direction)
+sh_mmcif_request_dma_pdata(struct sh_mmcif_host *host, uintptr_t slave_id)
 {
-       struct dma_slave_config cfg = { 0, };
-       struct dma_chan *chan;
-       void *slave_data = NULL;
-       struct resource *res;
-       struct device *dev = sh_mmcif_host_to_dev(host);
        dma_cap_mask_t mask;
-       int ret;
 
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
+       if (slave_id <= 0)
+               return NULL;
 
-       if (pdata)
-               slave_data = direction == DMA_MEM_TO_DEV ?
-                       (void *)pdata->slave_id_tx :
-                       (void *)pdata->slave_id_rx;
-
-       chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
-                               slave_data, dev,
-                               direction == DMA_MEM_TO_DEV ? "tx" : "rx");
-
-       dev_dbg(dev, "%s: %s: got channel %p\n", __func__,
-               direction == DMA_MEM_TO_DEV ? "TX" : "RX", chan);
+       return dma_request_channel(mask, shdma_chan_filter, (void *)slave_id);
+}
 
-       if (!chan)
-               return NULL;
+static int sh_mmcif_dma_slave_config(struct sh_mmcif_host *host,
+                                    struct dma_chan *chan,
+                                    enum dma_transfer_direction direction)
+{
+       struct resource *res;
+       struct dma_slave_config cfg = { 0, };
 
        res = platform_get_resource(host->pd, IORESOURCE_MEM, 0);
-
        cfg.direction = direction;
 
        if (direction == DMA_DEV_TO_MEM) {
@@ -439,38 +427,42 @@ sh_mmcif_request_dma_one(struct sh_mmcif_host *host,
                cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
        }
 
-       ret = dmaengine_slave_config(chan, &cfg);
-       if (ret < 0) {
-               dma_release_channel(chan);
-               return NULL;
-       }
-
-       return chan;
+       return dmaengine_slave_config(chan, &cfg);
 }
 
-static void sh_mmcif_request_dma(struct sh_mmcif_host *host,
-                                struct sh_mmcif_plat_data *pdata)
+static void sh_mmcif_request_dma(struct sh_mmcif_host *host)
 {
        struct device *dev = sh_mmcif_host_to_dev(host);
        host->dma_active = false;
 
-       if (pdata) {
-               if (pdata->slave_id_tx <= 0 || pdata->slave_id_rx <= 0)
-                       return;
-       } else if (!dev->of_node) {
-               return;
+       /* We can only either use DMA for both Tx and Rx or not use it at all */
+       if (IS_ENABLED(CONFIG_SUPERH) && dev->platform_data) {
+               struct sh_mmcif_plat_data *pdata = dev->platform_data;
+
+               host->chan_tx = sh_mmcif_request_dma_pdata(host,
+                                                       pdata->slave_id_tx);
+               host->chan_rx = sh_mmcif_request_dma_pdata(host,
+                                                       pdata->slave_id_rx);
+       } else {
+               host->chan_tx = dma_request_slave_channel(dev, "tx");
+               host->chan_tx = dma_request_slave_channel(dev, "rx");
        }
+       dev_dbg(dev, "%s: got channel TX %p RX %p\n", __func__, host->chan_tx,
+               host->chan_rx);
 
-       /* We can only either use DMA for both Tx and Rx or not use it at all */
-       host->chan_tx = sh_mmcif_request_dma_one(host, pdata, DMA_MEM_TO_DEV);
-       if (!host->chan_tx)
-               return;
+       if (!host->chan_tx || !host->chan_rx ||
+           sh_mmcif_dma_slave_config(host, host->chan_tx, DMA_MEM_TO_DEV) ||
+           sh_mmcif_dma_slave_config(host, host->chan_rx, DMA_DEV_TO_MEM))
+               goto error;
 
-       host->chan_rx = sh_mmcif_request_dma_one(host, pdata, DMA_DEV_TO_MEM);
-       if (!host->chan_rx) {
+       return;
+
+error:
+       if (host->chan_tx)
                dma_release_channel(host->chan_tx);
-               host->chan_tx = NULL;
-       }
+       if (host->chan_rx)
+               dma_release_channel(host->chan_rx);
+       host->chan_tx = host->chan_rx = NULL;
 }
 
 static void sh_mmcif_release_dma(struct sh_mmcif_host *host)
@@ -1102,7 +1094,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        if (ios->power_mode == MMC_POWER_UP) {
                if (!host->card_present) {
                        /* See if we also get DMA */
-                       sh_mmcif_request_dma(host, dev->platform_data);
+                       sh_mmcif_request_dma(host);
                        host->card_present = true;
                }
                sh_mmcif_set_power(host, ios);
index 4498e92116b808d2a62f6e146f33f3b41838ee33..b47122d3e8d8c71b435cdc47a275f349bf102a22 100644 (file)
@@ -1634,7 +1634,7 @@ static void usdhi6_timeout_work(struct work_struct *work)
        struct usdhi6_host *host = container_of(d, struct usdhi6_host, timeout_work);
        struct mmc_request *mrq = host->mrq;
        struct mmc_data *data = mrq ? mrq->data : NULL;
-       struct scatterlist *sg = host->sg ?: data->sg;
+       struct scatterlist *sg;
 
        dev_warn(mmc_dev(host->mmc),
                 "%s timeout wait %u CMD%d: IRQ 0x%08x:0x%08x, last IRQ 0x%08x\n",
@@ -1666,6 +1666,7 @@ static void usdhi6_timeout_work(struct work_struct *work)
        case USDHI6_WAIT_FOR_MWRITE:
        case USDHI6_WAIT_FOR_READ:
        case USDHI6_WAIT_FOR_WRITE:
+               sg = host->sg ?: data->sg;
                dev_dbg(mmc_dev(host->mmc),
                        "%c: page #%u @ +0x%zx %ux%u in SG%u. Current SG %u bytes @ %u\n",
                        data->flags & MMC_DATA_READ ? 'R' : 'W', host->page_idx,
index 95c13b2ffa799e59f453e8a95813171cd56a13fc..ffa2884748205e26a376712c453b4fca5d3075bf 100644 (file)
@@ -426,15 +426,6 @@ int add_mtd_device(struct mtd_info *mtd)
        mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;
        mtd->writesize_mask = (1 << mtd->writesize_shift) - 1;
 
-       if (mtd->dev.parent) {
-               if (!mtd->owner && mtd->dev.parent->driver)
-                       mtd->owner = mtd->dev.parent->driver->owner;
-               if (!mtd->name)
-                       mtd->name = dev_name(mtd->dev.parent);
-       } else {
-               pr_debug("mtd device won't show a device symlink in sysfs\n");
-       }
-
        /* Some chips always power up locked. Unlock them now */
        if ((mtd->flags & MTD_WRITEABLE) && (mtd->flags & MTD_POWERUP_LOCK)) {
                error = mtd_unlock(mtd, 0, mtd->size);
@@ -549,6 +540,21 @@ static int mtd_add_device_partitions(struct mtd_info *mtd,
        return 0;
 }
 
+/*
+ * Set a few defaults based on the parent devices, if not provided by the
+ * driver
+ */
+static void mtd_set_dev_defaults(struct mtd_info *mtd)
+{
+       if (mtd->dev.parent) {
+               if (!mtd->owner && mtd->dev.parent->driver)
+                       mtd->owner = mtd->dev.parent->driver->owner;
+               if (!mtd->name)
+                       mtd->name = dev_name(mtd->dev.parent);
+       } else {
+               pr_debug("mtd device won't show a device symlink in sysfs\n");
+       }
+}
 
 /**
  * mtd_device_parse_register - parse partitions and register an MTD device.
@@ -587,6 +593,8 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
        int ret;
        struct mtd_partition *real_parts = NULL;
 
+       mtd_set_dev_defaults(mtd);
+
        ret = parse_mtd_partitions(mtd, types, &real_parts, parser_data);
        if (ret <= 0 && nr_parts && parts) {
                real_parts = kmemdup(parts, sizeof(*parts) * nr_parts,
index 49883905a434b68b98af50e515a0356731c62fa6..32477c4eb421390e250645f94b0eefdab871a043 100644 (file)
@@ -516,8 +516,8 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
        status_old = read_sr(nor);
 
        /* Cannot unlock; would unlock larger region than requested */
-       if (stm_is_locked_sr(nor, status_old, ofs - mtd->erasesize,
-                            mtd->erasesize))
+       if (stm_is_locked_sr(nor, ofs - mtd->erasesize, mtd->erasesize,
+                            status_old))
                return -EINVAL;
 
        /*
@@ -1200,8 +1200,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 
        if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
            JEDEC_MFR(info) == SNOR_MFR_INTEL ||
-           JEDEC_MFR(info) == SNOR_MFR_SST ||
-           JEDEC_MFR(info) == SNOR_MFR_WINBOND) {
+           JEDEC_MFR(info) == SNOR_MFR_SST) {
                write_enable(nor);
                write_sr(nor, 0);
        }
@@ -1217,8 +1216,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
        mtd->_read = spi_nor_read;
 
        /* NOR protection support for STmicro/Micron chips and similar */
-       if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||
-           JEDEC_MFR(info) == SNOR_MFR_WINBOND) {
+       if (JEDEC_MFR(info) == SNOR_MFR_MICRON) {
                nor->flash_lock = stm_lock;
                nor->flash_unlock = stm_unlock;
                nor->flash_is_locked = stm_is_locked;
index f8d7a2f06950139b936dc7d793bb884bb579980d..c82ab87fcbe8fb09e59be79f866910751f4b4308 100644 (file)
@@ -3430,25 +3430,29 @@ static u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb)
        return rc;
 }
 
-#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - 3)
+/* VXLAN: 4 = 1 (for linear data BD) + 3 (2 for PBD and last BD) */
+#define BNX2X_NUM_VXLAN_TSO_WIN_SUB_BDS         4
+
+/* Regular: 3 = 1 (for linear data BD) + 2 (for PBD and last BD) */
+#define BNX2X_NUM_TSO_WIN_SUB_BDS               3
+
+#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - BDS_PER_TX_PKT)
 /* check if packet requires linearization (packet is too fragmented)
    no need to check fragmentation if page size > 8K (there will be no
    violation to FW restrictions) */
 static int bnx2x_pkt_req_lin(struct bnx2x *bp, struct sk_buff *skb,
                             u32 xmit_type)
 {
-       int to_copy = 0;
-       int hlen = 0;
-       int first_bd_sz = 0;
+       int first_bd_sz = 0, num_tso_win_sub = BNX2X_NUM_TSO_WIN_SUB_BDS;
+       int to_copy = 0, hlen = 0;
 
-       /* 3 = 1 (for linear data BD) + 2 (for PBD and last BD) */
-       if (skb_shinfo(skb)->nr_frags >= (MAX_FETCH_BD - 3)) {
+       if (xmit_type & XMIT_GSO_ENC)
+               num_tso_win_sub = BNX2X_NUM_VXLAN_TSO_WIN_SUB_BDS;
 
+       if (skb_shinfo(skb)->nr_frags >= (MAX_FETCH_BD - num_tso_win_sub)) {
                if (xmit_type & XMIT_GSO) {
                        unsigned short lso_mss = skb_shinfo(skb)->gso_size;
-                       /* Check if LSO packet needs to be copied:
-                          3 = 1 (for headers BD) + 2 (for PBD and last BD) */
-                       int wnd_size = MAX_FETCH_BD - 3;
+                       int wnd_size = MAX_FETCH_BD - num_tso_win_sub;
                        /* Number of windows to check */
                        int num_wnds = skb_shinfo(skb)->nr_frags - wnd_size;
                        int wnd_idx = 0;
index c308429dd9c7fa0aebf2cee3b951f71f3863d939..11dd91e4db56b061311645567ab8c46f80123a61 100644 (file)
@@ -295,6 +295,10 @@ struct clip_tbl *t4_init_clip_tbl(unsigned int clipt_start,
                INIT_LIST_HEAD(&ctbl->hash_list[i]);
 
        cl_list = t4_alloc_mem(clipt_size*sizeof(struct clip_entry));
+       if (!cl_list) {
+               t4_free_mem(ctbl);
+               return NULL;
+       }
        ctbl->cl_list = (void *)cl_list;
 
        for (i = 0; i < clipt_size; i++) {
index d463563e1f7039ee5176ca36abfdc6bae3f2ed46..6ee78c203ecad7a18ba136e45ea0d2e24ec35930 100644 (file)
@@ -848,8 +848,6 @@ void be_roce_dev_remove(struct be_adapter *);
 /*
  * internal function to open-close roce device during ifup-ifdown.
  */
-void be_roce_dev_open(struct be_adapter *);
-void be_roce_dev_close(struct be_adapter *);
 void be_roce_dev_shutdown(struct be_adapter *);
 
 #endif                         /* BE_H */
index b6ad02909d6b3c87b861d4e35c345426bef30a64..8a1d9fffd7d671ea88023a120c93f4cdefbcff54 100644 (file)
@@ -3299,8 +3299,10 @@ static int be_msix_register(struct be_adapter *adapter)
 
        return 0;
 err_msix:
-       for (i--, eqo = &adapter->eq_obj[i]; i >= 0; i--, eqo--)
+       for (i--; i >= 0; i--) {
+               eqo = &adapter->eq_obj[i];
                free_irq(be_msix_vec_get(adapter, eqo), eqo);
+       }
        dev_warn(&adapter->pdev->dev, "MSIX Request IRQ failed - err %d\n",
                 status);
        be_msix_disable(adapter);
@@ -3432,8 +3434,6 @@ static int be_close(struct net_device *netdev)
 
        be_disable_if_filters(adapter);
 
-       be_roce_dev_close(adapter);
-
        if (adapter->flags & BE_FLAGS_NAPI_ENABLED) {
                for_all_evt_queues(adapter, eqo, i) {
                        napi_disable(&eqo->napi);
@@ -3601,8 +3601,6 @@ static int be_open(struct net_device *netdev)
                be_link_status_update(adapter, link_status);
 
        netif_tx_start_all_queues(netdev);
-       be_roce_dev_open(adapter);
-
 #ifdef CONFIG_BE2NET_VXLAN
        if (skyhawk_chip(adapter))
                vxlan_get_rx_port(netdev);
index 60368207bf584188b4d0293d9f2a8d7235180a8d..4089156a7f5e20177dfee8d29315c404924f4d9e 100644 (file)
@@ -116,40 +116,6 @@ void be_roce_dev_remove(struct be_adapter *adapter)
        }
 }
 
-static void _be_roce_dev_open(struct be_adapter *adapter)
-{
-       if (ocrdma_drv && adapter->ocrdma_dev &&
-           ocrdma_drv->state_change_handler)
-               ocrdma_drv->state_change_handler(adapter->ocrdma_dev,
-                                                BE_DEV_UP);
-}
-
-void be_roce_dev_open(struct be_adapter *adapter)
-{
-       if (be_roce_supported(adapter)) {
-               mutex_lock(&be_adapter_list_lock);
-               _be_roce_dev_open(adapter);
-               mutex_unlock(&be_adapter_list_lock);
-       }
-}
-
-static void _be_roce_dev_close(struct be_adapter *adapter)
-{
-       if (ocrdma_drv && adapter->ocrdma_dev &&
-           ocrdma_drv->state_change_handler)
-               ocrdma_drv->state_change_handler(adapter->ocrdma_dev,
-                                                BE_DEV_DOWN);
-}
-
-void be_roce_dev_close(struct be_adapter *adapter)
-{
-       if (be_roce_supported(adapter)) {
-               mutex_lock(&be_adapter_list_lock);
-               _be_roce_dev_close(adapter);
-               mutex_unlock(&be_adapter_list_lock);
-       }
-}
-
 void be_roce_dev_shutdown(struct be_adapter *adapter)
 {
        if (be_roce_supported(adapter)) {
@@ -177,8 +143,6 @@ int be_roce_register_driver(struct ocrdma_driver *drv)
 
                _be_roce_dev_add(dev);
                netdev = dev->netdev;
-               if (netif_running(netdev) && netif_oper_up(netdev))
-                       _be_roce_dev_open(dev);
        }
        mutex_unlock(&be_adapter_list_lock);
        return 0;
index cde6ef905ec481dce0436858fb1fd78252471146..fde609789483872582bda5a990d6bad357dc25df 100644 (file)
@@ -60,9 +60,7 @@ struct ocrdma_driver {
        void (*state_change_handler) (struct ocrdma_dev *, u32 new_state);
 };
 
-enum {
-       BE_DEV_UP       = 0,
-       BE_DEV_DOWN     = 1,
+enum be_roce_event {
        BE_DEV_SHUTDOWN = 2
 };
 
index 8a083d73efdbae61e7d71ee364c816b58a16b2f9..038f9ce391e626f02d3fe2f51a19fbd4b08a2711 100644 (file)
@@ -242,6 +242,13 @@ void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)
        unsigned long flags;
        u64 ns, zero = 0;
 
+       /* mlx4_en_init_timestamp is called for each netdev.
+        * mdev->ptp_clock is common for all ports, skip initialization if
+        * was done for other port.
+        */
+       if (mdev->ptp_clock)
+               return;
+
        rwlock_init(&mdev->clock_lock);
 
        memset(&mdev->cycles, 0, sizeof(mdev->cycles));
index 005f910ec955ecdaaa398c6edcc6d95c01d6c2c4..e0ec280a7fa13a55fd239f84c6f6c24db2c2e5e5 100644 (file)
@@ -232,9 +232,6 @@ static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr)
                if (mdev->pndev[i])
                        mlx4_en_destroy_netdev(mdev->pndev[i]);
 
-       if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
-               mlx4_en_remove_timestamp(mdev);
-
        flush_workqueue(mdev->workqueue);
        destroy_workqueue(mdev->workqueue);
        (void) mlx4_mr_free(dev, &mdev->mr);
@@ -320,10 +317,6 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
        mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH)
                mdev->port_cnt++;
 
-       /* Initialize time stamp mechanism */
-       if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
-               mlx4_en_init_timestamp(mdev);
-
        /* Set default number of RX rings*/
        mlx4_en_set_num_rx_rings(mdev);
 
index 886e1bc86374d990fc92655c7e1b40a3d611b45c..7869f97de5daf94cb99554c51a28a610aca76348 100644 (file)
@@ -2072,6 +2072,9 @@ void mlx4_en_destroy_netdev(struct net_device *dev)
        /* flush any pending task for this netdev */
        flush_workqueue(mdev->workqueue);
 
+       if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
+               mlx4_en_remove_timestamp(mdev);
+
        /* Detach the netdev so tasks would not attempt to access it */
        mutex_lock(&mdev->state_lock);
        mdev->pndev[priv->port] = NULL;
@@ -3058,9 +3061,12 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        }
        queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY);
 
+       /* Initialize time stamp mechanism */
        if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
-               queue_delayed_work(mdev->workqueue, &priv->service_task,
-                                  SERVICE_TASK_DELAY);
+               mlx4_en_init_timestamp(mdev);
+
+       queue_delayed_work(mdev->workqueue, &priv->service_task,
+                          SERVICE_TASK_DELAY);
 
        mlx4_en_set_stats_bitmap(mdev->dev, &priv->stats_bitmap,
                                 mdev->profile.prof[priv->port].rx_ppp,
index b83f7c0fcf9965b30fd179f72fa821b87d928bfd..122c2ee3dfe2aaa5948efd35158bf2fdf32bc0d5 100644 (file)
@@ -1937,6 +1937,12 @@ static void refill_rx(struct net_device *dev)
                                break; /* Better luck next round. */
                        np->rx_dma[entry] = pci_map_single(np->pci_dev,
                                skb->data, buflen, PCI_DMA_FROMDEVICE);
+                       if (pci_dma_mapping_error(np->pci_dev,
+                                                 np->rx_dma[entry])) {
+                               dev_kfree_skb_any(skb);
+                               np->rx_skbuff[entry] = NULL;
+                               break; /* Better luck next round. */
+                       }
                        np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]);
                }
                np->rx_ring[entry].cmd_status = cpu_to_le32(np->rx_buf_sz);
@@ -2093,6 +2099,12 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
        np->tx_skbuff[entry] = skb;
        np->tx_dma[entry] = pci_map_single(np->pci_dev,
                                skb->data,skb->len, PCI_DMA_TODEVICE);
+       if (pci_dma_mapping_error(np->pci_dev, np->tx_dma[entry])) {
+               np->tx_skbuff[entry] = NULL;
+               dev_kfree_skb_irq(skb);
+               dev->stats.tx_dropped++;
+               return NETDEV_TX_OK;
+       }
 
        np->tx_ring[entry].addr = cpu_to_le32(np->tx_dma[entry]);
 
index b1a452f291ee229866aae5d051385272e17e40dc..34906750b7e7091f5af122be88c659fd1c77f2e1 100644 (file)
@@ -252,7 +252,7 @@ int qlcnic_83xx_check_vnic_state(struct qlcnic_adapter *adapter)
                state = QLCRDX(ahw, QLC_83XX_VNIC_STATE);
        }
 
-       if (!idc->vnic_wait_limit) {
+       if (state != QLCNIC_DEV_NPAR_OPER) {
                dev_err(&adapter->pdev->dev,
                        "vNIC mode not operational, state check timed out.\n");
                return -EIO;
index a5f422f26cb4396a8dc25b65557c83793e956d94..daf05155b7329abdda58e63b1c19be9e06adc699 100644 (file)
@@ -772,8 +772,10 @@ int qlcnic_82xx_config_intrpt(struct qlcnic_adapter *adapter, u8 op_type)
        int i, err = 0;
 
        for (i = 0; i < ahw->num_msix; i++) {
-               qlcnic_alloc_mbx_args(&cmd, adapter,
-                                     QLCNIC_CMD_MQ_TX_CONFIG_INTR);
+               err = qlcnic_alloc_mbx_args(&cmd, adapter,
+                                           QLCNIC_CMD_MQ_TX_CONFIG_INTR);
+               if (err)
+                       return err;
                type = op_type ? QLCNIC_INTRPT_ADD : QLCNIC_INTRPT_DEL;
                val = type | (ahw->intr_tbl[i].type << 4);
                if (ahw->intr_tbl[i].type == QLCNIC_INTRPT_MSIX)
index a0eaf50499a292487333649052e1292c3cd28e19..6a8fc0f341ff2528fdda1cb97f8e2934d99c5f14 100644 (file)
@@ -1167,6 +1167,7 @@ static void sh_eth_ring_format(struct net_device *ndev)
        int tx_ringsize = sizeof(*txdesc) * mdp->num_tx_ring;
        int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN + 32 - 1;
        dma_addr_t dma_addr;
+       u32 buf_len;
 
        mdp->cur_rx = 0;
        mdp->cur_tx = 0;
@@ -1187,9 +1188,9 @@ static void sh_eth_ring_format(struct net_device *ndev)
                /* RX descriptor */
                rxdesc = &mdp->rx_ring[i];
                /* The size of the buffer is a multiple of 32 bytes. */
-               rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 32);
-               dma_addr = dma_map_single(&ndev->dev, skb->data,
-                                         rxdesc->buffer_length,
+               buf_len = ALIGN(mdp->rx_buf_sz, 32);
+               rxdesc->len = cpu_to_edmac(mdp, buf_len << 16);
+               dma_addr = dma_map_single(&ndev->dev, skb->data, buf_len,
                                          DMA_FROM_DEVICE);
                if (dma_mapping_error(&ndev->dev, dma_addr)) {
                        kfree_skb(skb);
@@ -1220,7 +1221,7 @@ static void sh_eth_ring_format(struct net_device *ndev)
                mdp->tx_skbuff[i] = NULL;
                txdesc = &mdp->tx_ring[i];
                txdesc->status = cpu_to_edmac(mdp, TD_TFP);
-               txdesc->buffer_length = 0;
+               txdesc->len = cpu_to_edmac(mdp, 0);
                if (i == 0) {
                        /* Tx descriptor address set */
                        sh_eth_write(ndev, mdp->tx_desc_dma, TDLAR);
@@ -1429,7 +1430,8 @@ static int sh_eth_txfree(struct net_device *ndev)
                if (mdp->tx_skbuff[entry]) {
                        dma_unmap_single(&ndev->dev,
                                         edmac_to_cpu(mdp, txdesc->addr),
-                                        txdesc->buffer_length, DMA_TO_DEVICE);
+                                        edmac_to_cpu(mdp, txdesc->len) >> 16,
+                                        DMA_TO_DEVICE);
                        dev_kfree_skb_irq(mdp->tx_skbuff[entry]);
                        mdp->tx_skbuff[entry] = NULL;
                        free_num++;
@@ -1439,7 +1441,7 @@ static int sh_eth_txfree(struct net_device *ndev)
                        txdesc->status |= cpu_to_edmac(mdp, TD_TDLE);
 
                ndev->stats.tx_packets++;
-               ndev->stats.tx_bytes += txdesc->buffer_length;
+               ndev->stats.tx_bytes += edmac_to_cpu(mdp, txdesc->len) >> 16;
        }
        return free_num;
 }
@@ -1458,6 +1460,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
        u32 desc_status;
        int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN + 32 - 1;
        dma_addr_t dma_addr;
+       u32 buf_len;
 
        boguscnt = min(boguscnt, *quota);
        limit = boguscnt;
@@ -1466,7 +1469,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
                /* RACT bit must be checked before all the following reads */
                dma_rmb();
                desc_status = edmac_to_cpu(mdp, rxdesc->status);
-               pkt_len = rxdesc->frame_length;
+               pkt_len = edmac_to_cpu(mdp, rxdesc->len) & RD_RFL;
 
                if (--boguscnt < 0)
                        break;
@@ -1532,7 +1535,8 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
                entry = mdp->dirty_rx % mdp->num_rx_ring;
                rxdesc = &mdp->rx_ring[entry];
                /* The size of the buffer is 32 byte boundary. */
-               rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 32);
+               buf_len = ALIGN(mdp->rx_buf_sz, 32);
+               rxdesc->len = cpu_to_edmac(mdp, buf_len << 16);
 
                if (mdp->rx_skbuff[entry] == NULL) {
                        skb = netdev_alloc_skb(ndev, skbuff_size);
@@ -1540,8 +1544,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
                                break;  /* Better luck next round. */
                        sh_eth_set_receive_align(skb);
                        dma_addr = dma_map_single(&ndev->dev, skb->data,
-                                                 rxdesc->buffer_length,
-                                                 DMA_FROM_DEVICE);
+                                                 buf_len, DMA_FROM_DEVICE);
                        if (dma_mapping_error(&ndev->dev, dma_addr)) {
                                kfree_skb(skb);
                                break;
@@ -2407,7 +2410,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                return NETDEV_TX_OK;
        }
        txdesc->addr = cpu_to_edmac(mdp, dma_addr);
-       txdesc->buffer_length = skb->len;
+       txdesc->len  = cpu_to_edmac(mdp, skb->len << 16);
 
        dma_wmb(); /* TACT bit must be set after all the above writes */
        if (entry >= mdp->num_tx_ring - 1)
index 26ad1cf0bcf158c0dcdca9b5fae3ffe18debaba9..72fcfc9245891e06bc4d37fd0e72a33880b48cd5 100644 (file)
@@ -283,7 +283,7 @@ enum DMAC_IM_BIT {
        DMAC_M_RINT1 = 0x00000001,
 };
 
-/* Receive descriptor bit */
+/* Receive descriptor 0 bits */
 enum RD_STS_BIT {
        RD_RACT = 0x80000000, RD_RDLE = 0x40000000,
        RD_RFP1 = 0x20000000, RD_RFP0 = 0x10000000,
@@ -298,6 +298,12 @@ enum RD_STS_BIT {
 #define RDFEND RD_RFP0
 #define RD_RFP (RD_RFP1|RD_RFP0)
 
+/* Receive descriptor 1 bits */
+enum RD_LEN_BIT {
+       RD_RFL  = 0x0000ffff,   /* receive frame  length */
+       RD_RBL  = 0xffff0000,   /* receive buffer length */
+};
+
 /* FCFTR */
 enum FCFTR_BIT {
        FCFTR_RFF2 = 0x00040000, FCFTR_RFF1 = 0x00020000,
@@ -307,7 +313,7 @@ enum FCFTR_BIT {
 #define DEFAULT_FIFO_F_D_RFF   (FCFTR_RFF2 | FCFTR_RFF1 | FCFTR_RFF0)
 #define DEFAULT_FIFO_F_D_RFD   (FCFTR_RFD2 | FCFTR_RFD1 | FCFTR_RFD0)
 
-/* Transmit descriptor bit */
+/* Transmit descriptor 0 bits */
 enum TD_STS_BIT {
        TD_TACT = 0x80000000, TD_TDLE = 0x40000000,
        TD_TFP1 = 0x20000000, TD_TFP0 = 0x10000000,
@@ -317,6 +323,11 @@ enum TD_STS_BIT {
 #define TDFEND TD_TFP0
 #define TD_TFP (TD_TFP1|TD_TFP0)
 
+/* Transmit descriptor 1 bits */
+enum TD_LEN_BIT {
+       TD_TBL  = 0xffff0000,   /* transmit buffer length */
+};
+
 /* RMCR */
 enum RMCR_BIT {
        RMCR_RNC = 0x00000001,
@@ -425,15 +436,9 @@ enum TSU_FWSLC_BIT {
  */
 struct sh_eth_txdesc {
        u32 status;             /* TD0 */
-#if defined(__LITTLE_ENDIAN)
-       u16 pad0;               /* TD1 */
-       u16 buffer_length;      /* TD1 */
-#else
-       u16 buffer_length;      /* TD1 */
-       u16 pad0;               /* TD1 */
-#endif
+       u32 len;                /* TD1 */
        u32 addr;               /* TD2 */
-       u32 pad1;               /* padding data */
+       u32 pad0;               /* padding data */
 } __aligned(2) __packed;
 
 /* The sh ether Rx buffer descriptors.
@@ -441,13 +446,7 @@ struct sh_eth_txdesc {
  */
 struct sh_eth_rxdesc {
        u32 status;             /* RD0 */
-#if defined(__LITTLE_ENDIAN)
-       u16 frame_length;       /* RD1 */
-       u16 buffer_length;      /* RD1 */
-#else
-       u16 buffer_length;      /* RD1 */
-       u16 frame_length;       /* RD1 */
-#endif
+       u32 len;                /* RD1 */
        u32 addr;               /* RD2 */
        u32 pad0;               /* padding data */
 } __aligned(2) __packed;
index 48b92c9de12a5af4f75ab6b48b4ffd39a77d6ed5..fc958067d10a77d248115968ec0dc4625460aee2 100644 (file)
@@ -2026,45 +2026,54 @@ static int cpsw_probe_dt(struct cpsw_priv *priv,
        for_each_child_of_node(node, slave_node) {
                struct cpsw_slave_data *slave_data = data->slave_data + i;
                const void *mac_addr = NULL;
-               u32 phyid;
                int lenp;
                const __be32 *parp;
-               struct device_node *mdio_node;
-               struct platform_device *mdio;
 
                /* This is no slave child node, continue */
                if (strcmp(slave_node->name, "slave"))
                        continue;
 
                priv->phy_node = of_parse_phandle(slave_node, "phy-handle", 0);
+               parp = of_get_property(slave_node, "phy_id", &lenp);
                if (of_phy_is_fixed_link(slave_node)) {
-                       struct phy_device *pd;
+                       struct device_node *phy_node;
+                       struct phy_device *phy_dev;
 
+                       /* In the case of a fixed PHY, the DT node associated
+                        * to the PHY is the Ethernet MAC DT node.
+                        */
                        ret = of_phy_register_fixed_link(slave_node);
                        if (ret)
                                return ret;
-                       pd = of_phy_find_device(slave_node);
-                       if (!pd)
+                       phy_node = of_node_get(slave_node);
+                       phy_dev = of_phy_find_device(phy_node);
+                       if (!phy_dev)
                                return -ENODEV;
                        snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
-                                PHY_ID_FMT, pd->bus->id, pd->phy_id);
-                       goto no_phy_slave;
-               }
-               parp = of_get_property(slave_node, "phy_id", &lenp);
-               if ((parp == NULL) || (lenp != (sizeof(void *) * 2))) {
-                       dev_err(&pdev->dev, "Missing slave[%d] phy_id property\n", i);
+                                PHY_ID_FMT, phy_dev->bus->id, phy_dev->addr);
+               } else if (parp) {
+                       u32 phyid;
+                       struct device_node *mdio_node;
+                       struct platform_device *mdio;
+
+                       if (lenp != (sizeof(__be32) * 2)) {
+                               dev_err(&pdev->dev, "Invalid slave[%d] phy_id property\n", i);
+                               goto no_phy_slave;
+                       }
+                       mdio_node = of_find_node_by_phandle(be32_to_cpup(parp));
+                       phyid = be32_to_cpup(parp+1);
+                       mdio = of_find_device_by_node(mdio_node);
+                       of_node_put(mdio_node);
+                       if (!mdio) {
+                               dev_err(&pdev->dev, "Missing mdio platform device\n");
+                               return -EINVAL;
+                       }
+                       snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
+                                PHY_ID_FMT, mdio->name, phyid);
+               } else {
+                       dev_err(&pdev->dev, "No slave[%d] phy_id or fixed-link property\n", i);
                        goto no_phy_slave;
                }
-               mdio_node = of_find_node_by_phandle(be32_to_cpup(parp));
-               phyid = be32_to_cpup(parp+1);
-               mdio = of_find_device_by_node(mdio_node);
-               of_node_put(mdio_node);
-               if (!mdio) {
-                       dev_err(&pdev->dev, "Missing mdio platform device\n");
-                       return -EINVAL;
-               }
-               snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
-                        PHY_ID_FMT, mdio->name, phyid);
                slave_data->phy_if = of_get_phy_mode(slave_node);
                if (slave_data->phy_if < 0) {
                        dev_err(&pdev->dev, "Missing or malformed slave[%d] phy-mode property\n",
@@ -2418,7 +2427,7 @@ static int cpsw_probe(struct platform_device *pdev)
        ndev->irq = platform_get_irq(pdev, 1);
        if (ndev->irq < 0) {
                dev_err(priv->dev, "error getting irq resource\n");
-               ret = -ENOENT;
+               ret = ndev->irq;
                goto clean_ale_ret;
        }
 
@@ -2439,8 +2448,10 @@ static int cpsw_probe(struct platform_device *pdev)
 
        /* RX IRQ */
        irq = platform_get_irq(pdev, 1);
-       if (irq < 0)
+       if (irq < 0) {
+               ret = irq;
                goto clean_ale_ret;
+       }
 
        priv->irqs_table[0] = irq;
        ret = devm_request_irq(&pdev->dev, irq, cpsw_rx_interrupt,
@@ -2452,8 +2463,10 @@ static int cpsw_probe(struct platform_device *pdev)
 
        /* TX IRQ */
        irq = platform_get_irq(pdev, 2);
-       if (irq < 0)
+       if (irq < 0) {
+               ret = irq;
                goto clean_ale_ret;
+       }
 
        priv->irqs_table[1] = irq;
        ret = devm_request_irq(&pdev->dev, irq, cpsw_tx_interrupt,
index c2b79f5d1c89b6b5872c8197fde3eb2d806d4f36..58efdec12f300dec69f6790c19f7cd56b10a4b22 100644 (file)
@@ -1155,7 +1155,7 @@ static int geneve_configure(struct net *net, struct net_device *dev,
        struct geneve_net *gn = net_generic(net, geneve_net_id);
        struct geneve_dev *t, *geneve = netdev_priv(dev);
        bool tun_collect_md, tun_on_same_port;
-       int err;
+       int err, encap_len;
 
        if (!remote)
                return -EINVAL;
@@ -1187,6 +1187,14 @@ static int geneve_configure(struct net *net, struct net_device *dev,
        if (t)
                return -EBUSY;
 
+       /* make enough headroom for basic scenario */
+       encap_len = GENEVE_BASE_HLEN + ETH_HLEN;
+       if (remote->sa.sa_family == AF_INET)
+               encap_len += sizeof(struct iphdr);
+       else
+               encap_len += sizeof(struct ipv6hdr);
+       dev->needed_headroom = encap_len + ETH_HLEN;
+
        if (metadata) {
                if (tun_on_same_port)
                        return -EPERM;
index 7c4a4151ef0f23fca16b0fd957769c09dc5823d0..5a1e98547031953b1eae1db7ae59a3750d935f40 100644 (file)
@@ -683,14 +683,20 @@ static void sixpack_close(struct tty_struct *tty)
        if (!atomic_dec_and_test(&sp->refcnt))
                down(&sp->dead_sem);
 
-       unregister_netdev(sp->dev);
+       /* We must stop the queue to avoid potentially scribbling
+        * on the free buffers. The sp->dead_sem is not sufficient
+        * to protect us from sp->xbuff access.
+        */
+       netif_stop_queue(sp->dev);
 
-       del_timer(&sp->tx_t);
-       del_timer(&sp->resync_t);
+       del_timer_sync(&sp->tx_t);
+       del_timer_sync(&sp->resync_t);
 
        /* Free all 6pack frame buffers. */
        kfree(sp->rbuff);
        kfree(sp->xbuff);
+
+       unregister_netdev(sp->dev);
 }
 
 /* Perform I/O control on an active 6pack channel. */
index 216bfd350169a9da723035876d152e89b17c8432..85828f1534454dbfd4020e6407e6ad2a136af93c 100644 (file)
@@ -797,14 +797,19 @@ static void mkiss_close(struct tty_struct *tty)
         */
        if (!atomic_dec_and_test(&ax->refcnt))
                down(&ax->dead_sem);
-
-       unregister_netdev(ax->dev);
+       /*
+        * Halt the transmit queue so that a new transmit cannot scribble
+        * on our buffers
+        */
+       netif_stop_queue(ax->dev);
 
        /* Free all AX25 frame buffers. */
        kfree(ax->rbuff);
        kfree(ax->xbuff);
 
        ax->tty = NULL;
+
+       unregister_netdev(ax->dev);
 }
 
 /* Perform I/O control on an active ax25 channel. */
index 8973abdec9f6bee3d849d72c3cc4c18006332f53..bdd83d95ec0aa677b8443476ef2ee66018aff701 100644 (file)
@@ -100,7 +100,7 @@ static const struct net_device_ops cdc_mbim_netdev_ops = {
        .ndo_stop             = usbnet_stop,
        .ndo_start_xmit       = usbnet_start_xmit,
        .ndo_tx_timeout       = usbnet_tx_timeout,
-       .ndo_change_mtu       = usbnet_change_mtu,
+       .ndo_change_mtu       = cdc_ncm_change_mtu,
        .ndo_set_mac_address  = eth_mac_addr,
        .ndo_validate_addr    = eth_validate_addr,
        .ndo_vlan_rx_add_vid  = cdc_mbim_rx_add_vid,
index 1e9843a411685ea887e1dd6d732cd8d5d7bb4a82..e8a1144c5a8bfa28c1ddca137c56c888b176ab32 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/ctype.h>
+#include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/workqueue.h>
 #include <linux/mii.h>
@@ -689,6 +690,33 @@ static void cdc_ncm_free(struct cdc_ncm_ctx *ctx)
        kfree(ctx);
 }
 
+/* we need to override the usbnet change_mtu ndo for two reasons:
+ *  - respect the negotiated maximum datagram size
+ *  - avoid unwanted changes to rx and tx buffers
+ */
+int cdc_ncm_change_mtu(struct net_device *net, int new_mtu)
+{
+       struct usbnet *dev = netdev_priv(net);
+       struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
+       int maxmtu = ctx->max_datagram_size - cdc_ncm_eth_hlen(dev);
+
+       if (new_mtu <= 0 || new_mtu > maxmtu)
+               return -EINVAL;
+       net->mtu = new_mtu;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(cdc_ncm_change_mtu);
+
+static const struct net_device_ops cdc_ncm_netdev_ops = {
+       .ndo_open            = usbnet_open,
+       .ndo_stop            = usbnet_stop,
+       .ndo_start_xmit      = usbnet_start_xmit,
+       .ndo_tx_timeout      = usbnet_tx_timeout,
+       .ndo_change_mtu      = cdc_ncm_change_mtu,
+       .ndo_set_mac_address = eth_mac_addr,
+       .ndo_validate_addr   = eth_validate_addr,
+};
+
 int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags)
 {
        struct cdc_ncm_ctx *ctx;
@@ -823,6 +851,9 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
        /* add our sysfs attrs */
        dev->net->sysfs_groups[0] = &cdc_ncm_sysfs_attr_group;
 
+       /* must handle MTU changes */
+       dev->net->netdev_ops = &cdc_ncm_netdev_ops;
+
        return 0;
 
 error2:
@@ -1558,6 +1589,24 @@ static const struct usb_device_id cdc_devs[] = {
          .driver_info = (unsigned long) &wwan_info,
        },
 
+       /* DW5812 LTE Verizon Mobile Broadband Card
+        * Unlike DW5550 this device requires FLAG_NOARP
+        */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x413c, 0x81bb,
+               USB_CLASS_COMM,
+               USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
+         .driver_info = (unsigned long)&wwan_noarp_info,
+       },
+
+       /* DW5813 LTE AT&T Mobile Broadband Card
+        * Unlike DW5550 this device requires FLAG_NOARP
+        */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x413c, 0x81bc,
+               USB_CLASS_COMM,
+               USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
+         .driver_info = (unsigned long)&wwan_noarp_info,
+       },
+
        /* Dell branded MBM devices like DW5550 */
        { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
                | USB_DEVICE_ID_MATCH_VENDOR,
index 9a5be8b851867e53f7427ba31f7a089ad02562fd..5fccc5a8153f4d0f73f0fb212912302c19679c27 100644 (file)
@@ -742,6 +742,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x413c, 0x81a9, 8)},    /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
        {QMI_FIXED_INTF(0x413c, 0x81b1, 8)},    /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
        {QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)},    /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
+       {QMI_FIXED_INTF(0x22de, 0x9061, 3)},    /* WeTelecom WPD-600N */
 
        /* 4. Gobi 1000 devices */
        {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},    /* Acer Gobi Modem Device */
index 2e32c41536ae9b0048e81e3fbb1faf8aa11327c3..2fb637ad594a96fa35f30f686e25973ea70b578a 100644 (file)
@@ -3525,6 +3525,14 @@ static int rtl8152_resume(struct usb_interface *intf)
        return 0;
 }
 
+static int rtl8152_reset_resume(struct usb_interface *intf)
+{
+       struct r8152 *tp = usb_get_intfdata(intf);
+
+       clear_bit(SELECTIVE_SUSPEND, &tp->flags);
+       return rtl8152_resume(intf);
+}
+
 static void rtl8152_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct r8152 *tp = netdev_priv(dev);
@@ -4276,7 +4284,7 @@ static struct usb_driver rtl8152_driver = {
        .disconnect =   rtl8152_disconnect,
        .suspend =      rtl8152_suspend,
        .resume =       rtl8152_resume,
-       .reset_resume = rtl8152_resume,
+       .reset_resume = rtl8152_reset_resume,
        .pre_reset =    rtl8152_pre_reset,
        .post_reset =   rtl8152_post_reset,
        .supports_autosuspend = 1,
index 0ef4a5ad555739870897bfbb96c7a95847deed20..ba21d072be31c95827833f9e5014f20cfa43bb8b 100644 (file)
@@ -117,12 +117,6 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
                kfree_skb(skb);
                goto drop;
        }
-       /* don't change ip_summed == CHECKSUM_PARTIAL, as that
-        * will cause bad checksum on forwarded packets
-        */
-       if (skb->ip_summed == CHECKSUM_NONE &&
-           rcv->features & NETIF_F_RXCSUM)
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
 
        if (likely(dev_forward_skb(rcv, skb) == NET_RX_SUCCESS)) {
                struct pcpu_vstats *stats = this_cpu_ptr(dev->vstats);
index 417903715437ebda5b07a859effdca86a62d196b..0cbf520cea778fc703c9657ab2d085eee522634b 100644 (file)
@@ -1380,10 +1380,10 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
                                        skip_page_frags = true;
                                        goto rcd_done;
                                }
-                               new_dma_addr = dma_map_page(&adapter->pdev->dev
-                                                       , rbi->page,
-                                                       0, PAGE_SIZE,
-                                                       PCI_DMA_FROMDEVICE);
+                               new_dma_addr = dma_map_page(&adapter->pdev->dev,
+                                                           new_page,
+                                                           0, PAGE_SIZE,
+                                                           PCI_DMA_FROMDEVICE);
                                if (dma_mapping_error(&adapter->pdev->dev,
                                                      new_dma_addr)) {
                                        put_page(new_page);
index 4c58c83dc2253a43b7c6150866d67bcd0c02e250..bdb8a6c0f8aa2c62e22edc64d3900530477b6fa8 100644 (file)
 /*
  * Version numbers
  */
-#define VMXNET3_DRIVER_VERSION_STRING   "1.4.4.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING   "1.4.5.0-k"
 
 /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM      0x01040400
+#define VMXNET3_DRIVER_VERSION_NUM      0x01040500
 
 #if defined(CONFIG_PCI_MSI)
        /* RSS only makes sense if MSI-X is supported. */
index 4f9748457f5a722658e5cfb01b6cbcc0f488d14f..0a242b200df4c9e8198a9a74764eb05f89f13cbd 100644 (file)
@@ -800,7 +800,7 @@ static struct rtable *vrf_get_rtable(const struct net_device *dev,
 }
 
 /* called under rcu_read_lock */
-static void vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4)
+static int vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4)
 {
        struct fib_result res = { .tclassid = 0 };
        struct net *net = dev_net(dev);
@@ -808,9 +808,10 @@ static void vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4)
        u8 flags = fl4->flowi4_flags;
        u8 scope = fl4->flowi4_scope;
        u8 tos = RT_FL_TOS(fl4);
+       int rc;
 
        if (unlikely(!fl4->daddr))
-               return;
+               return 0;
 
        fl4->flowi4_flags |= FLOWI_FLAG_SKIP_NH_OIF;
        fl4->flowi4_iif = LOOPBACK_IFINDEX;
@@ -818,7 +819,8 @@ static void vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4)
        fl4->flowi4_scope = ((tos & RTO_ONLINK) ?
                             RT_SCOPE_LINK : RT_SCOPE_UNIVERSE);
 
-       if (!fib_lookup(net, fl4, &res, 0)) {
+       rc = fib_lookup(net, fl4, &res, 0);
+       if (!rc) {
                if (res.type == RTN_LOCAL)
                        fl4->saddr = res.fi->fib_prefsrc ? : fl4->daddr;
                else
@@ -828,6 +830,8 @@ static void vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4)
        fl4->flowi4_flags = flags;
        fl4->flowi4_tos = orig_tos;
        fl4->flowi4_scope = scope;
+
+       return rc;
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
index bf88ec3a65fab3e04aab4398185236bdb955126b..d9a4aee246a6379c6a6aee7d6185ff680387c55e 100644 (file)
 #include "iwl-agn-hw.h"
 
 /* Highest firmware API version supported */
-#define IWL7260_UCODE_API_MAX  19
+#define IWL7260_UCODE_API_MAX  17
+#define IWL7265_UCODE_API_MAX  19
+#define IWL7265D_UCODE_API_MAX 19
 
 /* Oldest version we won't warn about */
 #define IWL7260_UCODE_API_OK   13
+#define IWL7265_UCODE_API_OK   13
+#define IWL7265D_UCODE_API_OK  13
 
 /* Lowest firmware API version supported */
 #define IWL7260_UCODE_API_MIN  13
+#define IWL7265_UCODE_API_MIN  13
+#define IWL7265D_UCODE_API_MIN 13
 
 /* NVM versions */
 #define IWL7260_NVM_VERSION            0x0a1d
@@ -149,10 +155,7 @@ static const struct iwl_ht_params iwl7000_ht_params = {
        .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
 };
 
-#define IWL_DEVICE_7000                                                \
-       .ucode_api_max = IWL7260_UCODE_API_MAX,                 \
-       .ucode_api_ok = IWL7260_UCODE_API_OK,                   \
-       .ucode_api_min = IWL7260_UCODE_API_MIN,                 \
+#define IWL_DEVICE_7000_COMMON                                 \
        .device_family = IWL_DEVICE_FAMILY_7000,                \
        .max_inst_size = IWL60_RTC_INST_SIZE,                   \
        .max_data_size = IWL60_RTC_DATA_SIZE,                   \
@@ -163,6 +166,24 @@ static const struct iwl_ht_params iwl7000_ht_params = {
        .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,    \
        .dccm_offset = IWL7000_DCCM_OFFSET
 
+#define IWL_DEVICE_7000                                                \
+       IWL_DEVICE_7000_COMMON,                                 \
+       .ucode_api_max = IWL7260_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL7260_UCODE_API_OK,                   \
+       .ucode_api_min = IWL7260_UCODE_API_MIN
+
+#define IWL_DEVICE_7005                                                \
+       IWL_DEVICE_7000_COMMON,                                 \
+       .ucode_api_max = IWL7265_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL7265_UCODE_API_OK,                   \
+       .ucode_api_min = IWL7265_UCODE_API_MIN
+
+#define IWL_DEVICE_7005D                                       \
+       IWL_DEVICE_7000_COMMON,                                 \
+       .ucode_api_max = IWL7265D_UCODE_API_MAX,                \
+       .ucode_api_ok = IWL7265D_UCODE_API_OK,                  \
+       .ucode_api_min = IWL7265D_UCODE_API_MIN
+
 const struct iwl_cfg iwl7260_2ac_cfg = {
        .name = "Intel(R) Dual Band Wireless AC 7260",
        .fw_name_pre = IWL7260_FW_PRE,
@@ -266,7 +287,7 @@ static const struct iwl_ht_params iwl7265_ht_params = {
 const struct iwl_cfg iwl3165_2ac_cfg = {
        .name = "Intel(R) Dual Band Wireless AC 3165",
        .fw_name_pre = IWL7265D_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005D,
        .ht_params = &iwl7000_ht_params,
        .nvm_ver = IWL3165_NVM_VERSION,
        .nvm_calib_ver = IWL3165_TX_POWER_VERSION,
@@ -277,7 +298,7 @@ const struct iwl_cfg iwl3165_2ac_cfg = {
 const struct iwl_cfg iwl7265_2ac_cfg = {
        .name = "Intel(R) Dual Band Wireless AC 7265",
        .fw_name_pre = IWL7265_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005,
        .ht_params = &iwl7265_ht_params,
        .nvm_ver = IWL7265_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -288,7 +309,7 @@ const struct iwl_cfg iwl7265_2ac_cfg = {
 const struct iwl_cfg iwl7265_2n_cfg = {
        .name = "Intel(R) Dual Band Wireless N 7265",
        .fw_name_pre = IWL7265_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005,
        .ht_params = &iwl7265_ht_params,
        .nvm_ver = IWL7265_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -299,7 +320,7 @@ const struct iwl_cfg iwl7265_2n_cfg = {
 const struct iwl_cfg iwl7265_n_cfg = {
        .name = "Intel(R) Wireless N 7265",
        .fw_name_pre = IWL7265_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005,
        .ht_params = &iwl7265_ht_params,
        .nvm_ver = IWL7265_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -310,7 +331,7 @@ const struct iwl_cfg iwl7265_n_cfg = {
 const struct iwl_cfg iwl7265d_2ac_cfg = {
        .name = "Intel(R) Dual Band Wireless AC 7265",
        .fw_name_pre = IWL7265D_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005D,
        .ht_params = &iwl7265_ht_params,
        .nvm_ver = IWL7265D_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -321,7 +342,7 @@ const struct iwl_cfg iwl7265d_2ac_cfg = {
 const struct iwl_cfg iwl7265d_2n_cfg = {
        .name = "Intel(R) Dual Band Wireless N 7265",
        .fw_name_pre = IWL7265D_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005D,
        .ht_params = &iwl7265_ht_params,
        .nvm_ver = IWL7265D_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -332,7 +353,7 @@ const struct iwl_cfg iwl7265d_2n_cfg = {
 const struct iwl_cfg iwl7265d_n_cfg = {
        .name = "Intel(R) Wireless N 7265",
        .fw_name_pre = IWL7265D_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005D,
        .ht_params = &iwl7265_ht_params,
        .nvm_ver = IWL7265D_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -342,5 +363,5 @@ const struct iwl_cfg iwl7265d_n_cfg = {
 
 MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
 MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
-MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
-MODULE_FIRMWARE(IWL7265D_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
+MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7265_UCODE_API_OK));
+MODULE_FIRMWARE(IWL7265D_MODULE_FIRMWARE(IWL7265D_UCODE_API_OK));
index 354acbde088e9e6fad0927a9ef73787ab235558c..2b976b110207f87532162e6f8587c1fcd0063c83 100644 (file)
@@ -1222,8 +1222,8 @@ static u8 iwl_mvm_get_key_sta_id(struct iwl_mvm *mvm,
            mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
                u8 sta_id = mvmvif->ap_sta_id;
 
-               sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
-                                               lockdep_is_held(&mvm->mutex));
+               sta = rcu_dereference_check(mvm->fw_id_to_mac_id[sta_id],
+                                           lockdep_is_held(&mvm->mutex));
                /*
                 * It is possible that the 'sta' parameter is NULL,
                 * for example when a GTK is removed - the sta_id will then
@@ -1590,14 +1590,15 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
                             u16 *phase1key)
 {
        struct iwl_mvm_sta *mvm_sta;
-       u8 sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta);
+       u8 sta_id;
        bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
 
-       if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT))
-               return;
-
        rcu_read_lock();
 
+       sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta);
+       if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT))
+               goto unlock;
+
        if (!sta) {
                sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
                if (WARN_ON(IS_ERR_OR_NULL(sta))) {
@@ -1609,6 +1610,8 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
        mvm_sta = iwl_mvm_sta_from_mac80211(sta);
        iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
                             iv32, phase1key, CMD_ASYNC, keyconf->hw_key_idx);
+
+ unlock:
        rcu_read_unlock();
 }
 
index f131ba947dc6fe47941b09b0e6d1d35f2a53c255..c0ad9aaa16a75a815cb4fc605a270dbcadb07198 100644 (file)
@@ -5,6 +5,7 @@ config PCI_DRA7XX
        bool "TI DRA7xx PCIe controller"
        select PCIE_DW
        depends on OF && HAS_IOMEM && TI_PIPE3
+       depends on BROKEN
        help
         Enables support for the PCIe controller in the DRA7xx SoC.  There
         are two instances of PCIe controller in DRA7xx.  This controller can
index 163671a4f798dfc18bb24f3490ad7138753efac1..77f7c669a1b9bb497528874c10262430c868959d 100644 (file)
@@ -61,7 +61,9 @@ static int hisi_pcie_cfg_read(struct pcie_port *pp, int where, int size,
                *val = *(u8 __force *) walker;
        else if (size == 2)
                *val = *(u16 __force *) walker;
-       else if (size != 4)
+       else if (size == 4)
+               *val = reg_val;
+       else
                return PCIBIOS_BAD_REGISTER_NUMBER;
 
        return PCIBIOS_SUCCESSFUL;
index 7eaa4c87fec71c8dd792ccffc919b322711d91dd..7a0df3fdbfaef97267cf15743b42c1e37a958145 100644 (file)
@@ -257,6 +257,7 @@ void pci_msi_mask_irq(struct irq_data *data)
 {
        msi_set_mask_bit(data, 1);
 }
+EXPORT_SYMBOL_GPL(pci_msi_mask_irq);
 
 /**
  * pci_msi_unmask_irq - Generic irq chip callback to unmask PCI/MSI interrupts
@@ -266,6 +267,7 @@ void pci_msi_unmask_irq(struct irq_data *data)
 {
        msi_set_mask_bit(data, 0);
 }
+EXPORT_SYMBOL_GPL(pci_msi_unmask_irq);
 
 void default_restore_msi_irqs(struct pci_dev *dev)
 {
@@ -1126,6 +1128,7 @@ struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc)
 {
        return to_pci_dev(desc->dev);
 }
+EXPORT_SYMBOL(msi_desc_to_pci_dev);
 
 void *msi_desc_to_pci_sysdata(struct msi_desc *desc)
 {
@@ -1285,6 +1288,7 @@ struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode,
        domain->bus_token = DOMAIN_BUS_PCI_MSI;
        return domain;
 }
+EXPORT_SYMBOL_GPL(pci_msi_create_irq_domain);
 
 /**
  * pci_msi_domain_alloc_irqs - Allocate interrupts for @dev in @domain
index a32ba753e4135862825c60690f83f1f9b145fa07..d3f32d6417ef099c74e8f9ec1728225d9bc67974 100644 (file)
@@ -9,7 +9,9 @@
 
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/irqdomain.h>
 #include <linux/pci.h>
+#include <linux/msi.h>
 #include <linux/pci_hotplug.h>
 #include <linux/module.h>
 #include <linux/pci-aspm.h>
@@ -689,6 +691,46 @@ static struct acpi_bus_type acpi_pci_bus = {
        .cleanup = pci_acpi_cleanup,
 };
 
+
+static struct fwnode_handle *(*pci_msi_get_fwnode_cb)(struct device *dev);
+
+/**
+ * pci_msi_register_fwnode_provider - Register callback to retrieve fwnode
+ * @fn:       Callback matching a device to a fwnode that identifies a PCI
+ *            MSI domain.
+ *
+ * This should be called by irqchip driver, which is the parent of
+ * the MSI domain to provide callback interface to query fwnode.
+ */
+void
+pci_msi_register_fwnode_provider(struct fwnode_handle *(*fn)(struct device *))
+{
+       pci_msi_get_fwnode_cb = fn;
+}
+
+/**
+ * pci_host_bridge_acpi_msi_domain - Retrieve MSI domain of a PCI host bridge
+ * @bus:      The PCI host bridge bus.
+ *
+ * This function uses the callback function registered by
+ * pci_msi_register_fwnode_provider() to retrieve the irq_domain with
+ * type DOMAIN_BUS_PCI_MSI of the specified host bridge bus.
+ * This returns NULL on error or when the domain is not found.
+ */
+struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
+{
+       struct fwnode_handle *fwnode;
+
+       if (!pci_msi_get_fwnode_cb)
+               return NULL;
+
+       fwnode = pci_msi_get_fwnode_cb(&bus->dev);
+       if (!fwnode)
+               return NULL;
+
+       return irq_find_matching_fwnode(fwnode, DOMAIN_BUS_PCI_MSI);
+}
+
 static int __init acpi_pci_init(void)
 {
        int ret;
index edb1984201e9702162321c50f33f76ba362bac5a..553a029e37f15586c96198a098cbb40de91ef49a 100644 (file)
@@ -672,6 +672,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
         * should be called from here.
         */
        d = pci_host_bridge_of_msi_domain(bus);
+       if (!d)
+               d = pci_host_bridge_acpi_msi_domain(bus);
 
        return d;
 }
index be3755c973e96d4c6ee48f0459c751ba6d225665..166637f2917cc563d8a0acc34da2dc6ab22319f1 100644 (file)
@@ -551,14 +551,6 @@ static void armpmu_init(struct arm_pmu *armpmu)
        };
 }
 
-int armpmu_register(struct arm_pmu *armpmu, int type)
-{
-       armpmu_init(armpmu);
-       pr_info("enabled with %s PMU driver, %d counters available\n",
-                       armpmu->name, armpmu->num_events);
-       return perf_pmu_register(&armpmu->pmu, armpmu->name, type);
-}
-
 /* Set at runtime when we know what CPU type we are. */
 static struct arm_pmu *__oprofile_cpu_pmu;
 
@@ -887,6 +879,8 @@ int arm_pmu_device_probe(struct platform_device *pdev,
                return -ENOMEM;
        }
 
+       armpmu_init(pmu);
+
        if (!__oprofile_cpu_pmu)
                __oprofile_cpu_pmu = pmu;
 
@@ -912,10 +906,13 @@ int arm_pmu_device_probe(struct platform_device *pdev,
        if (ret)
                goto out_free;
 
-       ret = armpmu_register(pmu, -1);
+       ret = perf_pmu_register(&pmu->pmu, pmu->name, -1);
        if (ret)
                goto out_destroy;
 
+       pr_info("enabled with %s PMU driver, %d counters available\n",
+                       pmu->name, pmu->num_events);
+
        return 0;
 
 out_destroy:
index 312c78b27a3206c813c85912e14b570ffa43a0a6..99a4c10ed43f7a964c805f0bf55db367d07f9168 100644 (file)
@@ -244,7 +244,7 @@ config PINCTRL_ZYNQ
        select PINMUX
        select GENERIC_PINCONF
        help
-         This selectes the pinctrl driver for Xilinx Zynq.
+         This selects the pinctrl driver for Xilinx Zynq.
 
 source "drivers/pinctrl/bcm/Kconfig"
 source "drivers/pinctrl/berlin/Kconfig"
@@ -252,6 +252,7 @@ source "drivers/pinctrl/freescale/Kconfig"
 source "drivers/pinctrl/intel/Kconfig"
 source "drivers/pinctrl/mvebu/Kconfig"
 source "drivers/pinctrl/nomadik/Kconfig"
+source "drivers/pinctrl/pxa/Kconfig"
 source "drivers/pinctrl/qcom/Kconfig"
 source "drivers/pinctrl/samsung/Kconfig"
 source "drivers/pinctrl/sh-pfc/Kconfig"
index 738cb4929a49428890f543df5eab92976d40dbe7..bf1b5ca5180b5a899263ff43b819a04c2135f1c1 100644 (file)
@@ -41,15 +41,16 @@ obj-$(CONFIG_PINCTRL_ST)    += pinctrl-st.o
 obj-$(CONFIG_PINCTRL_ZYNQ)     += pinctrl-zynq.o
 
 obj-$(CONFIG_ARCH_BCM)         += bcm/
-obj-$(CONFIG_ARCH_BERLIN)      += berlin/
+obj-$(CONFIG_PINCTRL_BERLIN)   += berlin/
 obj-y                          += freescale/
 obj-$(CONFIG_X86)              += intel/
-obj-$(CONFIG_PLAT_ORION)        += mvebu/
+obj-$(CONFIG_PINCTRL_MVEBU)    += mvebu/
 obj-y                          += nomadik/
+obj-$(CONFIG_ARCH_PXA)         += pxa/
 obj-$(CONFIG_ARCH_QCOM)                += qcom/
 obj-$(CONFIG_PINCTRL_SAMSUNG)  += samsung/
 obj-$(CONFIG_PINCTRL_SH_PFC)   += sh-pfc/
-obj-$(CONFIG_PLAT_SPEAR)       += spear/
+obj-$(CONFIG_PINCTRL_SPEAR)    += spear/
 obj-$(CONFIG_ARCH_SUNXI)       += sunxi/
 obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/
 obj-$(CONFIG_ARCH_VT8500)      += vt8500/
index cd11d4d9ad58f86c719eca0193c9fe08ffd16f21..2cc74384cafadaed0025ad1e501f6576e5345d73 100644 (file)
@@ -9,6 +9,7 @@ config PINCTRL_BCM281XX
        select PINCONF
        select GENERIC_PINCONF
        select REGMAP_MMIO
+       default ARCH_BCM_MOBILE
        help
          Say Y here to support Broadcom BCM281xx pinctrl driver, which is used
          for the BCM281xx SoC family, including BCM11130, BCM11140, BCM11351,
@@ -20,27 +21,41 @@ config PINCTRL_BCM2835
        select PINMUX
        select PINCONF
 
-config PINCTRL_CYGNUS_GPIO
-       bool "Broadcom Cygnus GPIO (with PINCONF) driver"
-       depends on OF_GPIO && ARCH_BCM_CYGNUS
+config PINCTRL_IPROC_GPIO
+       bool "Broadcom iProc GPIO (with PINCONF) driver"
+       depends on OF_GPIO && (ARCH_BCM_IPROC || COMPILE_TEST)
        select GPIOLIB_IRQCHIP
        select PINCONF
        select GENERIC_PINCONF
-       default ARCH_BCM_CYGNUS
+       default ARCH_BCM_IPROC
        help
-         Say yes here to enable the Broadcom Cygnus GPIO driver.
+         Say yes here to enable the Broadcom iProc GPIO driver.
+
+         The Broadcom iProc based SoCs- Cygnus, NS2, NSP and Stingray, use
+         same GPIO Controller IP hence this driver could be used for all.
 
          The Broadcom Cygnus SoC has 3 GPIO controllers including the ASIU
          GPIO controller (ASIU), the chipCommonG GPIO controller (CCM), and
          the always-ON GPIO controller (CRMU/AON). All 3 GPIO controllers are
          supported by this driver.
 
-         All 3 Cygnus GPIO controllers support basic PINCONF functions such
+         The Broadcom NSP has two GPIO controllers including the ChipcommonA
+         GPIO, the ChipcommonB GPIO. Later controller is supported by this
+         driver.
+
+         The Broadcom NS2 has two GPIO controller including the CRMU GPIO,
+         the ChipcommonG GPIO. Both controllers are supported by this driver.
+
+         The Broadcom Stingray GPIO controllers are supported by this driver.
+
+         All above SoCs GPIO controllers support basic PINCONF functions such
          as bias pull up, pull down, and drive strength configurations, when
          these pins are muxed to GPIO.
 
-         Pins from the ASIU GPIO can be individually muxed to GPIO function,
-         through interaction with the Cygnus IOMUX controller.
+         It provides the framework where pins from the individual GPIO can be
+         individually muxed to GPIO function, through interaction with the
+         SoCs IOMUX controller. This features could be used only on SoCs which
+         support individual pin muxing.
 
 config PINCTRL_CYGNUS_MUX
        bool "Broadcom Cygnus IOMUX driver"
@@ -54,3 +69,20 @@ config PINCTRL_CYGNUS_MUX
          The Broadcom Cygnus IOMUX driver supports group based IOMUX
          configuration, with the exception that certain individual pins
          can be overrided to GPIO function
+
+config PINCTRL_NSP_GPIO
+       bool "Broadcom NSP GPIO (with PINCONF) driver"
+       depends on OF_GPIO && (ARCH_BCM_NSP || COMPILE_TEST)
+       select GPIOLIB_IRQCHIP
+       select PINCONF
+       select GENERIC_PINCONF
+       default ARCH_BCM_NSP
+       help
+         Say yes here to enable the Broadcom NSP GPIO driver.
+
+         The Broadcom Northstar Plus SoC ChipcommonA GPIO controller is
+         supported by this driver.
+
+         The ChipcommonA GPIO controller support basic PINCONF functions such
+         as bias pull up, pull down, and drive strength configurations, when
+         these pins are muxed to GPIO.
index 2b2f70ee804ccd607703a42698027f3435b9c760..6148367d5e8cdd1762429a16bac7de24bd6bd51d 100644 (file)
@@ -2,5 +2,6 @@
 
 obj-$(CONFIG_PINCTRL_BCM281XX)         += pinctrl-bcm281xx.o
 obj-$(CONFIG_PINCTRL_BCM2835)          += pinctrl-bcm2835.o
-obj-$(CONFIG_PINCTRL_CYGNUS_GPIO)      += pinctrl-cygnus-gpio.o
+obj-$(CONFIG_PINCTRL_IPROC_GPIO)       += pinctrl-iproc-gpio.o
 obj-$(CONFIG_PINCTRL_CYGNUS_MUX)       += pinctrl-cygnus-mux.o
+obj-$(CONFIG_PINCTRL_NSP_GPIO)         += pinctrl-nsp-gpio.o
index 2e6ca69635aa001531d2b9aca128d001b97d9aca..75b0d8c8f05815583c07a8fd95f680164476e54b 100644 (file)
@@ -795,7 +795,7 @@ static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
        return 0;
 
 out:
-       kfree(maps);
+       bcm2835_pctl_dt_free_map(pctldev, maps, num_pins * maps_per_pin);
        return err;
 }
 
diff --git a/drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c b/drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c
deleted file mode 100644 (file)
index 12a48f4..0000000
+++ /dev/null
@@ -1,784 +0,0 @@
-/*
- * Copyright (C) 2014-2015 Broadcom Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation 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.
- *
- * This file contains the Broadcom Cygnus GPIO driver that supports 3
- * GPIO controllers on Cygnus including the ASIU GPIO controller, the
- * chipCommonG GPIO controller, and the always-on GPIO controller. Basic
- * PINCONF such as bias pull up/down, and drive strength are also supported
- * in this driver.
- *
- * Pins from the ASIU GPIO can be individually muxed to GPIO function,
- * through the interaction with the Cygnus IOMUX controller
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/ioport.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
-#include <linux/pinctrl/pinctrl.h>
-#include <linux/pinctrl/pinconf.h>
-#include <linux/pinctrl/pinconf-generic.h>
-
-#include "../pinctrl-utils.h"
-
-#define CYGNUS_GPIO_DATA_IN_OFFSET   0x00
-#define CYGNUS_GPIO_DATA_OUT_OFFSET  0x04
-#define CYGNUS_GPIO_OUT_EN_OFFSET    0x08
-#define CYGNUS_GPIO_INT_TYPE_OFFSET  0x0c
-#define CYGNUS_GPIO_INT_DE_OFFSET    0x10
-#define CYGNUS_GPIO_INT_EDGE_OFFSET  0x14
-#define CYGNUS_GPIO_INT_MSK_OFFSET   0x18
-#define CYGNUS_GPIO_INT_STAT_OFFSET  0x1c
-#define CYGNUS_GPIO_INT_MSTAT_OFFSET 0x20
-#define CYGNUS_GPIO_INT_CLR_OFFSET   0x24
-#define CYGNUS_GPIO_PAD_RES_OFFSET   0x34
-#define CYGNUS_GPIO_RES_EN_OFFSET    0x38
-
-/* drive strength control for ASIU GPIO */
-#define CYGNUS_GPIO_ASIU_DRV0_CTRL_OFFSET 0x58
-
-/* drive strength control for CCM/CRMU (AON) GPIO */
-#define CYGNUS_GPIO_DRV0_CTRL_OFFSET  0x00
-
-#define GPIO_BANK_SIZE 0x200
-#define NGPIOS_PER_BANK 32
-#define GPIO_BANK(pin) ((pin) / NGPIOS_PER_BANK)
-
-#define CYGNUS_GPIO_REG(pin, reg) (GPIO_BANK(pin) * GPIO_BANK_SIZE + (reg))
-#define CYGNUS_GPIO_SHIFT(pin) ((pin) % NGPIOS_PER_BANK)
-
-#define GPIO_DRV_STRENGTH_BIT_SHIFT  20
-#define GPIO_DRV_STRENGTH_BITS       3
-#define GPIO_DRV_STRENGTH_BIT_MASK   ((1 << GPIO_DRV_STRENGTH_BITS) - 1)
-
-/*
- * Cygnus GPIO core
- *
- * @dev: pointer to device
- * @base: I/O register base for Cygnus GPIO controller
- * @io_ctrl: I/O register base for certain type of Cygnus GPIO controller that
- * has the PINCONF support implemented outside of the GPIO block
- * @lock: lock to protect access to I/O registers
- * @gc: GPIO chip
- * @num_banks: number of GPIO banks, each bank supports up to 32 GPIOs
- * @pinmux_is_supported: flag to indicate this GPIO controller contains pins
- * that can be individually muxed to GPIO
- * @pctl: pointer to pinctrl_dev
- * @pctldesc: pinctrl descriptor
- */
-struct cygnus_gpio {
-       struct device *dev;
-
-       void __iomem *base;
-       void __iomem *io_ctrl;
-
-       spinlock_t lock;
-
-       struct gpio_chip gc;
-       unsigned num_banks;
-
-       bool pinmux_is_supported;
-
-       struct pinctrl_dev *pctl;
-       struct pinctrl_desc pctldesc;
-};
-
-static inline struct cygnus_gpio *to_cygnus_gpio(struct gpio_chip *gc)
-{
-       return container_of(gc, struct cygnus_gpio, gc);
-}
-
-/*
- * Mapping from PINCONF pins to GPIO pins is 1-to-1
- */
-static inline unsigned cygnus_pin_to_gpio(unsigned pin)
-{
-       return pin;
-}
-
-/**
- *  cygnus_set_bit - set or clear one bit (corresponding to the GPIO pin) in a
- *  Cygnus GPIO register
- *
- *  @cygnus_gpio: Cygnus GPIO device
- *  @reg: register offset
- *  @gpio: GPIO pin
- *  @set: set or clear
- */
-static inline void cygnus_set_bit(struct cygnus_gpio *chip, unsigned int reg,
-                                 unsigned gpio, bool set)
-{
-       unsigned int offset = CYGNUS_GPIO_REG(gpio, reg);
-       unsigned int shift = CYGNUS_GPIO_SHIFT(gpio);
-       u32 val;
-
-       val = readl(chip->base + offset);
-       if (set)
-               val |= BIT(shift);
-       else
-               val &= ~BIT(shift);
-       writel(val, chip->base + offset);
-}
-
-static inline bool cygnus_get_bit(struct cygnus_gpio *chip, unsigned int reg,
-                                 unsigned gpio)
-{
-       unsigned int offset = CYGNUS_GPIO_REG(gpio, reg);
-       unsigned int shift = CYGNUS_GPIO_SHIFT(gpio);
-
-       return !!(readl(chip->base + offset) & BIT(shift));
-}
-
-static void cygnus_gpio_irq_handler(struct irq_desc *desc)
-{
-       struct gpio_chip *gc = irq_desc_get_handler_data(desc);
-       struct cygnus_gpio *chip = to_cygnus_gpio(gc);
-       struct irq_chip *irq_chip = irq_desc_get_chip(desc);
-       int i, bit;
-
-       chained_irq_enter(irq_chip, desc);
-
-       /* go through the entire GPIO banks and handle all interrupts */
-       for (i = 0; i < chip->num_banks; i++) {
-               unsigned long val = readl(chip->base + (i * GPIO_BANK_SIZE) +
-                                         CYGNUS_GPIO_INT_MSTAT_OFFSET);
-
-               for_each_set_bit(bit, &val, NGPIOS_PER_BANK) {
-                       unsigned pin = NGPIOS_PER_BANK * i + bit;
-                       int child_irq = irq_find_mapping(gc->irqdomain, pin);
-
-                       /*
-                        * Clear the interrupt before invoking the
-                        * handler, so we do not leave any window
-                        */
-                       writel(BIT(bit), chip->base + (i * GPIO_BANK_SIZE) +
-                              CYGNUS_GPIO_INT_CLR_OFFSET);
-
-                       generic_handle_irq(child_irq);
-               }
-       }
-
-       chained_irq_exit(irq_chip, desc);
-}
-
-
-static void cygnus_gpio_irq_ack(struct irq_data *d)
-{
-       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-       struct cygnus_gpio *chip = to_cygnus_gpio(gc);
-       unsigned gpio = d->hwirq;
-       unsigned int offset = CYGNUS_GPIO_REG(gpio,
-                       CYGNUS_GPIO_INT_CLR_OFFSET);
-       unsigned int shift = CYGNUS_GPIO_SHIFT(gpio);
-       u32 val = BIT(shift);
-
-       writel(val, chip->base + offset);
-}
-
-/**
- *  cygnus_gpio_irq_set_mask - mask/unmask a GPIO interrupt
- *
- *  @d: IRQ chip data
- *  @unmask: mask/unmask GPIO interrupt
- */
-static void cygnus_gpio_irq_set_mask(struct irq_data *d, bool unmask)
-{
-       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-       struct cygnus_gpio *chip = to_cygnus_gpio(gc);
-       unsigned gpio = d->hwirq;
-
-       cygnus_set_bit(chip, CYGNUS_GPIO_INT_MSK_OFFSET, gpio, unmask);
-}
-
-static void cygnus_gpio_irq_mask(struct irq_data *d)
-{
-       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-       struct cygnus_gpio *chip = to_cygnus_gpio(gc);
-       unsigned long flags;
-
-       spin_lock_irqsave(&chip->lock, flags);
-       cygnus_gpio_irq_set_mask(d, false);
-       spin_unlock_irqrestore(&chip->lock, flags);
-}
-
-static void cygnus_gpio_irq_unmask(struct irq_data *d)
-{
-       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-       struct cygnus_gpio *chip = to_cygnus_gpio(gc);
-       unsigned long flags;
-
-       spin_lock_irqsave(&chip->lock, flags);
-       cygnus_gpio_irq_set_mask(d, true);
-       spin_unlock_irqrestore(&chip->lock, flags);
-}
-
-static int cygnus_gpio_irq_set_type(struct irq_data *d, unsigned int type)
-{
-       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-       struct cygnus_gpio *chip = to_cygnus_gpio(gc);
-       unsigned gpio = d->hwirq;
-       bool level_triggered = false;
-       bool dual_edge = false;
-       bool rising_or_high = false;
-       unsigned long flags;
-
-       switch (type & IRQ_TYPE_SENSE_MASK) {
-       case IRQ_TYPE_EDGE_RISING:
-               rising_or_high = true;
-               break;
-
-       case IRQ_TYPE_EDGE_FALLING:
-               break;
-
-       case IRQ_TYPE_EDGE_BOTH:
-               dual_edge = true;
-               break;
-
-       case IRQ_TYPE_LEVEL_HIGH:
-               level_triggered = true;
-               rising_or_high = true;
-               break;
-
-       case IRQ_TYPE_LEVEL_LOW:
-               level_triggered = true;
-               break;
-
-       default:
-               dev_err(chip->dev, "invalid GPIO IRQ type 0x%x\n",
-                       type);
-               return -EINVAL;
-       }
-
-       spin_lock_irqsave(&chip->lock, flags);
-       cygnus_set_bit(chip, CYGNUS_GPIO_INT_TYPE_OFFSET, gpio,
-                      level_triggered);
-       cygnus_set_bit(chip, CYGNUS_GPIO_INT_DE_OFFSET, gpio, dual_edge);
-       cygnus_set_bit(chip, CYGNUS_GPIO_INT_EDGE_OFFSET, gpio,
-                      rising_or_high);
-       spin_unlock_irqrestore(&chip->lock, flags);
-
-       dev_dbg(chip->dev,
-               "gpio:%u level_triggered:%d dual_edge:%d rising_or_high:%d\n",
-               gpio, level_triggered, dual_edge, rising_or_high);
-
-       return 0;
-}
-
-static struct irq_chip cygnus_gpio_irq_chip = {
-       .name = "bcm-cygnus-gpio",
-       .irq_ack = cygnus_gpio_irq_ack,
-       .irq_mask = cygnus_gpio_irq_mask,
-       .irq_unmask = cygnus_gpio_irq_unmask,
-       .irq_set_type = cygnus_gpio_irq_set_type,
-};
-
-/*
- * Request the Cygnus IOMUX pinmux controller to mux individual pins to GPIO
- */
-static int cygnus_gpio_request(struct gpio_chip *gc, unsigned offset)
-{
-       struct cygnus_gpio *chip = to_cygnus_gpio(gc);
-       unsigned gpio = gc->base + offset;
-
-       /* not all Cygnus GPIO pins can be muxed individually */
-       if (!chip->pinmux_is_supported)
-               return 0;
-
-       return pinctrl_request_gpio(gpio);
-}
-
-static void cygnus_gpio_free(struct gpio_chip *gc, unsigned offset)
-{
-       struct cygnus_gpio *chip = to_cygnus_gpio(gc);
-       unsigned gpio = gc->base + offset;
-
-       if (!chip->pinmux_is_supported)
-               return;
-
-       pinctrl_free_gpio(gpio);
-}
-
-static int cygnus_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
-{
-       struct cygnus_gpio *chip = to_cygnus_gpio(gc);
-       unsigned long flags;
-
-       spin_lock_irqsave(&chip->lock, flags);
-       cygnus_set_bit(chip, CYGNUS_GPIO_OUT_EN_OFFSET, gpio, false);
-       spin_unlock_irqrestore(&chip->lock, flags);
-
-       dev_dbg(chip->dev, "gpio:%u set input\n", gpio);
-
-       return 0;
-}
-
-static int cygnus_gpio_direction_output(struct gpio_chip *gc, unsigned gpio,
-                                       int val)
-{
-       struct cygnus_gpio *chip = to_cygnus_gpio(gc);
-       unsigned long flags;
-
-       spin_lock_irqsave(&chip->lock, flags);
-       cygnus_set_bit(chip, CYGNUS_GPIO_OUT_EN_OFFSET, gpio, true);
-       cygnus_set_bit(chip, CYGNUS_GPIO_DATA_OUT_OFFSET, gpio, !!(val));
-       spin_unlock_irqrestore(&chip->lock, flags);
-
-       dev_dbg(chip->dev, "gpio:%u set output, value:%d\n", gpio, val);
-
-       return 0;
-}
-
-static void cygnus_gpio_set(struct gpio_chip *gc, unsigned gpio, int val)
-{
-       struct cygnus_gpio *chip = to_cygnus_gpio(gc);
-       unsigned long flags;
-
-       spin_lock_irqsave(&chip->lock, flags);
-       cygnus_set_bit(chip, CYGNUS_GPIO_DATA_OUT_OFFSET, gpio, !!(val));
-       spin_unlock_irqrestore(&chip->lock, flags);
-
-       dev_dbg(chip->dev, "gpio:%u set, value:%d\n", gpio, val);
-}
-
-static int cygnus_gpio_get(struct gpio_chip *gc, unsigned gpio)
-{
-       struct cygnus_gpio *chip = to_cygnus_gpio(gc);
-       unsigned int offset = CYGNUS_GPIO_REG(gpio,
-                                             CYGNUS_GPIO_DATA_IN_OFFSET);
-       unsigned int shift = CYGNUS_GPIO_SHIFT(gpio);
-
-       return !!(readl(chip->base + offset) & BIT(shift));
-}
-
-static int cygnus_get_groups_count(struct pinctrl_dev *pctldev)
-{
-       return 1;
-}
-
-/*
- * Only one group: "gpio_grp", since this local pinctrl device only performs
- * GPIO specific PINCONF configurations
- */
-static const char *cygnus_get_group_name(struct pinctrl_dev *pctldev,
-                                        unsigned selector)
-{
-       return "gpio_grp";
-}
-
-static const struct pinctrl_ops cygnus_pctrl_ops = {
-       .get_groups_count = cygnus_get_groups_count,
-       .get_group_name = cygnus_get_group_name,
-       .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
-       .dt_free_map = pinctrl_utils_dt_free_map,
-};
-
-static int cygnus_gpio_set_pull(struct cygnus_gpio *chip, unsigned gpio,
-                               bool disable, bool pull_up)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&chip->lock, flags);
-
-       if (disable) {
-               cygnus_set_bit(chip, CYGNUS_GPIO_RES_EN_OFFSET, gpio, false);
-       } else {
-               cygnus_set_bit(chip, CYGNUS_GPIO_PAD_RES_OFFSET, gpio,
-                              pull_up);
-               cygnus_set_bit(chip, CYGNUS_GPIO_RES_EN_OFFSET, gpio, true);
-       }
-
-       spin_unlock_irqrestore(&chip->lock, flags);
-
-       dev_dbg(chip->dev, "gpio:%u set pullup:%d\n", gpio, pull_up);
-
-       return 0;
-}
-
-static void cygnus_gpio_get_pull(struct cygnus_gpio *chip, unsigned gpio,
-                                bool *disable, bool *pull_up)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&chip->lock, flags);
-       *disable = !cygnus_get_bit(chip, CYGNUS_GPIO_RES_EN_OFFSET, gpio);
-       *pull_up = cygnus_get_bit(chip, CYGNUS_GPIO_PAD_RES_OFFSET, gpio);
-       spin_unlock_irqrestore(&chip->lock, flags);
-}
-
-static int cygnus_gpio_set_strength(struct cygnus_gpio *chip, unsigned gpio,
-                                   unsigned strength)
-{
-       void __iomem *base;
-       unsigned int i, offset, shift;
-       u32 val;
-       unsigned long flags;
-
-       /* make sure drive strength is supported */
-       if (strength < 2 ||  strength > 16 || (strength % 2))
-               return -ENOTSUPP;
-
-       if (chip->io_ctrl) {
-               base = chip->io_ctrl;
-               offset = CYGNUS_GPIO_DRV0_CTRL_OFFSET;
-       } else {
-               base = chip->base;
-               offset = CYGNUS_GPIO_REG(gpio,
-                                        CYGNUS_GPIO_ASIU_DRV0_CTRL_OFFSET);
-       }
-
-       shift = CYGNUS_GPIO_SHIFT(gpio);
-
-       dev_dbg(chip->dev, "gpio:%u set drive strength:%d mA\n", gpio,
-               strength);
-
-       spin_lock_irqsave(&chip->lock, flags);
-       strength = (strength / 2) - 1;
-       for (i = 0; i < GPIO_DRV_STRENGTH_BITS; i++) {
-               val = readl(base + offset);
-               val &= ~BIT(shift);
-               val |= ((strength >> i) & 0x1) << shift;
-               writel(val, base + offset);
-               offset += 4;
-       }
-       spin_unlock_irqrestore(&chip->lock, flags);
-
-       return 0;
-}
-
-static int cygnus_gpio_get_strength(struct cygnus_gpio *chip, unsigned gpio,
-                                   u16 *strength)
-{
-       void __iomem *base;
-       unsigned int i, offset, shift;
-       u32 val;
-       unsigned long flags;
-
-       if (chip->io_ctrl) {
-               base = chip->io_ctrl;
-               offset = CYGNUS_GPIO_DRV0_CTRL_OFFSET;
-       } else {
-               base = chip->base;
-               offset = CYGNUS_GPIO_REG(gpio,
-                                        CYGNUS_GPIO_ASIU_DRV0_CTRL_OFFSET);
-       }
-
-       shift = CYGNUS_GPIO_SHIFT(gpio);
-
-       spin_lock_irqsave(&chip->lock, flags);
-       *strength = 0;
-       for (i = 0; i < GPIO_DRV_STRENGTH_BITS; i++) {
-               val = readl(base + offset) & BIT(shift);
-               val >>= shift;
-               *strength += (val << i);
-               offset += 4;
-       }
-
-       /* convert to mA */
-       *strength = (*strength + 1) * 2;
-       spin_unlock_irqrestore(&chip->lock, flags);
-
-       return 0;
-}
-
-static int cygnus_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
-                                unsigned long *config)
-{
-       struct cygnus_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
-       enum pin_config_param param = pinconf_to_config_param(*config);
-       unsigned gpio = cygnus_pin_to_gpio(pin);
-       u16 arg;
-       bool disable, pull_up;
-       int ret;
-
-       switch (param) {
-       case PIN_CONFIG_BIAS_DISABLE:
-               cygnus_gpio_get_pull(chip, gpio, &disable, &pull_up);
-               if (disable)
-                       return 0;
-               else
-                       return -EINVAL;
-
-       case PIN_CONFIG_BIAS_PULL_UP:
-               cygnus_gpio_get_pull(chip, gpio, &disable, &pull_up);
-               if (!disable && pull_up)
-                       return 0;
-               else
-                       return -EINVAL;
-
-       case PIN_CONFIG_BIAS_PULL_DOWN:
-               cygnus_gpio_get_pull(chip, gpio, &disable, &pull_up);
-               if (!disable && !pull_up)
-                       return 0;
-               else
-                       return -EINVAL;
-
-       case PIN_CONFIG_DRIVE_STRENGTH:
-               ret = cygnus_gpio_get_strength(chip, gpio, &arg);
-               if (ret)
-                       return ret;
-               else
-                       *config = pinconf_to_config_packed(param, arg);
-
-               return 0;
-
-       default:
-               return -ENOTSUPP;
-       }
-
-       return -ENOTSUPP;
-}
-
-static int cygnus_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
-                                unsigned long *configs, unsigned num_configs)
-{
-       struct cygnus_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
-       enum pin_config_param param;
-       u16 arg;
-       unsigned i, gpio = cygnus_pin_to_gpio(pin);
-       int ret = -ENOTSUPP;
-
-       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:
-                       ret = cygnus_gpio_set_pull(chip, gpio, true, false);
-                       if (ret < 0)
-                               goto out;
-                       break;
-
-               case PIN_CONFIG_BIAS_PULL_UP:
-                       ret = cygnus_gpio_set_pull(chip, gpio, false, true);
-                       if (ret < 0)
-                               goto out;
-                       break;
-
-               case PIN_CONFIG_BIAS_PULL_DOWN:
-                       ret = cygnus_gpio_set_pull(chip, gpio, false, false);
-                       if (ret < 0)
-                               goto out;
-                       break;
-
-               case PIN_CONFIG_DRIVE_STRENGTH:
-                       ret = cygnus_gpio_set_strength(chip, gpio, arg);
-                       if (ret < 0)
-                               goto out;
-                       break;
-
-               default:
-                       dev_err(chip->dev, "invalid configuration\n");
-                       return -ENOTSUPP;
-               }
-       } /* for each config */
-
-out:
-       return ret;
-}
-
-static const struct pinconf_ops cygnus_pconf_ops = {
-       .is_generic = true,
-       .pin_config_get = cygnus_pin_config_get,
-       .pin_config_set = cygnus_pin_config_set,
-};
-
-/*
- * Cygnus GPIO controller supports some PINCONF related configurations such as
- * pull up, pull down, and drive strength, when the pin is configured to GPIO
- *
- * Here a local pinctrl device is created with simple 1-to-1 pin mapping to the
- * local GPIO pins
- */
-static int cygnus_gpio_register_pinconf(struct cygnus_gpio *chip)
-{
-       struct pinctrl_desc *pctldesc = &chip->pctldesc;
-       struct pinctrl_pin_desc *pins;
-       struct gpio_chip *gc = &chip->gc;
-       int i;
-
-       pins = devm_kcalloc(chip->dev, gc->ngpio, sizeof(*pins), GFP_KERNEL);
-       if (!pins)
-               return -ENOMEM;
-
-       for (i = 0; i < gc->ngpio; i++) {
-               pins[i].number = i;
-               pins[i].name = devm_kasprintf(chip->dev, GFP_KERNEL,
-                                             "gpio-%d", i);
-               if (!pins[i].name)
-                       return -ENOMEM;
-       }
-
-       pctldesc->name = dev_name(chip->dev);
-       pctldesc->pctlops = &cygnus_pctrl_ops;
-       pctldesc->pins = pins;
-       pctldesc->npins = gc->ngpio;
-       pctldesc->confops = &cygnus_pconf_ops;
-
-       chip->pctl = pinctrl_register(pctldesc, chip->dev, chip);
-       if (IS_ERR(chip->pctl)) {
-               dev_err(chip->dev, "unable to register pinctrl device\n");
-               return PTR_ERR(chip->pctl);
-       }
-
-       return 0;
-}
-
-static void cygnus_gpio_unregister_pinconf(struct cygnus_gpio *chip)
-{
-       if (chip->pctl)
-               pinctrl_unregister(chip->pctl);
-}
-
-struct cygnus_gpio_data {
-       unsigned num_gpios;
-};
-
-static const struct cygnus_gpio_data cygnus_cmm_gpio_data = {
-       .num_gpios = 24,
-};
-
-static const struct cygnus_gpio_data cygnus_asiu_gpio_data = {
-       .num_gpios = 146,
-};
-
-static const struct cygnus_gpio_data cygnus_crmu_gpio_data = {
-       .num_gpios = 6,
-};
-
-static const struct of_device_id cygnus_gpio_of_match[] = {
-       {
-               .compatible = "brcm,cygnus-ccm-gpio",
-               .data = &cygnus_cmm_gpio_data,
-       },
-       {
-               .compatible = "brcm,cygnus-asiu-gpio",
-               .data = &cygnus_asiu_gpio_data,
-       },
-       {
-               .compatible = "brcm,cygnus-crmu-gpio",
-               .data = &cygnus_crmu_gpio_data,
-       }
-};
-
-static int cygnus_gpio_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct resource *res;
-       struct cygnus_gpio *chip;
-       struct gpio_chip *gc;
-       u32 ngpios;
-       int irq, ret;
-       const struct of_device_id *match;
-       const struct cygnus_gpio_data *gpio_data;
-
-       match = of_match_device(cygnus_gpio_of_match, dev);
-       if (!match)
-               return -ENODEV;
-       gpio_data = match->data;
-       ngpios = gpio_data->num_gpios;
-
-       chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
-       if (!chip)
-               return -ENOMEM;
-
-       chip->dev = dev;
-       platform_set_drvdata(pdev, chip);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       chip->base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(chip->base)) {
-               dev_err(dev, "unable to map I/O memory\n");
-               return PTR_ERR(chip->base);
-       }
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       if (res) {
-               chip->io_ctrl = devm_ioremap_resource(dev, res);
-               if (IS_ERR(chip->io_ctrl)) {
-                       dev_err(dev, "unable to map I/O memory\n");
-                       return PTR_ERR(chip->io_ctrl);
-               }
-       }
-
-       spin_lock_init(&chip->lock);
-
-       gc = &chip->gc;
-       gc->base = -1;
-       gc->ngpio = ngpios;
-       chip->num_banks = (ngpios + NGPIOS_PER_BANK - 1) / NGPIOS_PER_BANK;
-       gc->label = dev_name(dev);
-       gc->dev = dev;
-       gc->of_node = dev->of_node;
-       gc->request = cygnus_gpio_request;
-       gc->free = cygnus_gpio_free;
-       gc->direction_input = cygnus_gpio_direction_input;
-       gc->direction_output = cygnus_gpio_direction_output;
-       gc->set = cygnus_gpio_set;
-       gc->get = cygnus_gpio_get;
-
-       chip->pinmux_is_supported = of_property_read_bool(dev->of_node,
-                                                       "gpio-ranges");
-
-       ret = gpiochip_add(gc);
-       if (ret < 0) {
-               dev_err(dev, "unable to add GPIO chip\n");
-               return ret;
-       }
-
-       ret = cygnus_gpio_register_pinconf(chip);
-       if (ret) {
-               dev_err(dev, "unable to register pinconf\n");
-               goto err_rm_gpiochip;
-       }
-
-       /* optional GPIO interrupt support */
-       irq = platform_get_irq(pdev, 0);
-       if (irq) {
-               ret = gpiochip_irqchip_add(gc, &cygnus_gpio_irq_chip, 0,
-                                          handle_simple_irq, IRQ_TYPE_NONE);
-               if (ret) {
-                       dev_err(dev, "no GPIO irqchip\n");
-                       goto err_unregister_pinconf;
-               }
-
-               gpiochip_set_chained_irqchip(gc, &cygnus_gpio_irq_chip, irq,
-                                            cygnus_gpio_irq_handler);
-       }
-
-       return 0;
-
-err_unregister_pinconf:
-       cygnus_gpio_unregister_pinconf(chip);
-
-err_rm_gpiochip:
-       gpiochip_remove(gc);
-
-       return ret;
-}
-
-static struct platform_driver cygnus_gpio_driver = {
-       .driver = {
-               .name = "cygnus-gpio",
-               .of_match_table = cygnus_gpio_of_match,
-       },
-       .probe = cygnus_gpio_probe,
-};
-
-static int __init cygnus_gpio_init(void)
-{
-       return platform_driver_probe(&cygnus_gpio_driver, cygnus_gpio_probe);
-}
-arch_initcall_sync(cygnus_gpio_init);
diff --git a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
new file mode 100644 (file)
index 0000000..314591a
--- /dev/null
@@ -0,0 +1,758 @@
+/*
+ * Copyright (C) 2014-2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation 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.
+ *
+ * This file contains the Broadcom Iproc GPIO driver that supports 3
+ * GPIO controllers on Iproc including the ASIU GPIO controller, the
+ * chipCommonG GPIO controller, and the always-on GPIO controller. Basic
+ * PINCONF such as bias pull up/down, and drive strength are also supported
+ * in this driver.
+ *
+ * It provides the functionality where pins from the GPIO can be
+ * individually muxed to GPIO function, if individual pad
+ * configuration is supported, through the interaction with respective
+ * SoCs IOMUX controller.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/ioport.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+
+#include "../pinctrl-utils.h"
+
+#define IPROC_GPIO_DATA_IN_OFFSET   0x00
+#define IPROC_GPIO_DATA_OUT_OFFSET  0x04
+#define IPROC_GPIO_OUT_EN_OFFSET    0x08
+#define IPROC_GPIO_INT_TYPE_OFFSET  0x0c
+#define IPROC_GPIO_INT_DE_OFFSET    0x10
+#define IPROC_GPIO_INT_EDGE_OFFSET  0x14
+#define IPROC_GPIO_INT_MSK_OFFSET   0x18
+#define IPROC_GPIO_INT_STAT_OFFSET  0x1c
+#define IPROC_GPIO_INT_MSTAT_OFFSET 0x20
+#define IPROC_GPIO_INT_CLR_OFFSET   0x24
+#define IPROC_GPIO_PAD_RES_OFFSET   0x34
+#define IPROC_GPIO_RES_EN_OFFSET    0x38
+
+/* drive strength control for ASIU GPIO */
+#define IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET 0x58
+
+/* drive strength control for CCM/CRMU (AON) GPIO */
+#define IPROC_GPIO_DRV0_CTRL_OFFSET  0x00
+
+#define GPIO_BANK_SIZE 0x200
+#define NGPIOS_PER_BANK 32
+#define GPIO_BANK(pin) ((pin) / NGPIOS_PER_BANK)
+
+#define IPROC_GPIO_REG(pin, reg) (GPIO_BANK(pin) * GPIO_BANK_SIZE + (reg))
+#define IPROC_GPIO_SHIFT(pin) ((pin) % NGPIOS_PER_BANK)
+
+#define GPIO_DRV_STRENGTH_BIT_SHIFT  20
+#define GPIO_DRV_STRENGTH_BITS       3
+#define GPIO_DRV_STRENGTH_BIT_MASK   ((1 << GPIO_DRV_STRENGTH_BITS) - 1)
+
+/*
+ * Iproc GPIO core
+ *
+ * @dev: pointer to device
+ * @base: I/O register base for Iproc GPIO controller
+ * @io_ctrl: I/O register base for certain type of Iproc GPIO controller that
+ * has the PINCONF support implemented outside of the GPIO block
+ * @lock: lock to protect access to I/O registers
+ * @gc: GPIO chip
+ * @num_banks: number of GPIO banks, each bank supports up to 32 GPIOs
+ * @pinmux_is_supported: flag to indicate this GPIO controller contains pins
+ * that can be individually muxed to GPIO
+ * @pctl: pointer to pinctrl_dev
+ * @pctldesc: pinctrl descriptor
+ */
+struct iproc_gpio {
+       struct device *dev;
+
+       void __iomem *base;
+       void __iomem *io_ctrl;
+
+       spinlock_t lock;
+
+       struct gpio_chip gc;
+       unsigned num_banks;
+
+       bool pinmux_is_supported;
+
+       struct pinctrl_dev *pctl;
+       struct pinctrl_desc pctldesc;
+};
+
+static inline struct iproc_gpio *to_iproc_gpio(struct gpio_chip *gc)
+{
+       return container_of(gc, struct iproc_gpio, gc);
+}
+
+/*
+ * Mapping from PINCONF pins to GPIO pins is 1-to-1
+ */
+static inline unsigned iproc_pin_to_gpio(unsigned pin)
+{
+       return pin;
+}
+
+/**
+ *  iproc_set_bit - set or clear one bit (corresponding to the GPIO pin) in a
+ *  Iproc GPIO register
+ *
+ *  @iproc_gpio: Iproc GPIO device
+ *  @reg: register offset
+ *  @gpio: GPIO pin
+ *  @set: set or clear
+ */
+static inline void iproc_set_bit(struct iproc_gpio *chip, unsigned int reg,
+                                 unsigned gpio, bool set)
+{
+       unsigned int offset = IPROC_GPIO_REG(gpio, reg);
+       unsigned int shift = IPROC_GPIO_SHIFT(gpio);
+       u32 val;
+
+       val = readl(chip->base + offset);
+       if (set)
+               val |= BIT(shift);
+       else
+               val &= ~BIT(shift);
+       writel(val, chip->base + offset);
+}
+
+static inline bool iproc_get_bit(struct iproc_gpio *chip, unsigned int reg,
+                                 unsigned gpio)
+{
+       unsigned int offset = IPROC_GPIO_REG(gpio, reg);
+       unsigned int shift = IPROC_GPIO_SHIFT(gpio);
+
+       return !!(readl(chip->base + offset) & BIT(shift));
+}
+
+static void iproc_gpio_irq_handler(struct irq_desc *desc)
+{
+       struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+       struct iproc_gpio *chip = to_iproc_gpio(gc);
+       struct irq_chip *irq_chip = irq_desc_get_chip(desc);
+       int i, bit;
+
+       chained_irq_enter(irq_chip, desc);
+
+       /* go through the entire GPIO banks and handle all interrupts */
+       for (i = 0; i < chip->num_banks; i++) {
+               unsigned long val = readl(chip->base + (i * GPIO_BANK_SIZE) +
+                                         IPROC_GPIO_INT_MSTAT_OFFSET);
+
+               for_each_set_bit(bit, &val, NGPIOS_PER_BANK) {
+                       unsigned pin = NGPIOS_PER_BANK * i + bit;
+                       int child_irq = irq_find_mapping(gc->irqdomain, pin);
+
+                       /*
+                        * Clear the interrupt before invoking the
+                        * handler, so we do not leave any window
+                        */
+                       writel(BIT(bit), chip->base + (i * GPIO_BANK_SIZE) +
+                              IPROC_GPIO_INT_CLR_OFFSET);
+
+                       generic_handle_irq(child_irq);
+               }
+       }
+
+       chained_irq_exit(irq_chip, desc);
+}
+
+
+static void iproc_gpio_irq_ack(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct iproc_gpio *chip = to_iproc_gpio(gc);
+       unsigned gpio = d->hwirq;
+       unsigned int offset = IPROC_GPIO_REG(gpio,
+                       IPROC_GPIO_INT_CLR_OFFSET);
+       unsigned int shift = IPROC_GPIO_SHIFT(gpio);
+       u32 val = BIT(shift);
+
+       writel(val, chip->base + offset);
+}
+
+/**
+ *  iproc_gpio_irq_set_mask - mask/unmask a GPIO interrupt
+ *
+ *  @d: IRQ chip data
+ *  @unmask: mask/unmask GPIO interrupt
+ */
+static void iproc_gpio_irq_set_mask(struct irq_data *d, bool unmask)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct iproc_gpio *chip = to_iproc_gpio(gc);
+       unsigned gpio = d->hwirq;
+
+       iproc_set_bit(chip, IPROC_GPIO_INT_MSK_OFFSET, gpio, unmask);
+}
+
+static void iproc_gpio_irq_mask(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct iproc_gpio *chip = to_iproc_gpio(gc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->lock, flags);
+       iproc_gpio_irq_set_mask(d, false);
+       spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+static void iproc_gpio_irq_unmask(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct iproc_gpio *chip = to_iproc_gpio(gc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->lock, flags);
+       iproc_gpio_irq_set_mask(d, true);
+       spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+static int iproc_gpio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct iproc_gpio *chip = to_iproc_gpio(gc);
+       unsigned gpio = d->hwirq;
+       bool level_triggered = false;
+       bool dual_edge = false;
+       bool rising_or_high = false;
+       unsigned long flags;
+
+       switch (type & IRQ_TYPE_SENSE_MASK) {
+       case IRQ_TYPE_EDGE_RISING:
+               rising_or_high = true;
+               break;
+
+       case IRQ_TYPE_EDGE_FALLING:
+               break;
+
+       case IRQ_TYPE_EDGE_BOTH:
+               dual_edge = true;
+               break;
+
+       case IRQ_TYPE_LEVEL_HIGH:
+               level_triggered = true;
+               rising_or_high = true;
+               break;
+
+       case IRQ_TYPE_LEVEL_LOW:
+               level_triggered = true;
+               break;
+
+       default:
+               dev_err(chip->dev, "invalid GPIO IRQ type 0x%x\n",
+                       type);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&chip->lock, flags);
+       iproc_set_bit(chip, IPROC_GPIO_INT_TYPE_OFFSET, gpio,
+                      level_triggered);
+       iproc_set_bit(chip, IPROC_GPIO_INT_DE_OFFSET, gpio, dual_edge);
+       iproc_set_bit(chip, IPROC_GPIO_INT_EDGE_OFFSET, gpio,
+                      rising_or_high);
+       spin_unlock_irqrestore(&chip->lock, flags);
+
+       dev_dbg(chip->dev,
+               "gpio:%u level_triggered:%d dual_edge:%d rising_or_high:%d\n",
+               gpio, level_triggered, dual_edge, rising_or_high);
+
+       return 0;
+}
+
+static struct irq_chip iproc_gpio_irq_chip = {
+       .name = "bcm-iproc-gpio",
+       .irq_ack = iproc_gpio_irq_ack,
+       .irq_mask = iproc_gpio_irq_mask,
+       .irq_unmask = iproc_gpio_irq_unmask,
+       .irq_set_type = iproc_gpio_irq_set_type,
+};
+
+/*
+ * Request the Iproc IOMUX pinmux controller to mux individual pins to GPIO
+ */
+static int iproc_gpio_request(struct gpio_chip *gc, unsigned offset)
+{
+       struct iproc_gpio *chip = to_iproc_gpio(gc);
+       unsigned gpio = gc->base + offset;
+
+       /* not all Iproc GPIO pins can be muxed individually */
+       if (!chip->pinmux_is_supported)
+               return 0;
+
+       return pinctrl_request_gpio(gpio);
+}
+
+static void iproc_gpio_free(struct gpio_chip *gc, unsigned offset)
+{
+       struct iproc_gpio *chip = to_iproc_gpio(gc);
+       unsigned gpio = gc->base + offset;
+
+       if (!chip->pinmux_is_supported)
+               return;
+
+       pinctrl_free_gpio(gpio);
+}
+
+static int iproc_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
+{
+       struct iproc_gpio *chip = to_iproc_gpio(gc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->lock, flags);
+       iproc_set_bit(chip, IPROC_GPIO_OUT_EN_OFFSET, gpio, false);
+       spin_unlock_irqrestore(&chip->lock, flags);
+
+       dev_dbg(chip->dev, "gpio:%u set input\n", gpio);
+
+       return 0;
+}
+
+static int iproc_gpio_direction_output(struct gpio_chip *gc, unsigned gpio,
+                                       int val)
+{
+       struct iproc_gpio *chip = to_iproc_gpio(gc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->lock, flags);
+       iproc_set_bit(chip, IPROC_GPIO_OUT_EN_OFFSET, gpio, true);
+       iproc_set_bit(chip, IPROC_GPIO_DATA_OUT_OFFSET, gpio, !!(val));
+       spin_unlock_irqrestore(&chip->lock, flags);
+
+       dev_dbg(chip->dev, "gpio:%u set output, value:%d\n", gpio, val);
+
+       return 0;
+}
+
+static void iproc_gpio_set(struct gpio_chip *gc, unsigned gpio, int val)
+{
+       struct iproc_gpio *chip = to_iproc_gpio(gc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->lock, flags);
+       iproc_set_bit(chip, IPROC_GPIO_DATA_OUT_OFFSET, gpio, !!(val));
+       spin_unlock_irqrestore(&chip->lock, flags);
+
+       dev_dbg(chip->dev, "gpio:%u set, value:%d\n", gpio, val);
+}
+
+static int iproc_gpio_get(struct gpio_chip *gc, unsigned gpio)
+{
+       struct iproc_gpio *chip = to_iproc_gpio(gc);
+       unsigned int offset = IPROC_GPIO_REG(gpio,
+                                             IPROC_GPIO_DATA_IN_OFFSET);
+       unsigned int shift = IPROC_GPIO_SHIFT(gpio);
+
+       return !!(readl(chip->base + offset) & BIT(shift));
+}
+
+static int iproc_get_groups_count(struct pinctrl_dev *pctldev)
+{
+       return 1;
+}
+
+/*
+ * Only one group: "gpio_grp", since this local pinctrl device only performs
+ * GPIO specific PINCONF configurations
+ */
+static const char *iproc_get_group_name(struct pinctrl_dev *pctldev,
+                                        unsigned selector)
+{
+       return "gpio_grp";
+}
+
+static const struct pinctrl_ops iproc_pctrl_ops = {
+       .get_groups_count = iproc_get_groups_count,
+       .get_group_name = iproc_get_group_name,
+       .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
+       .dt_free_map = pinctrl_utils_dt_free_map,
+};
+
+static int iproc_gpio_set_pull(struct iproc_gpio *chip, unsigned gpio,
+                               bool disable, bool pull_up)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->lock, flags);
+
+       if (disable) {
+               iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio, false);
+       } else {
+               iproc_set_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio,
+                              pull_up);
+               iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio, true);
+       }
+
+       spin_unlock_irqrestore(&chip->lock, flags);
+
+       dev_dbg(chip->dev, "gpio:%u set pullup:%d\n", gpio, pull_up);
+
+       return 0;
+}
+
+static void iproc_gpio_get_pull(struct iproc_gpio *chip, unsigned gpio,
+                                bool *disable, bool *pull_up)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->lock, flags);
+       *disable = !iproc_get_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio);
+       *pull_up = iproc_get_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio);
+       spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+static int iproc_gpio_set_strength(struct iproc_gpio *chip, unsigned gpio,
+                                   unsigned strength)
+{
+       void __iomem *base;
+       unsigned int i, offset, shift;
+       u32 val;
+       unsigned long flags;
+
+       /* make sure drive strength is supported */
+       if (strength < 2 ||  strength > 16 || (strength % 2))
+               return -ENOTSUPP;
+
+       if (chip->io_ctrl) {
+               base = chip->io_ctrl;
+               offset = IPROC_GPIO_DRV0_CTRL_OFFSET;
+       } else {
+               base = chip->base;
+               offset = IPROC_GPIO_REG(gpio,
+                                        IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET);
+       }
+
+       shift = IPROC_GPIO_SHIFT(gpio);
+
+       dev_dbg(chip->dev, "gpio:%u set drive strength:%d mA\n", gpio,
+               strength);
+
+       spin_lock_irqsave(&chip->lock, flags);
+       strength = (strength / 2) - 1;
+       for (i = 0; i < GPIO_DRV_STRENGTH_BITS; i++) {
+               val = readl(base + offset);
+               val &= ~BIT(shift);
+               val |= ((strength >> i) & 0x1) << shift;
+               writel(val, base + offset);
+               offset += 4;
+       }
+       spin_unlock_irqrestore(&chip->lock, flags);
+
+       return 0;
+}
+
+static int iproc_gpio_get_strength(struct iproc_gpio *chip, unsigned gpio,
+                                   u16 *strength)
+{
+       void __iomem *base;
+       unsigned int i, offset, shift;
+       u32 val;
+       unsigned long flags;
+
+       if (chip->io_ctrl) {
+               base = chip->io_ctrl;
+               offset = IPROC_GPIO_DRV0_CTRL_OFFSET;
+       } else {
+               base = chip->base;
+               offset = IPROC_GPIO_REG(gpio,
+                                        IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET);
+       }
+
+       shift = IPROC_GPIO_SHIFT(gpio);
+
+       spin_lock_irqsave(&chip->lock, flags);
+       *strength = 0;
+       for (i = 0; i < GPIO_DRV_STRENGTH_BITS; i++) {
+               val = readl(base + offset) & BIT(shift);
+               val >>= shift;
+               *strength += (val << i);
+               offset += 4;
+       }
+
+       /* convert to mA */
+       *strength = (*strength + 1) * 2;
+       spin_unlock_irqrestore(&chip->lock, flags);
+
+       return 0;
+}
+
+static int iproc_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
+                                unsigned long *config)
+{
+       struct iproc_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
+       enum pin_config_param param = pinconf_to_config_param(*config);
+       unsigned gpio = iproc_pin_to_gpio(pin);
+       u16 arg;
+       bool disable, pull_up;
+       int ret;
+
+       switch (param) {
+       case PIN_CONFIG_BIAS_DISABLE:
+               iproc_gpio_get_pull(chip, gpio, &disable, &pull_up);
+               if (disable)
+                       return 0;
+               else
+                       return -EINVAL;
+
+       case PIN_CONFIG_BIAS_PULL_UP:
+               iproc_gpio_get_pull(chip, gpio, &disable, &pull_up);
+               if (!disable && pull_up)
+                       return 0;
+               else
+                       return -EINVAL;
+
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+               iproc_gpio_get_pull(chip, gpio, &disable, &pull_up);
+               if (!disable && !pull_up)
+                       return 0;
+               else
+                       return -EINVAL;
+
+       case PIN_CONFIG_DRIVE_STRENGTH:
+               ret = iproc_gpio_get_strength(chip, gpio, &arg);
+               if (ret)
+                       return ret;
+               *config = pinconf_to_config_packed(param, arg);
+
+               return 0;
+
+       default:
+               return -ENOTSUPP;
+       }
+
+       return -ENOTSUPP;
+}
+
+static int iproc_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
+                                unsigned long *configs, unsigned num_configs)
+{
+       struct iproc_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
+       enum pin_config_param param;
+       u16 arg;
+       unsigned i, gpio = iproc_pin_to_gpio(pin);
+       int ret = -ENOTSUPP;
+
+       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:
+                       ret = iproc_gpio_set_pull(chip, gpio, true, false);
+                       if (ret < 0)
+                               goto out;
+                       break;
+
+               case PIN_CONFIG_BIAS_PULL_UP:
+                       ret = iproc_gpio_set_pull(chip, gpio, false, true);
+                       if (ret < 0)
+                               goto out;
+                       break;
+
+               case PIN_CONFIG_BIAS_PULL_DOWN:
+                       ret = iproc_gpio_set_pull(chip, gpio, false, false);
+                       if (ret < 0)
+                               goto out;
+                       break;
+
+               case PIN_CONFIG_DRIVE_STRENGTH:
+                       ret = iproc_gpio_set_strength(chip, gpio, arg);
+                       if (ret < 0)
+                               goto out;
+                       break;
+
+               default:
+                       dev_err(chip->dev, "invalid configuration\n");
+                       return -ENOTSUPP;
+               }
+       } /* for each config */
+
+out:
+       return ret;
+}
+
+static const struct pinconf_ops iproc_pconf_ops = {
+       .is_generic = true,
+       .pin_config_get = iproc_pin_config_get,
+       .pin_config_set = iproc_pin_config_set,
+};
+
+/*
+ * Iproc GPIO controller supports some PINCONF related configurations such as
+ * pull up, pull down, and drive strength, when the pin is configured to GPIO
+ *
+ * Here a local pinctrl device is created with simple 1-to-1 pin mapping to the
+ * local GPIO pins
+ */
+static int iproc_gpio_register_pinconf(struct iproc_gpio *chip)
+{
+       struct pinctrl_desc *pctldesc = &chip->pctldesc;
+       struct pinctrl_pin_desc *pins;
+       struct gpio_chip *gc = &chip->gc;
+       int i;
+
+       pins = devm_kcalloc(chip->dev, gc->ngpio, sizeof(*pins), GFP_KERNEL);
+       if (!pins)
+               return -ENOMEM;
+
+       for (i = 0; i < gc->ngpio; i++) {
+               pins[i].number = i;
+               pins[i].name = devm_kasprintf(chip->dev, GFP_KERNEL,
+                                             "gpio-%d", i);
+               if (!pins[i].name)
+                       return -ENOMEM;
+       }
+
+       pctldesc->name = dev_name(chip->dev);
+       pctldesc->pctlops = &iproc_pctrl_ops;
+       pctldesc->pins = pins;
+       pctldesc->npins = gc->ngpio;
+       pctldesc->confops = &iproc_pconf_ops;
+
+       chip->pctl = pinctrl_register(pctldesc, chip->dev, chip);
+       if (IS_ERR(chip->pctl)) {
+               dev_err(chip->dev, "unable to register pinctrl device\n");
+               return PTR_ERR(chip->pctl);
+       }
+
+       return 0;
+}
+
+static void iproc_gpio_unregister_pinconf(struct iproc_gpio *chip)
+{
+       pinctrl_unregister(chip->pctl);
+}
+
+static const struct of_device_id iproc_gpio_of_match[] = {
+       { .compatible = "brcm,cygnus-ccm-gpio" },
+       { .compatible = "brcm,cygnus-asiu-gpio" },
+       { .compatible = "brcm,cygnus-crmu-gpio" },
+       { .compatible = "brcm,iproc-gpio" },
+       { }
+};
+
+static int iproc_gpio_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       struct iproc_gpio *chip;
+       struct gpio_chip *gc;
+       u32 ngpios;
+       int irq, ret;
+
+       chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       chip->dev = dev;
+       platform_set_drvdata(pdev, chip);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       chip->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(chip->base)) {
+               dev_err(dev, "unable to map I/O memory\n");
+               return PTR_ERR(chip->base);
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (res) {
+               chip->io_ctrl = devm_ioremap_resource(dev, res);
+               if (IS_ERR(chip->io_ctrl)) {
+                       dev_err(dev, "unable to map I/O memory\n");
+                       return PTR_ERR(chip->io_ctrl);
+               }
+       }
+
+       if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) {
+               dev_err(&pdev->dev, "missing ngpios DT property\n");
+               return -ENODEV;
+       }
+
+       spin_lock_init(&chip->lock);
+
+       gc = &chip->gc;
+       gc->base = -1;
+       gc->ngpio = ngpios;
+       chip->num_banks = (ngpios + NGPIOS_PER_BANK - 1) / NGPIOS_PER_BANK;
+       gc->label = dev_name(dev);
+       gc->dev = dev;
+       gc->of_node = dev->of_node;
+       gc->request = iproc_gpio_request;
+       gc->free = iproc_gpio_free;
+       gc->direction_input = iproc_gpio_direction_input;
+       gc->direction_output = iproc_gpio_direction_output;
+       gc->set = iproc_gpio_set;
+       gc->get = iproc_gpio_get;
+
+       chip->pinmux_is_supported = of_property_read_bool(dev->of_node,
+                                                       "gpio-ranges");
+
+       ret = gpiochip_add(gc);
+       if (ret < 0) {
+               dev_err(dev, "unable to add GPIO chip\n");
+               return ret;
+       }
+
+       ret = iproc_gpio_register_pinconf(chip);
+       if (ret) {
+               dev_err(dev, "unable to register pinconf\n");
+               goto err_rm_gpiochip;
+       }
+
+       /* optional GPIO interrupt support */
+       irq = platform_get_irq(pdev, 0);
+       if (irq) {
+               ret = gpiochip_irqchip_add(gc, &iproc_gpio_irq_chip, 0,
+                                          handle_simple_irq, IRQ_TYPE_NONE);
+               if (ret) {
+                       dev_err(dev, "no GPIO irqchip\n");
+                       goto err_unregister_pinconf;
+               }
+
+               gpiochip_set_chained_irqchip(gc, &iproc_gpio_irq_chip, irq,
+                                            iproc_gpio_irq_handler);
+       }
+
+       return 0;
+
+err_unregister_pinconf:
+       iproc_gpio_unregister_pinconf(chip);
+
+err_rm_gpiochip:
+       gpiochip_remove(gc);
+
+       return ret;
+}
+
+static struct platform_driver iproc_gpio_driver = {
+       .driver = {
+               .name = "iproc-gpio",
+               .of_match_table = iproc_gpio_of_match,
+       },
+       .probe = iproc_gpio_probe,
+};
+
+static int __init iproc_gpio_init(void)
+{
+       return platform_driver_probe(&iproc_gpio_driver, iproc_gpio_probe);
+}
+arch_initcall_sync(iproc_gpio_init);
diff --git a/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c b/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
new file mode 100644 (file)
index 0000000..725c36f
--- /dev/null
@@ -0,0 +1,749 @@
+/*
+ * Copyright (C) 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation 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.
+ *
+ * This file contains the Broadcom Northstar Plus (NSP) GPIO driver that
+ * supports the chipCommonA GPIO controller. Basic PINCONF such as bias,
+ * pull up/down, slew and drive strength are also supported in this driver.
+ *
+ * Pins from the chipCommonA  GPIO can be individually muxed to GPIO function,
+ * through the interaction with the NSP IOMUX controller.
+ */
+
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/slab.h>
+
+#include "../pinctrl-utils.h"
+
+#define NSP_CHIP_A_INT_STATUS          0x00
+#define NSP_CHIP_A_INT_MASK            0x04
+#define NSP_GPIO_DATA_IN               0x40
+#define NSP_GPIO_DATA_OUT              0x44
+#define NSP_GPIO_OUT_EN                        0x48
+#define NSP_GPIO_INT_POLARITY          0x50
+#define NSP_GPIO_INT_MASK              0x54
+#define NSP_GPIO_EVENT                 0x58
+#define NSP_GPIO_EVENT_INT_MASK                0x5c
+#define NSP_GPIO_EVENT_INT_POLARITY    0x64
+#define NSP_CHIP_A_GPIO_INT_BIT                0x01
+
+/* I/O parameters offset for chipcommon A GPIO */
+#define NSP_GPIO_DRV_CTRL              0x00
+#define NSP_GPIO_HYSTERESIS_EN         0x10
+#define NSP_GPIO_SLEW_RATE_EN          0x14
+#define NSP_PULL_UP_EN                 0x18
+#define NSP_PULL_DOWN_EN               0x1c
+#define GPIO_DRV_STRENGTH_BITS         0x03
+
+/*
+ * nsp GPIO core
+ *
+ * @dev: pointer to device
+ * @base: I/O register base for nsp GPIO controller
+ * @io_ctrl: I/O register base for PINCONF support outside the GPIO block
+ * @gc: GPIO chip
+ * @pctl: pointer to pinctrl_dev
+ * @pctldesc: pinctrl descriptor
+ * @irq_domain: pointer to irq domain
+ * @lock: lock to protect access to I/O registers
+ */
+struct nsp_gpio {
+       struct device *dev;
+       void __iomem *base;
+       void __iomem *io_ctrl;
+       struct gpio_chip gc;
+       struct pinctrl_dev *pctl;
+       struct pinctrl_desc pctldesc;
+       struct irq_domain *irq_domain;
+       spinlock_t lock;
+};
+
+enum base_type {
+       REG,
+       IO_CTRL
+};
+
+static inline struct nsp_gpio *to_nsp_gpio(struct gpio_chip *gc)
+{
+       return container_of(gc, struct nsp_gpio, gc);
+}
+
+/*
+ * Mapping from PINCONF pins to GPIO pins is 1-to-1
+ */
+static inline unsigned nsp_pin_to_gpio(unsigned pin)
+{
+       return pin;
+}
+
+/*
+ *  nsp_set_bit - set or clear one bit (corresponding to the GPIO pin) in a
+ *  nsp GPIO register
+ *
+ *  @nsp_gpio: nsp GPIO device
+ *  @base_type: reg base to modify
+ *  @reg: register offset
+ *  @gpio: GPIO pin
+ *  @set: set or clear
+ */
+static inline void nsp_set_bit(struct nsp_gpio *chip, enum base_type address,
+                              unsigned int reg, unsigned gpio, bool set)
+{
+       u32 val;
+       void __iomem *base_address;
+
+       if (address == IO_CTRL)
+               base_address = chip->io_ctrl;
+       else
+               base_address = chip->base;
+
+       val = readl(base_address + reg);
+       if (set)
+               val |= BIT(gpio);
+       else
+               val &= ~BIT(gpio);
+
+       writel(val, base_address + reg);
+}
+
+/*
+ *  nsp_get_bit - get one bit (corresponding to the GPIO pin) in a
+ *  nsp GPIO register
+ */
+static inline bool nsp_get_bit(struct nsp_gpio *chip, enum base_type address,
+                              unsigned int reg, unsigned gpio)
+{
+       if (address == IO_CTRL)
+               return !!(readl(chip->io_ctrl + reg) & BIT(gpio));
+       else
+               return !!(readl(chip->base + reg) & BIT(gpio));
+}
+
+static irqreturn_t nsp_gpio_irq_handler(int irq, void *data)
+{
+       struct nsp_gpio *chip = (struct nsp_gpio *)data;
+       struct gpio_chip gc = chip->gc;
+       int bit;
+       unsigned long int_bits = 0;
+       u32 int_status;
+
+       /* go through the entire GPIOs and handle all interrupts */
+       int_status = readl(chip->base + NSP_CHIP_A_INT_STATUS);
+       if (int_status & NSP_CHIP_A_GPIO_INT_BIT) {
+               unsigned int event, level;
+
+               /* Get level and edge interrupts */
+               event = readl(chip->base + NSP_GPIO_EVENT_INT_MASK) &
+                             readl(chip->base + NSP_GPIO_EVENT);
+               level = readl(chip->base + NSP_GPIO_DATA_IN) ^
+                             readl(chip->base + NSP_GPIO_INT_POLARITY);
+               level &= readl(chip->base + NSP_GPIO_INT_MASK);
+               int_bits = level | event;
+
+               for_each_set_bit(bit, &int_bits, gc.ngpio) {
+                       /*
+                        * Clear the interrupt before invoking the
+                        * handler, so we do not leave any window
+                        */
+                       writel(BIT(bit), chip->base + NSP_GPIO_EVENT);
+                       generic_handle_irq(
+                               irq_linear_revmap(chip->irq_domain, bit));
+               }
+       }
+
+       return  int_bits ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static void nsp_gpio_irq_ack(struct irq_data *d)
+{
+       struct nsp_gpio *chip = irq_data_get_irq_chip_data(d);
+       unsigned gpio = d->hwirq;
+       u32 val = BIT(gpio);
+       u32 trigger_type;
+
+       trigger_type = irq_get_trigger_type(d->irq);
+       if (trigger_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
+               nsp_set_bit(chip, REG, NSP_GPIO_EVENT, gpio, val);
+}
+
+/*
+ *  nsp_gpio_irq_set_mask - mask/unmask a GPIO interrupt
+ *
+ *  @d: IRQ chip data
+ *  @unmask: mask/unmask GPIO interrupt
+ */
+static void nsp_gpio_irq_set_mask(struct irq_data *d, bool unmask)
+{
+       struct nsp_gpio *chip = irq_data_get_irq_chip_data(d);
+       unsigned gpio = d->hwirq;
+       u32 trigger_type;
+
+       trigger_type = irq_get_trigger_type(d->irq);
+       if (trigger_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
+               nsp_set_bit(chip, REG, NSP_GPIO_EVENT_INT_MASK, gpio, unmask);
+       else
+               nsp_set_bit(chip, REG, NSP_GPIO_INT_MASK, gpio, unmask);
+}
+
+static void nsp_gpio_irq_mask(struct irq_data *d)
+{
+       struct nsp_gpio *chip = irq_data_get_irq_chip_data(d);
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->lock, flags);
+       nsp_gpio_irq_set_mask(d, false);
+       spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+static void nsp_gpio_irq_unmask(struct irq_data *d)
+{
+       struct nsp_gpio *chip = irq_data_get_irq_chip_data(d);
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->lock, flags);
+       nsp_gpio_irq_set_mask(d, true);
+       spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+static int nsp_gpio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+       struct nsp_gpio *chip = irq_data_get_irq_chip_data(d);
+       unsigned gpio = d->hwirq;
+       bool level_low;
+       bool falling;
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->lock, flags);
+       falling = nsp_get_bit(chip, REG, NSP_GPIO_EVENT_INT_POLARITY, gpio);
+       level_low = nsp_get_bit(chip, REG, NSP_GPIO_INT_POLARITY, gpio);
+
+       switch (type & IRQ_TYPE_SENSE_MASK) {
+       case IRQ_TYPE_EDGE_RISING:
+               falling = false;
+               break;
+
+       case IRQ_TYPE_EDGE_FALLING:
+               falling = true;
+               break;
+
+       case IRQ_TYPE_LEVEL_HIGH:
+               level_low = false;
+               break;
+
+       case IRQ_TYPE_LEVEL_LOW:
+               level_low = true;
+               break;
+
+       default:
+               dev_err(chip->dev, "invalid GPIO IRQ type 0x%x\n",
+                       type);
+               spin_unlock_irqrestore(&chip->lock, flags);
+               return -EINVAL;
+       }
+
+       nsp_set_bit(chip, REG, NSP_GPIO_EVENT_INT_POLARITY, gpio, falling);
+       nsp_set_bit(chip, REG, NSP_GPIO_INT_POLARITY, gpio, level_low);
+       spin_unlock_irqrestore(&chip->lock, flags);
+
+       dev_dbg(chip->dev, "gpio:%u level_low:%s falling:%s\n", gpio,
+               level_low ? "true" : "false", falling ? "true" : "false");
+       return 0;
+}
+
+static struct irq_chip nsp_gpio_irq_chip = {
+       .name = "gpio-a",
+       .irq_enable = nsp_gpio_irq_unmask,
+       .irq_disable = nsp_gpio_irq_mask,
+       .irq_ack = nsp_gpio_irq_ack,
+       .irq_mask = nsp_gpio_irq_mask,
+       .irq_unmask = nsp_gpio_irq_unmask,
+       .irq_set_type = nsp_gpio_irq_set_type,
+};
+
+/*
+ * Request the nsp IOMUX pinmux controller to mux individual pins to GPIO
+ */
+static int nsp_gpio_request(struct gpio_chip *gc, unsigned offset)
+{
+       unsigned gpio = gc->base + offset;
+
+       return pinctrl_request_gpio(gpio);
+}
+
+static void nsp_gpio_free(struct gpio_chip *gc, unsigned offset)
+{
+       unsigned gpio = gc->base + offset;
+
+       pinctrl_free_gpio(gpio);
+}
+
+static int nsp_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
+{
+       struct nsp_gpio *chip = to_nsp_gpio(gc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->lock, flags);
+       nsp_set_bit(chip, REG, NSP_GPIO_OUT_EN, gpio, false);
+       spin_unlock_irqrestore(&chip->lock, flags);
+
+       dev_dbg(chip->dev, "gpio:%u set input\n", gpio);
+       return 0;
+}
+
+static int nsp_gpio_direction_output(struct gpio_chip *gc, unsigned gpio,
+                                    int val)
+{
+       struct nsp_gpio *chip = to_nsp_gpio(gc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->lock, flags);
+       nsp_set_bit(chip, REG, NSP_GPIO_OUT_EN, gpio, true);
+       nsp_set_bit(chip, REG, NSP_GPIO_DATA_OUT, gpio, !!(val));
+       spin_unlock_irqrestore(&chip->lock, flags);
+
+       dev_dbg(chip->dev, "gpio:%u set output, value:%d\n", gpio, val);
+       return 0;
+}
+
+static void nsp_gpio_set(struct gpio_chip *gc, unsigned gpio, int val)
+{
+       struct nsp_gpio *chip = to_nsp_gpio(gc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->lock, flags);
+       nsp_set_bit(chip, REG, NSP_GPIO_DATA_OUT, gpio, !!(val));
+       spin_unlock_irqrestore(&chip->lock, flags);
+
+       dev_dbg(chip->dev, "gpio:%u set, value:%d\n", gpio, val);
+}
+
+static int nsp_gpio_get(struct gpio_chip *gc, unsigned gpio)
+{
+       struct nsp_gpio *chip = to_nsp_gpio(gc);
+
+       return !!(readl(chip->base + NSP_GPIO_DATA_IN) & BIT(gpio));
+}
+
+static int nsp_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+       struct nsp_gpio *chip = to_nsp_gpio(gc);
+
+       return irq_linear_revmap(chip->irq_domain, offset);
+}
+
+static int nsp_get_groups_count(struct pinctrl_dev *pctldev)
+{
+       return 1;
+}
+
+/*
+ * Only one group: "gpio_grp", since this local pinctrl device only performs
+ * GPIO specific PINCONF configurations
+ */
+static const char *nsp_get_group_name(struct pinctrl_dev *pctldev,
+                                     unsigned selector)
+{
+       return "gpio_grp";
+}
+
+static const struct pinctrl_ops nsp_pctrl_ops = {
+       .get_groups_count = nsp_get_groups_count,
+       .get_group_name = nsp_get_group_name,
+       .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
+       .dt_free_map = pinctrl_utils_dt_free_map,
+};
+
+static int nsp_gpio_set_slew(struct nsp_gpio *chip, unsigned gpio, u16 slew)
+{
+       if (slew)
+               nsp_set_bit(chip, IO_CTRL, NSP_GPIO_SLEW_RATE_EN, gpio, true);
+       else
+               nsp_set_bit(chip, IO_CTRL, NSP_GPIO_SLEW_RATE_EN, gpio, false);
+
+       return 0;
+}
+
+static int nsp_gpio_set_pull(struct nsp_gpio *chip, unsigned gpio,
+                            bool pull_up, bool pull_down)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->lock, flags);
+       nsp_set_bit(chip, IO_CTRL, NSP_PULL_DOWN_EN, gpio, pull_down);
+       nsp_set_bit(chip, IO_CTRL, NSP_PULL_UP_EN, gpio, pull_up);
+       spin_unlock_irqrestore(&chip->lock, flags);
+
+       dev_dbg(chip->dev, "gpio:%u set pullup:%d pulldown: %d\n",
+               gpio, pull_up, pull_down);
+       return 0;
+}
+
+static void nsp_gpio_get_pull(struct nsp_gpio *chip, unsigned gpio,
+                             bool *pull_up, bool *pull_down)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->lock, flags);
+       *pull_up = nsp_get_bit(chip, IO_CTRL, NSP_PULL_UP_EN, gpio);
+       *pull_down = nsp_get_bit(chip, IO_CTRL, NSP_PULL_DOWN_EN, gpio);
+       spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+static int nsp_gpio_set_strength(struct nsp_gpio *chip, unsigned gpio,
+                                u16 strength)
+{
+       u32 offset, shift, i;
+       u32 val;
+       unsigned long flags;
+
+       /* make sure drive strength is supported */
+       if (strength < 2 || strength > 16 || (strength % 2))
+               return -ENOTSUPP;
+
+       shift = gpio;
+       offset = NSP_GPIO_DRV_CTRL;
+       dev_dbg(chip->dev, "gpio:%u set drive strength:%d mA\n", gpio,
+               strength);
+       spin_lock_irqsave(&chip->lock, flags);
+       strength = (strength / 2) - 1;
+       for (i = GPIO_DRV_STRENGTH_BITS; i > 0; i--) {
+               val = readl(chip->io_ctrl + offset);
+               val &= ~BIT(shift);
+               val |= ((strength >> (i-1)) & 0x1) << shift;
+               writel(val, chip->io_ctrl + offset);
+               offset += 4;
+       }
+       spin_unlock_irqrestore(&chip->lock, flags);
+
+       return 0;
+}
+
+static int nsp_gpio_get_strength(struct nsp_gpio *chip, unsigned gpio,
+                                u16 *strength)
+{
+       unsigned int offset, shift;
+       u32 val;
+       unsigned long flags;
+       int i;
+
+       offset = NSP_GPIO_DRV_CTRL;
+       shift = gpio;
+
+       spin_lock_irqsave(&chip->lock, flags);
+       *strength = 0;
+       for (i = (GPIO_DRV_STRENGTH_BITS - 1); i >= 0; i--) {
+               val = readl(chip->io_ctrl + offset) & BIT(shift);
+               val >>= shift;
+               *strength += (val << i);
+               offset += 4;
+       }
+
+       /* convert to mA */
+       *strength = (*strength + 1) * 2;
+       spin_unlock_irqrestore(&chip->lock, flags);
+
+       return 0;
+}
+
+int nsp_pin_config_group_get(struct pinctrl_dev *pctldev, unsigned selector,
+                            unsigned long *config)
+{
+       return 0;
+}
+
+int nsp_pin_config_group_set(struct pinctrl_dev *pctldev, unsigned selector,
+                            unsigned long *configs, unsigned num_configs)
+{
+       return 0;
+}
+
+static int nsp_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
+                             unsigned long *config)
+{
+       struct nsp_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
+       enum pin_config_param param = pinconf_to_config_param(*config);
+       unsigned int gpio;
+       u16 arg = 0;
+       bool pull_up, pull_down;
+       int ret;
+
+       gpio = nsp_pin_to_gpio(pin);
+       switch (param) {
+       case PIN_CONFIG_BIAS_DISABLE:
+               nsp_gpio_get_pull(chip, gpio, &pull_up, &pull_down);
+               if ((pull_up == false) && (pull_down == false))
+                       return 0;
+               else
+                       return -EINVAL;
+
+       case PIN_CONFIG_BIAS_PULL_UP:
+               nsp_gpio_get_pull(chip, gpio, &pull_up, &pull_down);
+               if (pull_up)
+                       return 0;
+               else
+                       return -EINVAL;
+
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+               nsp_gpio_get_pull(chip, gpio, &pull_up, &pull_down);
+               if (pull_down)
+                       return 0;
+               else
+                       return -EINVAL;
+
+       case PIN_CONFIG_DRIVE_STRENGTH:
+               ret = nsp_gpio_get_strength(chip, gpio, &arg);
+               if (ret)
+                       return ret;
+               *config = pinconf_to_config_packed(param, arg);
+               return 0;
+
+       default:
+               return -ENOTSUPP;
+       }
+}
+
+static int nsp_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
+                             unsigned long *configs, unsigned num_configs)
+{
+       struct nsp_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
+       enum pin_config_param param;
+       u16 arg;
+       unsigned int i, gpio;
+       int ret = -ENOTSUPP;
+
+       gpio = nsp_pin_to_gpio(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:
+                       ret = nsp_gpio_set_pull(chip, gpio, false, false);
+                       if (ret < 0)
+                               goto out;
+                       break;
+
+               case PIN_CONFIG_BIAS_PULL_UP:
+                       ret = nsp_gpio_set_pull(chip, gpio, true, false);
+                       if (ret < 0)
+                               goto out;
+                       break;
+
+               case PIN_CONFIG_BIAS_PULL_DOWN:
+                       ret = nsp_gpio_set_pull(chip, gpio, false, true);
+                       if (ret < 0)
+                               goto out;
+                       break;
+
+               case PIN_CONFIG_DRIVE_STRENGTH:
+                       ret = nsp_gpio_set_strength(chip, gpio, arg);
+                       if (ret < 0)
+                               goto out;
+                       break;
+
+               case PIN_CONFIG_SLEW_RATE:
+                       ret = nsp_gpio_set_slew(chip, gpio, arg);
+                       if (ret < 0)
+                               goto out;
+                       break;
+
+               default:
+                       dev_err(chip->dev, "invalid configuration\n");
+                       return -ENOTSUPP;
+               }
+       }
+
+out:
+       return ret;
+}
+
+static const struct pinconf_ops nsp_pconf_ops = {
+       .is_generic = true,
+       .pin_config_get = nsp_pin_config_get,
+       .pin_config_set = nsp_pin_config_set,
+       .pin_config_group_get = nsp_pin_config_group_get,
+       .pin_config_group_set = nsp_pin_config_group_set,
+};
+
+/*
+ * NSP GPIO controller supports some PINCONF related configurations such as
+ * pull up, pull down, slew and drive strength, when the pin is configured
+ * to GPIO.
+ *
+ * Here a local pinctrl device is created with simple 1-to-1 pin mapping to the
+ * local GPIO pins
+ */
+static int nsp_gpio_register_pinconf(struct nsp_gpio *chip)
+{
+       struct pinctrl_desc *pctldesc = &chip->pctldesc;
+       struct pinctrl_pin_desc *pins;
+       struct gpio_chip *gc = &chip->gc;
+       int i;
+
+       pins = devm_kcalloc(chip->dev, gc->ngpio, sizeof(*pins), GFP_KERNEL);
+       if (!pins)
+               return -ENOMEM;
+       for (i = 0; i < gc->ngpio; i++) {
+               pins[i].number = i;
+               pins[i].name = devm_kasprintf(chip->dev, GFP_KERNEL,
+                                             "gpio-%d", i);
+               if (!pins[i].name)
+                       return -ENOMEM;
+       }
+       pctldesc->name = dev_name(chip->dev);
+       pctldesc->pctlops = &nsp_pctrl_ops;
+       pctldesc->pins = pins;
+       pctldesc->npins = gc->ngpio;
+       pctldesc->confops = &nsp_pconf_ops;
+
+       chip->pctl = pinctrl_register(pctldesc, chip->dev, chip);
+       if (IS_ERR(chip->pctl)) {
+               dev_err(chip->dev, "unable to register pinctrl device\n");
+               return PTR_ERR(chip->pctl);
+       }
+
+       return 0;
+}
+
+static const struct of_device_id nsp_gpio_of_match[] = {
+       {.compatible = "brcm,nsp-gpio-a",},
+       {}
+};
+
+static int nsp_gpio_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       struct nsp_gpio *chip;
+       struct gpio_chip *gc;
+       u32 val, count;
+       int irq, ret;
+
+       if (of_property_read_u32(pdev->dev.of_node, "ngpios", &val)) {
+               dev_err(&pdev->dev, "Missing ngpios OF property\n");
+               return -ENODEV;
+       }
+
+       chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       chip->dev = dev;
+       platform_set_drvdata(pdev, chip);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       chip->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(chip->base)) {
+               dev_err(dev, "unable to map I/O memory\n");
+               return PTR_ERR(chip->base);
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       chip->io_ctrl = devm_ioremap_resource(dev, res);
+       if (IS_ERR(chip->io_ctrl)) {
+               dev_err(dev, "unable to map I/O memory\n");
+               return PTR_ERR(chip->io_ctrl);
+       }
+
+       spin_lock_init(&chip->lock);
+       gc = &chip->gc;
+       gc->base = -1;
+       gc->can_sleep = false;
+       gc->ngpio = val;
+       gc->label = dev_name(dev);
+       gc->dev = dev;
+       gc->of_node = dev->of_node;
+       gc->request = nsp_gpio_request;
+       gc->free = nsp_gpio_free;
+       gc->direction_input = nsp_gpio_direction_input;
+       gc->direction_output = nsp_gpio_direction_output;
+       gc->set = nsp_gpio_set;
+       gc->get = nsp_gpio_get;
+       gc->to_irq = nsp_gpio_to_irq;
+
+       /* optional GPIO interrupt support */
+       irq = platform_get_irq(pdev, 0);
+       if (irq > 0) {
+               /* Create irq domain so that each pin can be assigned an IRQ.*/
+               chip->irq_domain = irq_domain_add_linear(gc->of_node, gc->ngpio,
+                                                        &irq_domain_simple_ops,
+                                                        chip);
+               if (!chip->irq_domain) {
+                       dev_err(&pdev->dev, "Couldn't allocate IRQ domain\n");
+                       return -ENXIO;
+               }
+
+               /* Map each gpio to an IRQ and set the handler for gpiolib. */
+               for (count = 0; count < gc->ngpio; count++) {
+                       int irq = irq_create_mapping(chip->irq_domain, count);
+
+                       irq_set_chip_and_handler(irq, &nsp_gpio_irq_chip,
+                                                handle_simple_irq);
+                       irq_set_chip_data(irq, chip);
+               }
+
+               /* Install ISR for this GPIO controller. */
+               ret = devm_request_irq(&pdev->dev, irq, nsp_gpio_irq_handler,
+                                      IRQF_SHARED, "gpio-a", chip);
+               if (ret) {
+                       dev_err(&pdev->dev, "Unable to request IRQ%d: %d\n",
+                               irq, ret);
+                       goto err_rm_gpiochip;
+               }
+
+               val = readl(chip->base + NSP_CHIP_A_INT_MASK);
+               val = val | NSP_CHIP_A_GPIO_INT_BIT;
+               writel(val, (chip->base + NSP_CHIP_A_INT_MASK));
+       }
+
+       ret = gpiochip_add(gc);
+       if (ret < 0) {
+               dev_err(dev, "unable to add GPIO chip\n");
+               return ret;
+       }
+
+       ret = nsp_gpio_register_pinconf(chip);
+       if (ret) {
+               dev_err(dev, "unable to register pinconf\n");
+               goto err_rm_gpiochip;
+       }
+
+       return 0;
+
+err_rm_gpiochip:
+       gpiochip_remove(gc);
+
+       return ret;
+}
+
+static struct platform_driver nsp_gpio_driver = {
+       .driver = {
+               .name = "nsp-gpio-a",
+               .of_match_table = nsp_gpio_of_match,
+       },
+       .probe = nsp_gpio_probe,
+};
+
+static int __init nsp_gpio_init(void)
+{
+       return platform_driver_probe(&nsp_gpio_driver, nsp_gpio_probe);
+}
+arch_initcall_sync(nsp_gpio_init);
index 06f94029ad66715995288cf842b58e14cac573a9..6f641ce2c83093fb1ffed0f88ce055149840b0d3 100644 (file)
@@ -1,4 +1,4 @@
-obj-$(CONFIG_PINCTRL_BERLIN)           += berlin.o
+obj-y                                  += berlin.o
 obj-$(CONFIG_PINCTRL_BERLIN_BG2)       += berlin-bg2.o
 obj-$(CONFIG_PINCTRL_BERLIN_BG2CD)     += berlin-bg2cd.o
 obj-$(CONFIG_PINCTRL_BERLIN_BG2Q)      += berlin-bg2q.o
index b317b0b664eabd7a8be533f0d2e59a377aa4a75c..98e0bebfdf92fcf461dbaa121e60d13d48bd5a8c 100644 (file)
@@ -351,7 +351,7 @@ static int __init mtk_pinctrl_init(void)
        return platform_driver_register(&mtk_pinctrl_driver);
 }
 
-module_init(mtk_pinctrl_init);
+arch_initcall(mtk_pinctrl_init);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("MediaTek MT8127 Pinctrl Driver");
index 404f1178511d97b24adebdd8b95a6c3c4daf8889..1c153b860f36533858194cdb72b5a8fb8a77aef4 100644 (file)
@@ -366,7 +366,7 @@ static int __init mtk_pinctrl_init(void)
        return platform_driver_register(&mtk_pinctrl_driver);
 }
 
-module_init(mtk_pinctrl_init);
+arch_initcall(mtk_pinctrl_init);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("MediaTek Pinctrl Driver");
index ad271840d8652f783a4e8700e25fe8fe8d3d2dc5..a62514eb21290b6edee22aff6b63b19ea1334284 100644 (file)
@@ -394,7 +394,7 @@ static int __init mtk_pinctrl_init(void)
        return platform_driver_register(&mtk_pinctrl_driver);
 }
 
-module_init(mtk_pinctrl_init);
+arch_initcall(mtk_pinctrl_init);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("MediaTek Pinctrl Driver");
index 5c717275a7fa805f370cdd68815e64f8982b142b..e22cbaf9f9cf56696acfe5d5cc628a1f81ee2c80 100644 (file)
@@ -509,6 +509,9 @@ static int mtk_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
 
        err = pinconf_generic_parse_dt_config(node, pctldev, &configs,
                &num_configs);
+       if (err)
+               return err;
+
        if (num_configs)
                has_config = 1;
 
@@ -520,21 +523,23 @@ static int mtk_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
        if (has_config && num_pins >= 1)
                maps_per_pin++;
 
-       if (!num_pins || !maps_per_pin)
-               return -EINVAL;
+       if (!num_pins || !maps_per_pin) {
+               err = -EINVAL;
+               goto exit;
+       }
 
        reserve = num_pins * maps_per_pin;
 
        err = pinctrl_utils_reserve_map(pctldev, map,
                        reserved_maps, num_maps, reserve);
        if (err < 0)
-               goto fail;
+               goto exit;
 
        for (i = 0; i < num_pins; i++) {
                err = of_property_read_u32_index(node, "pinmux",
                                i, &pinfunc);
                if (err)
-                       goto fail;
+                       goto exit;
 
                pin = MTK_GET_PIN_NO(pinfunc);
                func = MTK_GET_PIN_FUNC(pinfunc);
@@ -543,20 +548,21 @@ static int mtk_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
                                func >= ARRAY_SIZE(mtk_gpio_functions)) {
                        dev_err(pctl->dev, "invalid pins value.\n");
                        err = -EINVAL;
-                       goto fail;
+                       goto exit;
                }
 
                grp = mtk_pctrl_find_group_by_pin(pctl, pin);
                if (!grp) {
                        dev_err(pctl->dev, "unable to match pin %d to group\n",
                                        pin);
-                       return -EINVAL;
+                       err = -EINVAL;
+                       goto exit;
                }
 
                err = mtk_pctrl_dt_node_to_map_func(pctl, pin, func, grp, map,
                                reserved_maps, num_maps);
                if (err < 0)
-                       goto fail;
+                       goto exit;
 
                if (has_config) {
                        err = pinctrl_utils_add_map_configs(pctldev, map,
@@ -564,13 +570,14 @@ static int mtk_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
                                        configs, num_configs,
                                        PIN_MAP_TYPE_CONFIGS_GROUP);
                        if (err < 0)
-                               goto fail;
+                               goto exit;
                }
        }
 
-       return 0;
+       err = 0;
 
-fail:
+exit:
+       kfree(configs);
        return err;
 }
 
@@ -591,6 +598,7 @@ static int mtk_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
                                &reserved_maps, num_maps);
                if (ret < 0) {
                        pinctrl_utils_dt_free_map(pctldev, *map, *num_maps);
+                       of_node_put(np);
                        return ret;
                }
        }
index 554d8af14eebbb8d26e83ff64f7c1d01cebd0b91..18270cd5ea43650421e11593452d0c9c4c5baf08 100644 (file)
@@ -1,4 +1,4 @@
-obj-$(CONFIG_PINCTRL_MVEBU)    += pinctrl-mvebu.o
+obj-y                          += pinctrl-mvebu.o
 obj-$(CONFIG_PINCTRL_DOVE)     += pinctrl-dove.o
 obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o
 obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o
index 77d2221d379da41c95c195eb77ccbe38d9088191..e4d473811bb366c84cf5ab180529c36411aacd6d 100644 (file)
@@ -663,28 +663,20 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
        /* assign mpp modes to groups */
        for (n = 0; n < soc->nmodes; n++) {
                struct mvebu_mpp_mode *mode = &soc->modes[n];
-               struct mvebu_pinctrl_group *grp =
-                       mvebu_pinctrl_find_group_by_pid(pctl, mode->pid);
+               struct mvebu_mpp_ctrl_setting *set = &mode->settings[0];
+               struct mvebu_pinctrl_group *grp;
                unsigned num_settings;
 
-               if (!grp) {
-                       dev_warn(&pdev->dev, "unknown pinctrl group %d\n",
-                               mode->pid);
-                       continue;
-               }
-
-               for (num_settings = 0; ;) {
-                       struct mvebu_mpp_ctrl_setting *set =
-                               &mode->settings[num_settings];
-
+               for (num_settings = 0; ; set++) {
                        if (!set->name)
                                break;
-                       num_settings++;
 
                        /* skip unsupported settings for this variant */
                        if (pctl->variant && !(pctl->variant & set->variant))
                                continue;
 
+                       num_settings++;
+
                        /* find gpio/gpo/gpi settings */
                        if (strcmp(set->name, "gpio") == 0)
                                set->flags = MVEBU_SETTING_GPI |
@@ -695,6 +687,17 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
                                set->flags = MVEBU_SETTING_GPI;
                }
 
+               /* skip modes with no settings for this variant */
+               if (!num_settings)
+                       continue;
+
+               grp = mvebu_pinctrl_find_group_by_pid(pctl, mode->pid);
+               if (!grp) {
+                       dev_warn(&pdev->dev, "unknown pinctrl group %d\n",
+                               mode->pid);
+                       continue;
+               }
+
                grp->settings = mode->settings;
                grp->num_settings = num_settings;
        }
index 099a3442ff4214b2ab55497a93d49774e89d1c65..79e6159712c2abd43a749cf321eb721b98aebeab 100644 (file)
@@ -220,6 +220,7 @@ static void parse_dt_cfg(struct device_node *np,
  * parse the config properties into generic pinconfig values.
  * @np: node containing the pinconfig properties
  * @configs: array with nconfigs entries containing the generic pinconf values
+ *           must be freed when no longer necessary.
  * @nconfigs: umber of configurations
  */
 int pinconf_generic_parse_dt_config(struct device_node *np,
index fd342dffe4dc766cefe93a29b3408476753b7316..8e9e8eab59ba75c6c7643b41453d81d62e1d7187 100644 (file)
@@ -1102,32 +1102,24 @@ static struct platform_driver adi_gpio_driver = {
        },
 };
 
+static struct platform_driver * const drivers[] = {
+       &adi_pinctrl_driver,
+       &adi_gpio_pint_driver,
+       &adi_gpio_driver,
+};
+
 static int __init adi_pinctrl_setup(void)
 {
        int ret;
 
-       ret = platform_driver_register(&adi_pinctrl_driver);
+       ret = platform_register_drivers(drivers, ARRAY_SIZE(drivers));
        if (ret)
                return ret;
 
-       ret = platform_driver_register(&adi_gpio_pint_driver);
-       if (ret)
-               goto pint_error;
-
-       ret = platform_driver_register(&adi_gpio_driver);
-       if (ret)
-               goto gpio_error;
-
 #ifdef CONFIG_PM
        register_syscore_ops(&gpio_pm_syscore_ops);
 #endif
-       return ret;
-gpio_error:
-       platform_driver_unregister(&adi_gpio_pint_driver);
-pint_error:
-       platform_driver_unregister(&adi_pinctrl_driver);
-
-       return ret;
+       return 0;
 }
 arch_initcall(adi_pinctrl_setup);
 
index 33edd07d9149b6b2c895d4c9708dc0f95aa41700..d5bdcebc6aa695b2036da1c69e3c548673cccca2 100644 (file)
@@ -500,7 +500,8 @@ static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
        if (!num_pins) {
                dev_err(pctldev->dev, "no pins found in node %s\n",
                        of_node_full_name(np));
-               return -EINVAL;
+               ret = -EINVAL;
+               goto exit;
        }
 
        /*
@@ -514,19 +515,19 @@ static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
        ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps,
                                        reserve);
        if (ret < 0)
-               return ret;
+               goto exit;
 
        for (i = 0; i < num_pins; i++) {
                const char *group, *func;
 
                ret = of_property_read_u32_index(np, "pinmux", i, &pinfunc);
                if (ret)
-                       return ret;
+                       goto exit;
 
                ret = atmel_pctl_xlate_pinfunc(pctldev, np, pinfunc, &group,
                                               &func);
                if (ret)
-                       return ret;
+                       goto exit;
 
                pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, num_maps,
                                          group, func);
@@ -537,11 +538,13 @@ static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
                                        configs, num_configs,
                                        PIN_MAP_TYPE_CONFIGS_GROUP);
                        if (ret < 0)
-                               return ret;
+                               goto exit;
                }
        }
 
-       return 0;
+exit:
+       kfree(configs);
+       return ret;
 }
 
 static int atmel_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
@@ -1000,7 +1003,7 @@ static int atmel_pinctrl_probe(struct platform_device *pdev)
                atmel_pioctrl->irqs[i] = res->start;
                irq_set_chained_handler(res->start, atmel_gpio_irq_handler);
                irq_set_handler_data(res->start, atmel_pioctrl);
-               dev_dbg(dev, "bank %i: hwirq=%u\n", i, res->start);
+               dev_dbg(dev, "bank %i: irq=%pr\n", i, res);
        }
 
        atmel_pioctrl->irq_domain = irq_domain_add_linear(dev->of_node,
index 0d2fc0cff35ee6216ef5e62a77376e63cb2675e7..47b625b1b789fb0c10c08a940fd0766bcf93358a 100644 (file)
@@ -1828,20 +1828,20 @@ static struct platform_driver at91_pinctrl_driver = {
        .remove = at91_pinctrl_remove,
 };
 
+static struct platform_driver * const drivers[] = {
+       &at91_gpio_driver,
+       &at91_pinctrl_driver,
+};
+
 static int __init at91_pinctrl_init(void)
 {
-       int ret;
-
-       ret = platform_driver_register(&at91_gpio_driver);
-       if (ret)
-               return ret;
-       return platform_driver_register(&at91_pinctrl_driver);
+       return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
 }
 arch_initcall(at91_pinctrl_init);
 
 static void __exit at91_pinctrl_exit(void)
 {
-       platform_driver_unregister(&at91_pinctrl_driver);
+       platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
 }
 
 module_exit(at91_pinctrl_exit);
index eb89ba045228253d66e01b4a736c9e63a54bbf7c..e137d139e49467071867305d4b1ec4238848fe19 100644 (file)
@@ -162,6 +162,14 @@ enum ltq_pin {
        GPIO53,
        GPIO54,
        GPIO55,
+       GPIO56,
+       GPIO57,
+       GPIO58,
+       GPIO59,
+       GPIO60, /* 60 */
+       GPIO61,
+       GPIO62,
+       GPIO63,
 
        GPIO64,
        GPIO65,
index a0651128e23acc68fbe139dc10da3e859da2b9a1..91288265e856f60577f9c81de7619fcb1c8359ba 100644 (file)
@@ -614,6 +614,40 @@ static void rk3288_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
        }
 }
 
+#define RK3228_PULL_OFFSET             0x100
+
+static void rk3228_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
+                                   int pin_num, struct regmap **regmap,
+                                   int *reg, u8 *bit)
+{
+       struct rockchip_pinctrl *info = bank->drvdata;
+
+       *regmap = info->regmap_base;
+       *reg = RK3228_PULL_OFFSET;
+       *reg += bank->bank_num * RK3188_PULL_BANK_STRIDE;
+       *reg += ((pin_num / RK3188_PULL_PINS_PER_REG) * 4);
+
+       *bit = (pin_num % RK3188_PULL_PINS_PER_REG);
+       *bit *= RK3188_PULL_BITS_PER_PIN;
+}
+
+#define RK3228_DRV_GRF_OFFSET          0x200
+
+static void rk3228_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
+                                   int pin_num, struct regmap **regmap,
+                                   int *reg, u8 *bit)
+{
+       struct rockchip_pinctrl *info = bank->drvdata;
+
+       *regmap = info->regmap_base;
+       *reg = RK3228_DRV_GRF_OFFSET;
+       *reg += bank->bank_num * RK3288_DRV_BANK_STRIDE;
+       *reg += ((pin_num / RK3288_DRV_PINS_PER_REG) * 4);
+
+       *bit = (pin_num % RK3288_DRV_PINS_PER_REG);
+       *bit *= RK3288_DRV_BITS_PER_PIN;
+}
+
 #define RK3368_PULL_GRF_OFFSET         0x100
 #define RK3368_PULL_PMU_OFFSET         0x10
 
@@ -1258,8 +1292,10 @@ static int rockchip_pinctrl_parse_functions(struct device_node *np,
                func->groups[i] = child->name;
                grp = &info->groups[grp_index++];
                ret = rockchip_pinctrl_parse_groups(child, grp, info, i++);
-               if (ret)
+               if (ret) {
+                       of_node_put(child);
                        return ret;
+               }
        }
 
        return 0;
@@ -1304,6 +1340,7 @@ static int rockchip_pinctrl_parse_dt(struct platform_device *pdev,
                ret = rockchip_pinctrl_parse_functions(child, info, i++);
                if (ret) {
                        dev_err(&pdev->dev, "failed to parse function\n");
+                       of_node_put(child);
                        return ret;
                }
        }
@@ -2143,6 +2180,23 @@ static struct rockchip_pin_ctrl rk3188_pin_ctrl = {
                .pull_calc_reg          = rk3188_calc_pull_reg_and_bit,
 };
 
+static struct rockchip_pin_bank rk3228_pin_banks[] = {
+       PIN_BANK(0, 32, "gpio0"),
+       PIN_BANK(1, 32, "gpio1"),
+       PIN_BANK(2, 32, "gpio2"),
+       PIN_BANK(3, 32, "gpio3"),
+};
+
+static struct rockchip_pin_ctrl rk3228_pin_ctrl = {
+               .pin_banks              = rk3228_pin_banks,
+               .nr_banks               = ARRAY_SIZE(rk3228_pin_banks),
+               .label                  = "RK3228-GPIO",
+               .type                   = RK3288,
+               .grf_mux_offset         = 0x0,
+               .pull_calc_reg          = rk3228_calc_pull_reg_and_bit,
+               .drv_calc_reg           = rk3228_calc_drv_reg_and_bit,
+};
+
 static struct rockchip_pin_bank rk3288_pin_banks[] = {
        PIN_BANK_IOMUX_FLAGS(0, 24, "gpio0", IOMUX_SOURCE_PMU,
                                             IOMUX_SOURCE_PMU,
@@ -2220,6 +2274,8 @@ static const struct of_device_id rockchip_pinctrl_dt_match[] = {
                .data = (void *)&rk3066b_pin_ctrl },
        { .compatible = "rockchip,rk3188-pinctrl",
                .data = (void *)&rk3188_pin_ctrl },
+       { .compatible = "rockchip,rk3228-pinctrl",
+               .data = (void *)&rk3228_pin_ctrl },
        { .compatible = "rockchip,rk3288-pinctrl",
                .data = (void *)&rk3288_pin_ctrl },
        { .compatible = "rockchip,rk3368-pinctrl",
index ef04b962c3d51992ba41080b893829d2d4102b56..d24e5f1d15252f29f586badeb94ef620a7d33a73 100644 (file)
@@ -1484,10 +1484,7 @@ static void pcs_irq_free(struct pcs_device *pcs)
 static void pcs_free_resources(struct pcs_device *pcs)
 {
        pcs_irq_free(pcs);
-
-       if (pcs->pctl)
-               pinctrl_unregister(pcs->pctl);
-
+       pinctrl_unregister(pcs->pctl);
        pcs_free_funcs(pcs);
        pcs_free_pingroups(pcs);
 }
index 84a43e61295267aa5dfe07fc155095ac5ef390d3..bd3aa5a4fd6d296da5a592b781c4152844800eca 100644 (file)
@@ -253,8 +253,10 @@ static int tegra_xusb_padctl_dt_node_to_map(struct pinctrl_dev *pinctrl,
                err = tegra_xusb_padctl_parse_subnode(padctl, np, maps,
                                                      &reserved_maps,
                                                      num_maps);
-               if (err < 0)
+               if (err < 0) {
+                       of_node_put(np);
                        return err;
+               }
        }
 
        return 0;
index 0fd7fd2b0f72c23bd606ab0109e25c166dcdf0ee..9da4da219a0778af3f3ab6ec8b4336554fa15b66 100644 (file)
@@ -217,6 +217,7 @@ static int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
                if (ret < 0) {
                        pinctrl_utils_dt_free_map(pctldev, *map,
                                *num_maps);
+                       of_node_put(np);
                        return ret;
                }
        }
index ae724bdab3d324cbf9018e8f2bdaf6fc44103f02..7db74699fda453ced2f3064546250bfbd9436095 100644 (file)
@@ -7,6 +7,7 @@
  *  publishhed by the Free Software Foundation.
  *
  *  Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ *  Copyright (C) 2015 Martin Schiller <mschiller@tdt.de>
  */
 
 #include <linux/err.h>
@@ -24,7 +25,7 @@
 
 #include <lantiq_soc.h>
 
-/* we have 3 1/2 banks of 16 bit each */
+/* we have up to 4 banks of 16 bit each */
 #define PINS                   16
 #define PORT3                  3
 #define PORT(x)                        (x / PINS)
@@ -35,7 +36,7 @@
 #define MUX_ALT1       0x2
 
 /*
- * each bank has this offset apart from the 1/2 bank that is mixed into the
+ * each bank has this offset apart from the 4th bank that is mixed into the
  * other 3 ranges
  */
 #define REG_OFF                        0x30
@@ -51,7 +52,7 @@
 #define GPIO_PUDSEL(p)         (GPIO_BASE(p) + 0x1c)
 #define GPIO_PUDEN(p)          (GPIO_BASE(p) + 0x20)
 
-/* the 1/2 port needs special offsets for some registers */
+/* the 4th port needs special offsets for some registers */
 #define GPIO3_OD               (GPIO_BASE(0) + 0x24)
 #define GPIO3_PUDSEL           (GPIO_BASE(0) + 0x28)
 #define GPIO3_PUDEN            (GPIO_BASE(0) + 0x2C)
 #define FUNC_MUX(f, m)         \
        { .func = f, .mux = XWAY_MUX_##m, }
 
-#define XWAY_MAX_PIN           32
-#define XR9_MAX_PIN            56
-
 enum xway_mux {
        XWAY_MUX_GPIO = 0,
        XWAY_MUX_SPI,
        XWAY_MUX_ASC,
+       XWAY_MUX_USIF,
        XWAY_MUX_PCI,
+       XWAY_MUX_CBUS,
        XWAY_MUX_CGU,
        XWAY_MUX_EBU,
+       XWAY_MUX_EBU2,
        XWAY_MUX_JTAG,
+       XWAY_MUX_MCD,
        XWAY_MUX_EXIN,
        XWAY_MUX_TDM,
        XWAY_MUX_STP,
@@ -103,9 +105,15 @@ enum xway_mux {
        XWAY_MUX_DFE,
        XWAY_MUX_SDIO,
        XWAY_MUX_GPHY,
+       XWAY_MUX_SSI,
+       XWAY_MUX_WIFI,
        XWAY_MUX_NONE = 0xffff,
 };
 
+/* ---------  DEPRECATED: xr9 related code --------- */
+/* ----------  use xrx100/xrx200 instead  ---------- */
+#define XR9_MAX_PIN            56
+
 static const struct ltq_mfp_pin xway_mfp[] = {
        /*       pin    f0      f1      f2      f3   */
        MFP_XWAY(GPIO0, GPIO,   EXIN,   NONE,   TDM),
@@ -113,7 +121,7 @@ static const struct ltq_mfp_pin xway_mfp[] = {
        MFP_XWAY(GPIO2, GPIO,   CGU,    EXIN,   GPHY),
        MFP_XWAY(GPIO3, GPIO,   CGU,    NONE,   PCI),
        MFP_XWAY(GPIO4, GPIO,   STP,    NONE,   ASC),
-       MFP_XWAY(GPIO5, GPIO,   STP,    NONE,   GPHY),
+       MFP_XWAY(GPIO5, GPIO,   STP,    GPHY,   NONE),
        MFP_XWAY(GPIO6, GPIO,   STP,    GPT,    ASC),
        MFP_XWAY(GPIO7, GPIO,   CGU,    PCI,    GPHY),
        MFP_XWAY(GPIO8, GPIO,   CGU,    NMI,    NONE),
@@ -152,10 +160,10 @@ static const struct ltq_mfp_pin xway_mfp[] = {
        MFP_XWAY(GPIO41, GPIO,  NONE,   NONE,   NONE),
        MFP_XWAY(GPIO42, GPIO,  MDIO,   NONE,   NONE),
        MFP_XWAY(GPIO43, GPIO,  MDIO,   NONE,   NONE),
-       MFP_XWAY(GPIO44, GPIO,  NONE,   GPHY,   SIN),
+       MFP_XWAY(GPIO44, GPIO,  MII,    SIN,    GPHY),
        MFP_XWAY(GPIO45, GPIO,  NONE,   GPHY,   SIN),
        MFP_XWAY(GPIO46, GPIO,  NONE,   NONE,   EXIN),
-       MFP_XWAY(GPIO47, GPIO,  NONE,   GPHY,   SIN),
+       MFP_XWAY(GPIO47, GPIO,  MII,    GPHY,   SIN),
        MFP_XWAY(GPIO48, GPIO,  EBU,    NONE,   NONE),
        MFP_XWAY(GPIO49, GPIO,  EBU,    NONE,   NONE),
        MFP_XWAY(GPIO50, GPIO,  NONE,   NONE,   NONE),
@@ -166,42 +174,6 @@ static const struct ltq_mfp_pin xway_mfp[] = {
        MFP_XWAY(GPIO55, GPIO,  NONE,   NONE,   NONE),
 };
 
-static const struct ltq_mfp_pin ase_mfp[] = {
-       /*       pin    f0      f1      f2      f3   */
-       MFP_XWAY(GPIO0, GPIO,   EXIN,   MII,    TDM),
-       MFP_XWAY(GPIO1, GPIO,   STP,    DFE,    EBU),
-       MFP_XWAY(GPIO2, GPIO,   STP,    DFE,    EPHY),
-       MFP_XWAY(GPIO3, GPIO,   STP,    EPHY,   EBU),
-       MFP_XWAY(GPIO4, GPIO,   GPT,    EPHY,   MII),
-       MFP_XWAY(GPIO5, GPIO,   MII,    ASC,    GPT),
-       MFP_XWAY(GPIO6, GPIO,   MII,    ASC,    EXIN),
-       MFP_XWAY(GPIO7, GPIO,   SPI,    MII,    JTAG),
-       MFP_XWAY(GPIO8, GPIO,   SPI,    MII,    JTAG),
-       MFP_XWAY(GPIO9, GPIO,   SPI,    MII,    JTAG),
-       MFP_XWAY(GPIO10, GPIO,  SPI,    MII,    JTAG),
-       MFP_XWAY(GPIO11, GPIO,  EBU,    CGU,    JTAG),
-       MFP_XWAY(GPIO12, GPIO,  EBU,    MII,    SDIO),
-       MFP_XWAY(GPIO13, GPIO,  EBU,    MII,    CGU),
-       MFP_XWAY(GPIO14, GPIO,  EBU,    SPI,    CGU),
-       MFP_XWAY(GPIO15, GPIO,  EBU,    SPI,    SDIO),
-       MFP_XWAY(GPIO16, GPIO,  NONE,   NONE,   NONE),
-       MFP_XWAY(GPIO17, GPIO,  NONE,   NONE,   NONE),
-       MFP_XWAY(GPIO18, GPIO,  NONE,   NONE,   NONE),
-       MFP_XWAY(GPIO19, GPIO,  EBU,    MII,    SDIO),
-       MFP_XWAY(GPIO20, GPIO,  EBU,    MII,    SDIO),
-       MFP_XWAY(GPIO21, GPIO,  EBU,    MII,    SDIO),
-       MFP_XWAY(GPIO22, GPIO,  EBU,    MII,    CGU),
-       MFP_XWAY(GPIO23, GPIO,  EBU,    MII,    CGU),
-       MFP_XWAY(GPIO24, GPIO,  EBU,    NONE,   MII),
-       MFP_XWAY(GPIO25, GPIO,  EBU,    MII,    GPT),
-       MFP_XWAY(GPIO26, GPIO,  EBU,    MII,    SDIO),
-       MFP_XWAY(GPIO27, GPIO,  EBU,    NONE,   MII),
-       MFP_XWAY(GPIO28, GPIO,  MII,    EBU,    SDIO),
-       MFP_XWAY(GPIO29, GPIO,  EBU,    MII,    EXIN),
-       MFP_XWAY(GPIO30, GPIO,  NONE,   NONE,   NONE),
-       MFP_XWAY(GPIO31, GPIO,  NONE,   NONE,   NONE),
-};
-
 static const unsigned pins_jtag[] = {GPIO15, GPIO16, GPIO17, GPIO19, GPIO35};
 static const unsigned pins_asc0[] = {GPIO11, GPIO12};
 static const unsigned pins_asc0_cts_rts[] = {GPIO9, GPIO10};
@@ -231,6 +203,8 @@ static const unsigned pins_nand_cle[] = {GPIO24};
 static const unsigned pins_nand_rdy[] = {GPIO48};
 static const unsigned pins_nand_rd[] = {GPIO49};
 
+static const unsigned xway_exin_pin_map[] = {GPIO0, GPIO1, GPIO2, GPIO39, GPIO46, GPIO9};
+
 static const unsigned pins_exin0[] = {GPIO0};
 static const unsigned pins_exin1[] = {GPIO1};
 static const unsigned pins_exin2[] = {GPIO2};
@@ -240,7 +214,7 @@ static const unsigned pins_exin5[] = {GPIO9};
 
 static const unsigned pins_spi[] = {GPIO16, GPIO17, GPIO18};
 static const unsigned pins_spi_cs1[] = {GPIO15};
-static const unsigned pins_spi_cs2[] = {GPIO21};
+static const unsigned pins_spi_cs2[] = {GPIO22};
 static const unsigned pins_spi_cs3[] = {GPIO13};
 static const unsigned pins_spi_cs4[] = {GPIO10};
 static const unsigned pins_spi_cs5[] = {GPIO9};
@@ -264,25 +238,6 @@ static const unsigned pins_pci_req2[] = {GPIO31};
 static const unsigned pins_pci_req3[] = {GPIO3};
 static const unsigned pins_pci_req4[] = {GPIO37};
 
-static const unsigned ase_pins_jtag[] = {GPIO7, GPIO8, GPIO9, GPIO10, GPIO11};
-static const unsigned ase_pins_asc[] = {GPIO5, GPIO6};
-static const unsigned ase_pins_stp[] = {GPIO1, GPIO2, GPIO3};
-static const unsigned ase_pins_ephy[] = {GPIO2, GPIO3, GPIO4};
-static const unsigned ase_pins_dfe[] = {GPIO1, GPIO2};
-
-static const unsigned ase_pins_spi[] = {GPIO8, GPIO9, GPIO10};
-static const unsigned ase_pins_spi_cs1[] = {GPIO7};
-static const unsigned ase_pins_spi_cs2[] = {GPIO15};
-static const unsigned ase_pins_spi_cs3[] = {GPIO14};
-
-static const unsigned ase_pins_exin0[] = {GPIO6};
-static const unsigned ase_pins_exin1[] = {GPIO29};
-static const unsigned ase_pins_exin2[] = {GPIO0};
-
-static const unsigned ase_pins_gpt1[] = {GPIO5};
-static const unsigned ase_pins_gpt2[] = {GPIO4};
-static const unsigned ase_pins_gpt3[] = {GPIO25};
-
 static const struct ltq_pin_group xway_grps[] = {
        GRP_MUX("exin0", EXIN, pins_exin0),
        GRP_MUX("exin1", EXIN, pins_exin1),
@@ -338,24 +293,6 @@ static const struct ltq_pin_group xway_grps[] = {
        GRP_MUX("gphy1 led2", GPHY, pins_gphy1_led2),
 };
 
-static const struct ltq_pin_group ase_grps[] = {
-       GRP_MUX("exin0", EXIN, ase_pins_exin0),
-       GRP_MUX("exin1", EXIN, ase_pins_exin1),
-       GRP_MUX("exin2", EXIN, ase_pins_exin2),
-       GRP_MUX("jtag", JTAG, ase_pins_jtag),
-       GRP_MUX("stp", STP, ase_pins_stp),
-       GRP_MUX("asc", ASC, ase_pins_asc),
-       GRP_MUX("gpt1", GPT, ase_pins_gpt1),
-       GRP_MUX("gpt2", GPT, ase_pins_gpt2),
-       GRP_MUX("gpt3", GPT, ase_pins_gpt3),
-       GRP_MUX("ephy", EPHY, ase_pins_ephy),
-       GRP_MUX("dfe", DFE, ase_pins_dfe),
-       GRP_MUX("spi", SPI, ase_pins_spi),
-       GRP_MUX("spi_cs1", SPI, ase_pins_spi_cs1),
-       GRP_MUX("spi_cs2", SPI, ase_pins_spi_cs2),
-       GRP_MUX("spi_cs3", SPI, ase_pins_spi_cs3),
-};
-
 static const char * const xway_pci_grps[] = {"gnt1", "gnt2",
                                                "gnt3", "req1",
                                                "req2", "req3"};
@@ -395,30 +332,6 @@ static const char * const xrx_pci_grps[] = {"gnt1", "gnt2",
                                                "req1", "req2",
                                                "req3", "req4"};
 
-/* ase */
-static const char * const ase_exin_grps[] = {"exin0", "exin1", "exin2"};
-static const char * const ase_gpt_grps[] = {"gpt1", "gpt2", "gpt3"};
-static const char * const ase_dfe_grps[] = {"dfe"};
-static const char * const ase_ephy_grps[] = {"ephy"};
-static const char * const ase_asc_grps[] = {"asc"};
-static const char * const ase_jtag_grps[] = {"jtag"};
-static const char * const ase_stp_grps[] = {"stp"};
-static const char * const ase_spi_grps[] = {"spi", "spi_cs1",
-                                               "spi_cs2", "spi_cs3"};
-
-static const struct ltq_pmx_func danube_funcs[] = {
-       {"spi",         ARRAY_AND_SIZE(xway_spi_grps)},
-       {"asc",         ARRAY_AND_SIZE(xway_asc_grps)},
-       {"cgu",         ARRAY_AND_SIZE(xway_cgu_grps)},
-       {"jtag",        ARRAY_AND_SIZE(xway_jtag_grps)},
-       {"exin",        ARRAY_AND_SIZE(xway_exin_grps)},
-       {"stp",         ARRAY_AND_SIZE(xway_stp_grps)},
-       {"gpt",         ARRAY_AND_SIZE(xway_gpt_grps)},
-       {"nmi",         ARRAY_AND_SIZE(xway_nmi_grps)},
-       {"pci",         ARRAY_AND_SIZE(xway_pci_grps)},
-       {"ebu",         ARRAY_AND_SIZE(xway_ebu_grps)},
-};
-
 static const struct ltq_pmx_func xrx_funcs[] = {
        {"spi",         ARRAY_AND_SIZE(xway_spi_grps)},
        {"asc",         ARRAY_AND_SIZE(xway_asc_grps)},
@@ -434,17 +347,991 @@ static const struct ltq_pmx_func xrx_funcs[] = {
        {"gphy",        ARRAY_AND_SIZE(xrx_gphy_grps)},
 };
 
+/* ---------  ase related code --------- */
+#define ASE_MAX_PIN            32
+
+static const struct ltq_mfp_pin ase_mfp[] = {
+       /*       pin    f0      f1      f2      f3   */
+       MFP_XWAY(GPIO0, GPIO,   EXIN,   MII,    TDM),
+       MFP_XWAY(GPIO1, GPIO,   STP,    DFE,    EBU),
+       MFP_XWAY(GPIO2, GPIO,   STP,    DFE,    EPHY),
+       MFP_XWAY(GPIO3, GPIO,   STP,    EPHY,   EBU),
+       MFP_XWAY(GPIO4, GPIO,   GPT,    EPHY,   MII),
+       MFP_XWAY(GPIO5, GPIO,   MII,    ASC,    GPT),
+       MFP_XWAY(GPIO6, GPIO,   MII,    ASC,    EXIN),
+       MFP_XWAY(GPIO7, GPIO,   SPI,    MII,    JTAG),
+       MFP_XWAY(GPIO8, GPIO,   SPI,    MII,    JTAG),
+       MFP_XWAY(GPIO9, GPIO,   SPI,    MII,    JTAG),
+       MFP_XWAY(GPIO10, GPIO,  SPI,    MII,    JTAG),
+       MFP_XWAY(GPIO11, GPIO,  EBU,    CGU,    JTAG),
+       MFP_XWAY(GPIO12, GPIO,  EBU,    MII,    SDIO),
+       MFP_XWAY(GPIO13, GPIO,  EBU,    MII,    CGU),
+       MFP_XWAY(GPIO14, GPIO,  EBU,    SPI,    CGU),
+       MFP_XWAY(GPIO15, GPIO,  EBU,    SPI,    SDIO),
+       MFP_XWAY(GPIO16, GPIO,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO17, GPIO,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO18, GPIO,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO19, GPIO,  EBU,    MII,    SDIO),
+       MFP_XWAY(GPIO20, GPIO,  EBU,    MII,    SDIO),
+       MFP_XWAY(GPIO21, GPIO,  EBU,    MII,    EBU2),
+       MFP_XWAY(GPIO22, GPIO,  EBU,    MII,    CGU),
+       MFP_XWAY(GPIO23, GPIO,  EBU,    MII,    CGU),
+       MFP_XWAY(GPIO24, GPIO,  EBU,    EBU2,   MDIO),
+       MFP_XWAY(GPIO25, GPIO,  EBU,    MII,    GPT),
+       MFP_XWAY(GPIO26, GPIO,  EBU,    MII,    SDIO),
+       MFP_XWAY(GPIO27, GPIO,  EBU,    NONE,   MDIO),
+       MFP_XWAY(GPIO28, GPIO,  MII,    EBU,    SDIO),
+       MFP_XWAY(GPIO29, GPIO,  EBU,    MII,    EXIN),
+       MFP_XWAY(GPIO30, GPIO,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO31, GPIO,  NONE,   NONE,   NONE),
+};
+
+static const unsigned ase_exin_pin_map[] = {GPIO6, GPIO29, GPIO0};
+
+static const unsigned ase_pins_exin0[] = {GPIO6};
+static const unsigned ase_pins_exin1[] = {GPIO29};
+static const unsigned ase_pins_exin2[] = {GPIO0};
+
+static const unsigned ase_pins_jtag[] = {GPIO7, GPIO8, GPIO9, GPIO10, GPIO11};
+static const unsigned ase_pins_asc[] = {GPIO5, GPIO6};
+static const unsigned ase_pins_stp[] = {GPIO1, GPIO2, GPIO3};
+static const unsigned ase_pins_mdio[] = {GPIO24, GPIO27};
+static const unsigned ase_pins_ephy_led0[] = {GPIO2};
+static const unsigned ase_pins_ephy_led1[] = {GPIO3};
+static const unsigned ase_pins_ephy_led2[] = {GPIO4};
+static const unsigned ase_pins_dfe_led0[] = {GPIO1};
+static const unsigned ase_pins_dfe_led1[] = {GPIO2};
+
+static const unsigned ase_pins_spi[] = {GPIO8, GPIO9, GPIO10}; /* DEPRECATED */
+static const unsigned ase_pins_spi_di[] = {GPIO8};
+static const unsigned ase_pins_spi_do[] = {GPIO9};
+static const unsigned ase_pins_spi_clk[] = {GPIO10};
+static const unsigned ase_pins_spi_cs1[] = {GPIO7};
+static const unsigned ase_pins_spi_cs2[] = {GPIO15};
+static const unsigned ase_pins_spi_cs3[] = {GPIO14};
+
+static const unsigned ase_pins_gpt1[] = {GPIO5};
+static const unsigned ase_pins_gpt2[] = {GPIO4};
+static const unsigned ase_pins_gpt3[] = {GPIO25};
+
+static const unsigned ase_pins_clkout0[] = {GPIO23};
+static const unsigned ase_pins_clkout1[] = {GPIO22};
+static const unsigned ase_pins_clkout2[] = {GPIO14};
+
+static const struct ltq_pin_group ase_grps[] = {
+       GRP_MUX("exin0", EXIN, ase_pins_exin0),
+       GRP_MUX("exin1", EXIN, ase_pins_exin1),
+       GRP_MUX("exin2", EXIN, ase_pins_exin2),
+       GRP_MUX("jtag", JTAG, ase_pins_jtag),
+       GRP_MUX("spi", SPI, ase_pins_spi), /* DEPRECATED */
+       GRP_MUX("spi_di", SPI, ase_pins_spi_di),
+       GRP_MUX("spi_do", SPI, ase_pins_spi_do),
+       GRP_MUX("spi_clk", SPI, ase_pins_spi_clk),
+       GRP_MUX("spi_cs1", SPI, ase_pins_spi_cs1),
+       GRP_MUX("spi_cs2", SPI, ase_pins_spi_cs2),
+       GRP_MUX("spi_cs3", SPI, ase_pins_spi_cs3),
+       GRP_MUX("asc", ASC, ase_pins_asc),
+       GRP_MUX("stp", STP, ase_pins_stp),
+       GRP_MUX("gpt1", GPT, ase_pins_gpt1),
+       GRP_MUX("gpt2", GPT, ase_pins_gpt2),
+       GRP_MUX("gpt3", GPT, ase_pins_gpt3),
+       GRP_MUX("clkout0", CGU, ase_pins_clkout0),
+       GRP_MUX("clkout1", CGU, ase_pins_clkout1),
+       GRP_MUX("clkout2", CGU, ase_pins_clkout2),
+       GRP_MUX("mdio", MDIO, ase_pins_mdio),
+       GRP_MUX("dfe led0", DFE, ase_pins_dfe_led0),
+       GRP_MUX("dfe led1", DFE, ase_pins_dfe_led1),
+       GRP_MUX("ephy led0", EPHY, ase_pins_ephy_led0),
+       GRP_MUX("ephy led1", EPHY, ase_pins_ephy_led1),
+       GRP_MUX("ephy led2", EPHY, ase_pins_ephy_led2),
+};
+
+static const char * const ase_exin_grps[] = {"exin0", "exin1", "exin2"};
+static const char * const ase_gpt_grps[] = {"gpt1", "gpt2", "gpt3"};
+static const char * const ase_cgu_grps[] = {"clkout0", "clkout1",
+                                               "clkout2"};
+static const char * const ase_mdio_grps[] = {"mdio"};
+static const char * const ase_dfe_grps[] = {"dfe led0", "dfe led1"};
+static const char * const ase_ephy_grps[] = {"ephy led0", "ephy led1",
+                                               "ephy led2"};
+static const char * const ase_asc_grps[] = {"asc"};
+static const char * const ase_jtag_grps[] = {"jtag"};
+static const char * const ase_stp_grps[] = {"stp"};
+static const char * const ase_spi_grps[] = {"spi",  /* DEPRECATED */
+                                               "spi_di", "spi_do",
+                                               "spi_clk", "spi_cs1",
+                                               "spi_cs2", "spi_cs3"};
+
 static const struct ltq_pmx_func ase_funcs[] = {
        {"spi",         ARRAY_AND_SIZE(ase_spi_grps)},
        {"asc",         ARRAY_AND_SIZE(ase_asc_grps)},
+       {"cgu",         ARRAY_AND_SIZE(ase_cgu_grps)},
        {"jtag",        ARRAY_AND_SIZE(ase_jtag_grps)},
        {"exin",        ARRAY_AND_SIZE(ase_exin_grps)},
        {"stp",         ARRAY_AND_SIZE(ase_stp_grps)},
        {"gpt",         ARRAY_AND_SIZE(ase_gpt_grps)},
+       {"mdio",        ARRAY_AND_SIZE(ase_mdio_grps)},
        {"ephy",        ARRAY_AND_SIZE(ase_ephy_grps)},
        {"dfe",         ARRAY_AND_SIZE(ase_dfe_grps)},
 };
 
+/* ---------  danube related code --------- */
+#define DANUBE_MAX_PIN         32
+
+static const struct ltq_mfp_pin danube_mfp[] = {
+       /*       pin    f0      f1      f2      f3   */
+       MFP_XWAY(GPIO0, GPIO,   EXIN,   SDIO,   TDM),
+       MFP_XWAY(GPIO1, GPIO,   EXIN,   CBUS,   MII),
+       MFP_XWAY(GPIO2, GPIO,   CGU,    EXIN,   MII),
+       MFP_XWAY(GPIO3, GPIO,   CGU,    SDIO,   PCI),
+       MFP_XWAY(GPIO4, GPIO,   STP,    DFE,    ASC),
+       MFP_XWAY(GPIO5, GPIO,   STP,    MII,    DFE),
+       MFP_XWAY(GPIO6, GPIO,   STP,    GPT,    ASC),
+       MFP_XWAY(GPIO7, GPIO,   CGU,    CBUS,   MII),
+       MFP_XWAY(GPIO8, GPIO,   CGU,    NMI,    MII),
+       MFP_XWAY(GPIO9, GPIO,   ASC,    SPI,    MII),
+       MFP_XWAY(GPIO10, GPIO,  ASC,    SPI,    MII),
+       MFP_XWAY(GPIO11, GPIO,  ASC,    CBUS,   SPI),
+       MFP_XWAY(GPIO12, GPIO,  ASC,    CBUS,   MCD),
+       MFP_XWAY(GPIO13, GPIO,  EBU,    SPI,    MII),
+       MFP_XWAY(GPIO14, GPIO,  CGU,    CBUS,   MII),
+       MFP_XWAY(GPIO15, GPIO,  SPI,    SDIO,   JTAG),
+       MFP_XWAY(GPIO16, GPIO,  SPI,    SDIO,   JTAG),
+       MFP_XWAY(GPIO17, GPIO,  SPI,    SDIO,   JTAG),
+       MFP_XWAY(GPIO18, GPIO,  SPI,    SDIO,   JTAG),
+       MFP_XWAY(GPIO19, GPIO,  PCI,    SDIO,   MII),
+       MFP_XWAY(GPIO20, GPIO,  JTAG,   SDIO,   MII),
+       MFP_XWAY(GPIO21, GPIO,  PCI,    EBU,    GPT),
+       MFP_XWAY(GPIO22, GPIO,  SPI,    MCD,    MII),
+       MFP_XWAY(GPIO23, GPIO,  EBU,    PCI,    STP),
+       MFP_XWAY(GPIO24, GPIO,  EBU,    TDM,    PCI),
+       MFP_XWAY(GPIO25, GPIO,  TDM,    SDIO,   ASC),
+       MFP_XWAY(GPIO26, GPIO,  EBU,    TDM,    SDIO),
+       MFP_XWAY(GPIO27, GPIO,  TDM,    SDIO,   ASC),
+       MFP_XWAY(GPIO28, GPIO,  GPT,    MII,    SDIO),
+       MFP_XWAY(GPIO29, GPIO,  PCI,    CBUS,   MII),
+       MFP_XWAY(GPIO30, GPIO,  PCI,    CBUS,   MII),
+       MFP_XWAY(GPIO31, GPIO,  EBU,    PCI,    MII),
+};
+
+static const unsigned danube_exin_pin_map[] = {GPIO0, GPIO1, GPIO2};
+
+static const unsigned danube_pins_exin0[] = {GPIO0};
+static const unsigned danube_pins_exin1[] = {GPIO1};
+static const unsigned danube_pins_exin2[] = {GPIO2};
+
+static const unsigned danube_pins_jtag[] = {GPIO15, GPIO16, GPIO17, GPIO18, GPIO20};
+static const unsigned danube_pins_asc0[] = {GPIO11, GPIO12};
+static const unsigned danube_pins_asc0_cts_rts[] = {GPIO9, GPIO10};
+static const unsigned danube_pins_stp[] = {GPIO4, GPIO5, GPIO6};
+static const unsigned danube_pins_nmi[] = {GPIO8};
+
+static const unsigned danube_pins_dfe_led0[] = {GPIO4};
+static const unsigned danube_pins_dfe_led1[] = {GPIO5};
+
+static const unsigned danube_pins_ebu_a24[] = {GPIO13};
+static const unsigned danube_pins_ebu_clk[] = {GPIO21};
+static const unsigned danube_pins_ebu_cs1[] = {GPIO23};
+static const unsigned danube_pins_ebu_a23[] = {GPIO24};
+static const unsigned danube_pins_ebu_wait[] = {GPIO26};
+static const unsigned danube_pins_ebu_a25[] = {GPIO31};
+
+static const unsigned danube_pins_nand_ale[] = {GPIO13};
+static const unsigned danube_pins_nand_cs1[] = {GPIO23};
+static const unsigned danube_pins_nand_cle[] = {GPIO24};
+
+static const unsigned danube_pins_spi[] = {GPIO16, GPIO17, GPIO18}; /* DEPRECATED */
+static const unsigned danube_pins_spi_di[] = {GPIO16};
+static const unsigned danube_pins_spi_do[] = {GPIO17};
+static const unsigned danube_pins_spi_clk[] = {GPIO18};
+static const unsigned danube_pins_spi_cs1[] = {GPIO15};
+static const unsigned danube_pins_spi_cs2[] = {GPIO21};
+static const unsigned danube_pins_spi_cs3[] = {GPIO13};
+static const unsigned danube_pins_spi_cs4[] = {GPIO10};
+static const unsigned danube_pins_spi_cs5[] = {GPIO9};
+static const unsigned danube_pins_spi_cs6[] = {GPIO11};
+
+static const unsigned danube_pins_gpt1[] = {GPIO28};
+static const unsigned danube_pins_gpt2[] = {GPIO21};
+static const unsigned danube_pins_gpt3[] = {GPIO6};
+
+static const unsigned danube_pins_clkout0[] = {GPIO8};
+static const unsigned danube_pins_clkout1[] = {GPIO7};
+static const unsigned danube_pins_clkout2[] = {GPIO3};
+static const unsigned danube_pins_clkout3[] = {GPIO2};
+
+static const unsigned danube_pins_pci_gnt1[] = {GPIO30};
+static const unsigned danube_pins_pci_gnt2[] = {GPIO23};
+static const unsigned danube_pins_pci_gnt3[] = {GPIO19};
+static const unsigned danube_pins_pci_req1[] = {GPIO29};
+static const unsigned danube_pins_pci_req2[] = {GPIO31};
+static const unsigned danube_pins_pci_req3[] = {GPIO3};
+
+static const struct ltq_pin_group danube_grps[] = {
+       GRP_MUX("exin0", EXIN, danube_pins_exin0),
+       GRP_MUX("exin1", EXIN, danube_pins_exin1),
+       GRP_MUX("exin2", EXIN, danube_pins_exin2),
+       GRP_MUX("jtag", JTAG, danube_pins_jtag),
+       GRP_MUX("ebu a23", EBU, danube_pins_ebu_a23),
+       GRP_MUX("ebu a24", EBU, danube_pins_ebu_a24),
+       GRP_MUX("ebu a25", EBU, danube_pins_ebu_a25),
+       GRP_MUX("ebu clk", EBU, danube_pins_ebu_clk),
+       GRP_MUX("ebu cs1", EBU, danube_pins_ebu_cs1),
+       GRP_MUX("ebu wait", EBU, danube_pins_ebu_wait),
+       GRP_MUX("nand ale", EBU, danube_pins_nand_ale),
+       GRP_MUX("nand cs1", EBU, danube_pins_nand_cs1),
+       GRP_MUX("nand cle", EBU, danube_pins_nand_cle),
+       GRP_MUX("spi", SPI, danube_pins_spi), /* DEPRECATED */
+       GRP_MUX("spi_di", SPI, danube_pins_spi_di),
+       GRP_MUX("spi_do", SPI, danube_pins_spi_do),
+       GRP_MUX("spi_clk", SPI, danube_pins_spi_clk),
+       GRP_MUX("spi_cs1", SPI, danube_pins_spi_cs1),
+       GRP_MUX("spi_cs2", SPI, danube_pins_spi_cs2),
+       GRP_MUX("spi_cs3", SPI, danube_pins_spi_cs3),
+       GRP_MUX("spi_cs4", SPI, danube_pins_spi_cs4),
+       GRP_MUX("spi_cs5", SPI, danube_pins_spi_cs5),
+       GRP_MUX("spi_cs6", SPI, danube_pins_spi_cs6),
+       GRP_MUX("asc0", ASC, danube_pins_asc0),
+       GRP_MUX("asc0 cts rts", ASC, danube_pins_asc0_cts_rts),
+       GRP_MUX("stp", STP, danube_pins_stp),
+       GRP_MUX("nmi", NMI, danube_pins_nmi),
+       GRP_MUX("gpt1", GPT, danube_pins_gpt1),
+       GRP_MUX("gpt2", GPT, danube_pins_gpt2),
+       GRP_MUX("gpt3", GPT, danube_pins_gpt3),
+       GRP_MUX("clkout0", CGU, danube_pins_clkout0),
+       GRP_MUX("clkout1", CGU, danube_pins_clkout1),
+       GRP_MUX("clkout2", CGU, danube_pins_clkout2),
+       GRP_MUX("clkout3", CGU, danube_pins_clkout3),
+       GRP_MUX("gnt1", PCI, danube_pins_pci_gnt1),
+       GRP_MUX("gnt2", PCI, danube_pins_pci_gnt2),
+       GRP_MUX("gnt3", PCI, danube_pins_pci_gnt3),
+       GRP_MUX("req1", PCI, danube_pins_pci_req1),
+       GRP_MUX("req2", PCI, danube_pins_pci_req2),
+       GRP_MUX("req3", PCI, danube_pins_pci_req3),
+       GRP_MUX("dfe led0", DFE, danube_pins_dfe_led0),
+       GRP_MUX("dfe led1", DFE, danube_pins_dfe_led1),
+};
+
+static const char * const danube_pci_grps[] = {"gnt1", "gnt2",
+                                               "gnt3", "req1",
+                                               "req2", "req3"};
+static const char * const danube_spi_grps[] = {"spi", /* DEPRECATED */
+                                               "spi_di", "spi_do",
+                                               "spi_clk", "spi_cs1",
+                                               "spi_cs2", "spi_cs3",
+                                               "spi_cs4", "spi_cs5",
+                                               "spi_cs6"};
+static const char * const danube_cgu_grps[] = {"clkout0", "clkout1",
+                                               "clkout2", "clkout3"};
+static const char * const danube_ebu_grps[] = {"ebu a23", "ebu a24",
+                                               "ebu a25", "ebu cs1",
+                                               "ebu wait", "ebu clk",
+                                               "nand ale", "nand cs1",
+                                               "nand cle"};
+static const char * const danube_dfe_grps[] = {"dfe led0", "dfe led1"};
+static const char * const danube_exin_grps[] = {"exin0", "exin1", "exin2"};
+static const char * const danube_gpt_grps[] = {"gpt1", "gpt2", "gpt3"};
+static const char * const danube_asc_grps[] = {"asc0", "asc0 cts rts"};
+static const char * const danube_jtag_grps[] = {"jtag"};
+static const char * const danube_stp_grps[] = {"stp"};
+static const char * const danube_nmi_grps[] = {"nmi"};
+
+static const struct ltq_pmx_func danube_funcs[] = {
+       {"spi",         ARRAY_AND_SIZE(danube_spi_grps)},
+       {"asc",         ARRAY_AND_SIZE(danube_asc_grps)},
+       {"cgu",         ARRAY_AND_SIZE(danube_cgu_grps)},
+       {"jtag",        ARRAY_AND_SIZE(danube_jtag_grps)},
+       {"exin",        ARRAY_AND_SIZE(danube_exin_grps)},
+       {"stp",         ARRAY_AND_SIZE(danube_stp_grps)},
+       {"gpt",         ARRAY_AND_SIZE(danube_gpt_grps)},
+       {"nmi",         ARRAY_AND_SIZE(danube_nmi_grps)},
+       {"pci",         ARRAY_AND_SIZE(danube_pci_grps)},
+       {"ebu",         ARRAY_AND_SIZE(danube_ebu_grps)},
+       {"dfe",         ARRAY_AND_SIZE(danube_dfe_grps)},
+};
+
+/* ---------  xrx100 related code --------- */
+#define XRX100_MAX_PIN         56
+
+static const struct ltq_mfp_pin xrx100_mfp[] = {
+       /*       pin    f0      f1      f2      f3   */
+       MFP_XWAY(GPIO0, GPIO,   EXIN,   SDIO,   TDM),
+       MFP_XWAY(GPIO1, GPIO,   EXIN,   CBUS,   SIN),
+       MFP_XWAY(GPIO2, GPIO,   CGU,    EXIN,   NONE),
+       MFP_XWAY(GPIO3, GPIO,   CGU,    SDIO,   PCI),
+       MFP_XWAY(GPIO4, GPIO,   STP,    DFE,    ASC),
+       MFP_XWAY(GPIO5, GPIO,   STP,    NONE,   DFE),
+       MFP_XWAY(GPIO6, GPIO,   STP,    GPT,    ASC),
+       MFP_XWAY(GPIO7, GPIO,   CGU,    CBUS,   NONE),
+       MFP_XWAY(GPIO8, GPIO,   CGU,    NMI,    NONE),
+       MFP_XWAY(GPIO9, GPIO,   ASC,    SPI,    EXIN),
+       MFP_XWAY(GPIO10, GPIO,  ASC,    SPI,    EXIN),
+       MFP_XWAY(GPIO11, GPIO,  ASC,    CBUS,   SPI),
+       MFP_XWAY(GPIO12, GPIO,  ASC,    CBUS,   MCD),
+       MFP_XWAY(GPIO13, GPIO,  EBU,    SPI,    NONE),
+       MFP_XWAY(GPIO14, GPIO,  CGU,    NONE,   NONE),
+       MFP_XWAY(GPIO15, GPIO,  SPI,    SDIO,   MCD),
+       MFP_XWAY(GPIO16, GPIO,  SPI,    SDIO,   NONE),
+       MFP_XWAY(GPIO17, GPIO,  SPI,    SDIO,   NONE),
+       MFP_XWAY(GPIO18, GPIO,  SPI,    SDIO,   NONE),
+       MFP_XWAY(GPIO19, GPIO,  PCI,    SDIO,   CGU),
+       MFP_XWAY(GPIO20, GPIO,  NONE,   SDIO,   EBU),
+       MFP_XWAY(GPIO21, GPIO,  PCI,    EBU,    GPT),
+       MFP_XWAY(GPIO22, GPIO,  SPI,    NONE,   EBU),
+       MFP_XWAY(GPIO23, GPIO,  EBU,    PCI,    STP),
+       MFP_XWAY(GPIO24, GPIO,  EBU,    TDM,    PCI),
+       MFP_XWAY(GPIO25, GPIO,  TDM,    SDIO,   ASC),
+       MFP_XWAY(GPIO26, GPIO,  EBU,    TDM,    SDIO),
+       MFP_XWAY(GPIO27, GPIO,  TDM,    SDIO,   ASC),
+       MFP_XWAY(GPIO28, GPIO,  GPT,    NONE,   SDIO),
+       MFP_XWAY(GPIO29, GPIO,  PCI,    CBUS,   NONE),
+       MFP_XWAY(GPIO30, GPIO,  PCI,    CBUS,   NONE),
+       MFP_XWAY(GPIO31, GPIO,  EBU,    PCI,    NONE),
+       MFP_XWAY(GPIO32, GPIO,  MII,    NONE,   EBU),
+       MFP_XWAY(GPIO33, GPIO,  MII,    NONE,   EBU),
+       MFP_XWAY(GPIO34, GPIO,  SIN,    SSI,    NONE),
+       MFP_XWAY(GPIO35, GPIO,  SIN,    SSI,    NONE),
+       MFP_XWAY(GPIO36, GPIO,  SIN,    SSI,    NONE),
+       MFP_XWAY(GPIO37, GPIO,  PCI,    NONE,   NONE),
+       MFP_XWAY(GPIO38, GPIO,  PCI,    NONE,   NONE),
+       MFP_XWAY(GPIO39, GPIO,  NONE,   EXIN,   NONE),
+       MFP_XWAY(GPIO40, GPIO,  MII,    TDM,    NONE),
+       MFP_XWAY(GPIO41, GPIO,  MII,    TDM,    NONE),
+       MFP_XWAY(GPIO42, GPIO,  MDIO,   NONE,   NONE),
+       MFP_XWAY(GPIO43, GPIO,  MDIO,   NONE,   NONE),
+       MFP_XWAY(GPIO44, GPIO,  MII,    SIN,    NONE),
+       MFP_XWAY(GPIO45, GPIO,  MII,    NONE,   SIN),
+       MFP_XWAY(GPIO46, GPIO,  MII,    NONE,   EXIN),
+       MFP_XWAY(GPIO47, GPIO,  MII,    NONE,   SIN),
+       MFP_XWAY(GPIO48, GPIO,  EBU,    NONE,   NONE),
+       MFP_XWAY(GPIO49, GPIO,  EBU,    NONE,   NONE),
+       MFP_XWAY(GPIO50, GPIO,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO51, GPIO,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO52, GPIO,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO53, GPIO,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO54, GPIO,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO55, GPIO,  NONE,   NONE,   NONE),
+};
+
+static const unsigned xrx100_exin_pin_map[] = {GPIO0, GPIO1, GPIO2, GPIO39, GPIO10, GPIO9};
+
+static const unsigned xrx100_pins_exin0[] = {GPIO0};
+static const unsigned xrx100_pins_exin1[] = {GPIO1};
+static const unsigned xrx100_pins_exin2[] = {GPIO2};
+static const unsigned xrx100_pins_exin3[] = {GPIO39};
+static const unsigned xrx100_pins_exin4[] = {GPIO10};
+static const unsigned xrx100_pins_exin5[] = {GPIO9};
+
+static const unsigned xrx100_pins_asc0[] = {GPIO11, GPIO12};
+static const unsigned xrx100_pins_asc0_cts_rts[] = {GPIO9, GPIO10};
+static const unsigned xrx100_pins_stp[] = {GPIO4, GPIO5, GPIO6};
+static const unsigned xrx100_pins_nmi[] = {GPIO8};
+static const unsigned xrx100_pins_mdio[] = {GPIO42, GPIO43};
+
+static const unsigned xrx100_pins_dfe_led0[] = {GPIO4};
+static const unsigned xrx100_pins_dfe_led1[] = {GPIO5};
+
+static const unsigned xrx100_pins_ebu_a24[] = {GPIO13};
+static const unsigned xrx100_pins_ebu_clk[] = {GPIO21};
+static const unsigned xrx100_pins_ebu_cs1[] = {GPIO23};
+static const unsigned xrx100_pins_ebu_a23[] = {GPIO24};
+static const unsigned xrx100_pins_ebu_wait[] = {GPIO26};
+static const unsigned xrx100_pins_ebu_a25[] = {GPIO31};
+
+static const unsigned xrx100_pins_nand_ale[] = {GPIO13};
+static const unsigned xrx100_pins_nand_cs1[] = {GPIO23};
+static const unsigned xrx100_pins_nand_cle[] = {GPIO24};
+static const unsigned xrx100_pins_nand_rdy[] = {GPIO48};
+static const unsigned xrx100_pins_nand_rd[] = {GPIO49};
+
+static const unsigned xrx100_pins_spi_di[] = {GPIO16};
+static const unsigned xrx100_pins_spi_do[] = {GPIO17};
+static const unsigned xrx100_pins_spi_clk[] = {GPIO18};
+static const unsigned xrx100_pins_spi_cs1[] = {GPIO15};
+static const unsigned xrx100_pins_spi_cs2[] = {GPIO22};
+static const unsigned xrx100_pins_spi_cs3[] = {GPIO13};
+static const unsigned xrx100_pins_spi_cs4[] = {GPIO10};
+static const unsigned xrx100_pins_spi_cs5[] = {GPIO9};
+static const unsigned xrx100_pins_spi_cs6[] = {GPIO11};
+
+static const unsigned xrx100_pins_gpt1[] = {GPIO28};
+static const unsigned xrx100_pins_gpt2[] = {GPIO21};
+static const unsigned xrx100_pins_gpt3[] = {GPIO6};
+
+static const unsigned xrx100_pins_clkout0[] = {GPIO8};
+static const unsigned xrx100_pins_clkout1[] = {GPIO7};
+static const unsigned xrx100_pins_clkout2[] = {GPIO3};
+static const unsigned xrx100_pins_clkout3[] = {GPIO2};
+
+static const unsigned xrx100_pins_pci_gnt1[] = {GPIO30};
+static const unsigned xrx100_pins_pci_gnt2[] = {GPIO23};
+static const unsigned xrx100_pins_pci_gnt3[] = {GPIO19};
+static const unsigned xrx100_pins_pci_gnt4[] = {GPIO38};
+static const unsigned xrx100_pins_pci_req1[] = {GPIO29};
+static const unsigned xrx100_pins_pci_req2[] = {GPIO31};
+static const unsigned xrx100_pins_pci_req3[] = {GPIO3};
+static const unsigned xrx100_pins_pci_req4[] = {GPIO37};
+
+static const struct ltq_pin_group xrx100_grps[] = {
+       GRP_MUX("exin0", EXIN, xrx100_pins_exin0),
+       GRP_MUX("exin1", EXIN, xrx100_pins_exin1),
+       GRP_MUX("exin2", EXIN, xrx100_pins_exin2),
+       GRP_MUX("exin3", EXIN, xrx100_pins_exin3),
+       GRP_MUX("exin4", EXIN, xrx100_pins_exin4),
+       GRP_MUX("exin5", EXIN, xrx100_pins_exin5),
+       GRP_MUX("ebu a23", EBU, xrx100_pins_ebu_a23),
+       GRP_MUX("ebu a24", EBU, xrx100_pins_ebu_a24),
+       GRP_MUX("ebu a25", EBU, xrx100_pins_ebu_a25),
+       GRP_MUX("ebu clk", EBU, xrx100_pins_ebu_clk),
+       GRP_MUX("ebu cs1", EBU, xrx100_pins_ebu_cs1),
+       GRP_MUX("ebu wait", EBU, xrx100_pins_ebu_wait),
+       GRP_MUX("nand ale", EBU, xrx100_pins_nand_ale),
+       GRP_MUX("nand cs1", EBU, xrx100_pins_nand_cs1),
+       GRP_MUX("nand cle", EBU, xrx100_pins_nand_cle),
+       GRP_MUX("nand rdy", EBU, xrx100_pins_nand_rdy),
+       GRP_MUX("nand rd", EBU, xrx100_pins_nand_rd),
+       GRP_MUX("spi_di", SPI, xrx100_pins_spi_di),
+       GRP_MUX("spi_do", SPI, xrx100_pins_spi_do),
+       GRP_MUX("spi_clk", SPI, xrx100_pins_spi_clk),
+       GRP_MUX("spi_cs1", SPI, xrx100_pins_spi_cs1),
+       GRP_MUX("spi_cs2", SPI, xrx100_pins_spi_cs2),
+       GRP_MUX("spi_cs3", SPI, xrx100_pins_spi_cs3),
+       GRP_MUX("spi_cs4", SPI, xrx100_pins_spi_cs4),
+       GRP_MUX("spi_cs5", SPI, xrx100_pins_spi_cs5),
+       GRP_MUX("spi_cs6", SPI, xrx100_pins_spi_cs6),
+       GRP_MUX("asc0", ASC, xrx100_pins_asc0),
+       GRP_MUX("asc0 cts rts", ASC, xrx100_pins_asc0_cts_rts),
+       GRP_MUX("stp", STP, xrx100_pins_stp),
+       GRP_MUX("nmi", NMI, xrx100_pins_nmi),
+       GRP_MUX("gpt1", GPT, xrx100_pins_gpt1),
+       GRP_MUX("gpt2", GPT, xrx100_pins_gpt2),
+       GRP_MUX("gpt3", GPT, xrx100_pins_gpt3),
+       GRP_MUX("clkout0", CGU, xrx100_pins_clkout0),
+       GRP_MUX("clkout1", CGU, xrx100_pins_clkout1),
+       GRP_MUX("clkout2", CGU, xrx100_pins_clkout2),
+       GRP_MUX("clkout3", CGU, xrx100_pins_clkout3),
+       GRP_MUX("gnt1", PCI, xrx100_pins_pci_gnt1),
+       GRP_MUX("gnt2", PCI, xrx100_pins_pci_gnt2),
+       GRP_MUX("gnt3", PCI, xrx100_pins_pci_gnt3),
+       GRP_MUX("gnt4", PCI, xrx100_pins_pci_gnt4),
+       GRP_MUX("req1", PCI, xrx100_pins_pci_req1),
+       GRP_MUX("req2", PCI, xrx100_pins_pci_req2),
+       GRP_MUX("req3", PCI, xrx100_pins_pci_req3),
+       GRP_MUX("req4", PCI, xrx100_pins_pci_req4),
+       GRP_MUX("mdio", MDIO, xrx100_pins_mdio),
+       GRP_MUX("dfe led0", DFE, xrx100_pins_dfe_led0),
+       GRP_MUX("dfe led1", DFE, xrx100_pins_dfe_led1),
+};
+
+static const char * const xrx100_pci_grps[] = {"gnt1", "gnt2",
+                                               "gnt3", "gnt4",
+                                               "req1", "req2",
+                                               "req3", "req4"};
+static const char * const xrx100_spi_grps[] = {"spi_di", "spi_do",
+                                               "spi_clk", "spi_cs1",
+                                               "spi_cs2", "spi_cs3",
+                                               "spi_cs4", "spi_cs5",
+                                               "spi_cs6"};
+static const char * const xrx100_cgu_grps[] = {"clkout0", "clkout1",
+                                               "clkout2", "clkout3"};
+static const char * const xrx100_ebu_grps[] = {"ebu a23", "ebu a24",
+                                               "ebu a25", "ebu cs1",
+                                               "ebu wait", "ebu clk",
+                                               "nand ale", "nand cs1",
+                                               "nand cle", "nand rdy",
+                                               "nand rd"};
+static const char * const xrx100_exin_grps[] = {"exin0", "exin1", "exin2",
+                                               "exin3", "exin4", "exin5"};
+static const char * const xrx100_gpt_grps[] = {"gpt1", "gpt2", "gpt3"};
+static const char * const xrx100_asc_grps[] = {"asc0", "asc0 cts rts"};
+static const char * const xrx100_stp_grps[] = {"stp"};
+static const char * const xrx100_nmi_grps[] = {"nmi"};
+static const char * const xrx100_mdio_grps[] = {"mdio"};
+static const char * const xrx100_dfe_grps[] = {"dfe led0", "dfe led1"};
+
+static const struct ltq_pmx_func xrx100_funcs[] = {
+       {"spi",         ARRAY_AND_SIZE(xrx100_spi_grps)},
+       {"asc",         ARRAY_AND_SIZE(xrx100_asc_grps)},
+       {"cgu",         ARRAY_AND_SIZE(xrx100_cgu_grps)},
+       {"exin",        ARRAY_AND_SIZE(xrx100_exin_grps)},
+       {"stp",         ARRAY_AND_SIZE(xrx100_stp_grps)},
+       {"gpt",         ARRAY_AND_SIZE(xrx100_gpt_grps)},
+       {"nmi",         ARRAY_AND_SIZE(xrx100_nmi_grps)},
+       {"pci",         ARRAY_AND_SIZE(xrx100_pci_grps)},
+       {"ebu",         ARRAY_AND_SIZE(xrx100_ebu_grps)},
+       {"mdio",        ARRAY_AND_SIZE(xrx100_mdio_grps)},
+       {"dfe",         ARRAY_AND_SIZE(xrx100_dfe_grps)},
+};
+
+/* ---------  xrx200 related code --------- */
+#define XRX200_MAX_PIN         50
+
+static const struct ltq_mfp_pin xrx200_mfp[] = {
+       /*       pin    f0      f1      f2      f3   */
+       MFP_XWAY(GPIO0, GPIO,   EXIN,   SDIO,   TDM),
+       MFP_XWAY(GPIO1, GPIO,   EXIN,   CBUS,   SIN),
+       MFP_XWAY(GPIO2, GPIO,   CGU,    EXIN,   GPHY),
+       MFP_XWAY(GPIO3, GPIO,   CGU,    SDIO,   PCI),
+       MFP_XWAY(GPIO4, GPIO,   STP,    DFE,    USIF),
+       MFP_XWAY(GPIO5, GPIO,   STP,    GPHY,   DFE),
+       MFP_XWAY(GPIO6, GPIO,   STP,    GPT,    USIF),
+       MFP_XWAY(GPIO7, GPIO,   CGU,    CBUS,   GPHY),
+       MFP_XWAY(GPIO8, GPIO,   CGU,    NMI,    NONE),
+       MFP_XWAY(GPIO9, GPIO,   USIF,   SPI,    EXIN),
+       MFP_XWAY(GPIO10, GPIO,  USIF,   SPI,    EXIN),
+       MFP_XWAY(GPIO11, GPIO,  USIF,   CBUS,   SPI),
+       MFP_XWAY(GPIO12, GPIO,  USIF,   CBUS,   MCD),
+       MFP_XWAY(GPIO13, GPIO,  EBU,    SPI,    NONE),
+       MFP_XWAY(GPIO14, GPIO,  CGU,    CBUS,   USIF),
+       MFP_XWAY(GPIO15, GPIO,  SPI,    SDIO,   MCD),
+       MFP_XWAY(GPIO16, GPIO,  SPI,    SDIO,   NONE),
+       MFP_XWAY(GPIO17, GPIO,  SPI,    SDIO,   NONE),
+       MFP_XWAY(GPIO18, GPIO,  SPI,    SDIO,   NONE),
+       MFP_XWAY(GPIO19, GPIO,  PCI,    SDIO,   CGU),
+       MFP_XWAY(GPIO20, GPIO,  NONE,   SDIO,   EBU),
+       MFP_XWAY(GPIO21, GPIO,  PCI,    EBU,    GPT),
+       MFP_XWAY(GPIO22, GPIO,  SPI,    CGU,    EBU),
+       MFP_XWAY(GPIO23, GPIO,  EBU,    PCI,    STP),
+       MFP_XWAY(GPIO24, GPIO,  EBU,    TDM,    PCI),
+       MFP_XWAY(GPIO25, GPIO,  TDM,    SDIO,   USIF),
+       MFP_XWAY(GPIO26, GPIO,  EBU,    TDM,    SDIO),
+       MFP_XWAY(GPIO27, GPIO,  TDM,    SDIO,   USIF),
+       MFP_XWAY(GPIO28, GPIO,  GPT,    PCI,    SDIO),
+       MFP_XWAY(GPIO29, GPIO,  PCI,    CBUS,   EXIN),
+       MFP_XWAY(GPIO30, GPIO,  PCI,    CBUS,   NONE),
+       MFP_XWAY(GPIO31, GPIO,  EBU,    PCI,    NONE),
+       MFP_XWAY(GPIO32, GPIO,  MII,    NONE,   EBU),
+       MFP_XWAY(GPIO33, GPIO,  MII,    NONE,   EBU),
+       MFP_XWAY(GPIO34, GPIO,  SIN,    SSI,    NONE),
+       MFP_XWAY(GPIO35, GPIO,  SIN,    SSI,    NONE),
+       MFP_XWAY(GPIO36, GPIO,  SIN,    SSI,    EXIN),
+       MFP_XWAY(GPIO37, GPIO,  USIF,   NONE,   PCI),
+       MFP_XWAY(GPIO38, GPIO,  PCI,    USIF,   NONE),
+       MFP_XWAY(GPIO39, GPIO,  USIF,   EXIN,   NONE),
+       MFP_XWAY(GPIO40, GPIO,  MII,    TDM,    NONE),
+       MFP_XWAY(GPIO41, GPIO,  MII,    TDM,    NONE),
+       MFP_XWAY(GPIO42, GPIO,  MDIO,   NONE,   NONE),
+       MFP_XWAY(GPIO43, GPIO,  MDIO,   NONE,   NONE),
+       MFP_XWAY(GPIO44, GPIO,  MII,    SIN,    GPHY),
+       MFP_XWAY(GPIO45, GPIO,  MII,    GPHY,   SIN),
+       MFP_XWAY(GPIO46, GPIO,  MII,    NONE,   EXIN),
+       MFP_XWAY(GPIO47, GPIO,  MII,    GPHY,   SIN),
+       MFP_XWAY(GPIO48, GPIO,  EBU,    NONE,   NONE),
+       MFP_XWAY(GPIO49, GPIO,  EBU,    NONE,   NONE),
+};
+
+static const unsigned xrx200_exin_pin_map[] = {GPIO0, GPIO1, GPIO2, GPIO39, GPIO10, GPIO9};
+
+static const unsigned xrx200_pins_exin0[] = {GPIO0};
+static const unsigned xrx200_pins_exin1[] = {GPIO1};
+static const unsigned xrx200_pins_exin2[] = {GPIO2};
+static const unsigned xrx200_pins_exin3[] = {GPIO39};
+static const unsigned xrx200_pins_exin4[] = {GPIO10};
+static const unsigned xrx200_pins_exin5[] = {GPIO9};
+
+static const unsigned xrx200_pins_usif_uart_rx[] = {GPIO11};
+static const unsigned xrx200_pins_usif_uart_tx[] = {GPIO12};
+static const unsigned xrx200_pins_usif_uart_rts[] = {GPIO9};
+static const unsigned xrx200_pins_usif_uart_cts[] = {GPIO10};
+static const unsigned xrx200_pins_usif_uart_dtr[] = {GPIO4};
+static const unsigned xrx200_pins_usif_uart_dsr[] = {GPIO6};
+static const unsigned xrx200_pins_usif_uart_dcd[] = {GPIO25};
+static const unsigned xrx200_pins_usif_uart_ri[] = {GPIO27};
+
+static const unsigned xrx200_pins_usif_spi_di[] = {GPIO11};
+static const unsigned xrx200_pins_usif_spi_do[] = {GPIO12};
+static const unsigned xrx200_pins_usif_spi_clk[] = {GPIO38};
+static const unsigned xrx200_pins_usif_spi_cs0[] = {GPIO37};
+static const unsigned xrx200_pins_usif_spi_cs1[] = {GPIO39};
+static const unsigned xrx200_pins_usif_spi_cs2[] = {GPIO14};
+
+static const unsigned xrx200_pins_stp[] = {GPIO4, GPIO5, GPIO6};
+static const unsigned xrx200_pins_nmi[] = {GPIO8};
+static const unsigned xrx200_pins_mdio[] = {GPIO42, GPIO43};
+
+static const unsigned xrx200_pins_dfe_led0[] = {GPIO4};
+static const unsigned xrx200_pins_dfe_led1[] = {GPIO5};
+
+static const unsigned xrx200_pins_gphy0_led0[] = {GPIO5};
+static const unsigned xrx200_pins_gphy0_led1[] = {GPIO7};
+static const unsigned xrx200_pins_gphy0_led2[] = {GPIO2};
+static const unsigned xrx200_pins_gphy1_led0[] = {GPIO44};
+static const unsigned xrx200_pins_gphy1_led1[] = {GPIO45};
+static const unsigned xrx200_pins_gphy1_led2[] = {GPIO47};
+
+static const unsigned xrx200_pins_ebu_a24[] = {GPIO13};
+static const unsigned xrx200_pins_ebu_clk[] = {GPIO21};
+static const unsigned xrx200_pins_ebu_cs1[] = {GPIO23};
+static const unsigned xrx200_pins_ebu_a23[] = {GPIO24};
+static const unsigned xrx200_pins_ebu_wait[] = {GPIO26};
+static const unsigned xrx200_pins_ebu_a25[] = {GPIO31};
+
+static const unsigned xrx200_pins_nand_ale[] = {GPIO13};
+static const unsigned xrx200_pins_nand_cs1[] = {GPIO23};
+static const unsigned xrx200_pins_nand_cle[] = {GPIO24};
+static const unsigned xrx200_pins_nand_rdy[] = {GPIO48};
+static const unsigned xrx200_pins_nand_rd[] = {GPIO49};
+
+static const unsigned xrx200_pins_spi_di[] = {GPIO16};
+static const unsigned xrx200_pins_spi_do[] = {GPIO17};
+static const unsigned xrx200_pins_spi_clk[] = {GPIO18};
+static const unsigned xrx200_pins_spi_cs1[] = {GPIO15};
+static const unsigned xrx200_pins_spi_cs2[] = {GPIO22};
+static const unsigned xrx200_pins_spi_cs3[] = {GPIO13};
+static const unsigned xrx200_pins_spi_cs4[] = {GPIO10};
+static const unsigned xrx200_pins_spi_cs5[] = {GPIO9};
+static const unsigned xrx200_pins_spi_cs6[] = {GPIO11};
+
+static const unsigned xrx200_pins_gpt1[] = {GPIO28};
+static const unsigned xrx200_pins_gpt2[] = {GPIO21};
+static const unsigned xrx200_pins_gpt3[] = {GPIO6};
+
+static const unsigned xrx200_pins_clkout0[] = {GPIO8};
+static const unsigned xrx200_pins_clkout1[] = {GPIO7};
+static const unsigned xrx200_pins_clkout2[] = {GPIO3};
+static const unsigned xrx200_pins_clkout3[] = {GPIO2};
+
+static const unsigned xrx200_pins_pci_gnt1[] = {GPIO28};
+static const unsigned xrx200_pins_pci_gnt2[] = {GPIO23};
+static const unsigned xrx200_pins_pci_gnt3[] = {GPIO19};
+static const unsigned xrx200_pins_pci_gnt4[] = {GPIO38};
+static const unsigned xrx200_pins_pci_req1[] = {GPIO29};
+static const unsigned xrx200_pins_pci_req2[] = {GPIO31};
+static const unsigned xrx200_pins_pci_req3[] = {GPIO3};
+static const unsigned xrx200_pins_pci_req4[] = {GPIO37};
+
+static const struct ltq_pin_group xrx200_grps[] = {
+       GRP_MUX("exin0", EXIN, xrx200_pins_exin0),
+       GRP_MUX("exin1", EXIN, xrx200_pins_exin1),
+       GRP_MUX("exin2", EXIN, xrx200_pins_exin2),
+       GRP_MUX("exin3", EXIN, xrx200_pins_exin3),
+       GRP_MUX("exin4", EXIN, xrx200_pins_exin4),
+       GRP_MUX("exin5", EXIN, xrx200_pins_exin5),
+       GRP_MUX("ebu a23", EBU, xrx200_pins_ebu_a23),
+       GRP_MUX("ebu a24", EBU, xrx200_pins_ebu_a24),
+       GRP_MUX("ebu a25", EBU, xrx200_pins_ebu_a25),
+       GRP_MUX("ebu clk", EBU, xrx200_pins_ebu_clk),
+       GRP_MUX("ebu cs1", EBU, xrx200_pins_ebu_cs1),
+       GRP_MUX("ebu wait", EBU, xrx200_pins_ebu_wait),
+       GRP_MUX("nand ale", EBU, xrx200_pins_nand_ale),
+       GRP_MUX("nand cs1", EBU, xrx200_pins_nand_cs1),
+       GRP_MUX("nand cle", EBU, xrx200_pins_nand_cle),
+       GRP_MUX("nand rdy", EBU, xrx200_pins_nand_rdy),
+       GRP_MUX("nand rd", EBU, xrx200_pins_nand_rd),
+       GRP_MUX("spi_di", SPI, xrx200_pins_spi_di),
+       GRP_MUX("spi_do", SPI, xrx200_pins_spi_do),
+       GRP_MUX("spi_clk", SPI, xrx200_pins_spi_clk),
+       GRP_MUX("spi_cs1", SPI, xrx200_pins_spi_cs1),
+       GRP_MUX("spi_cs2", SPI, xrx200_pins_spi_cs2),
+       GRP_MUX("spi_cs3", SPI, xrx200_pins_spi_cs3),
+       GRP_MUX("spi_cs4", SPI, xrx200_pins_spi_cs4),
+       GRP_MUX("spi_cs5", SPI, xrx200_pins_spi_cs5),
+       GRP_MUX("spi_cs6", SPI, xrx200_pins_spi_cs6),
+       GRP_MUX("usif uart_rx", USIF, xrx200_pins_usif_uart_rx),
+       GRP_MUX("usif uart_rx", USIF, xrx200_pins_usif_uart_tx),
+       GRP_MUX("usif uart_rts", USIF, xrx200_pins_usif_uart_rts),
+       GRP_MUX("usif uart_cts", USIF, xrx200_pins_usif_uart_cts),
+       GRP_MUX("usif uart_dtr", USIF, xrx200_pins_usif_uart_dtr),
+       GRP_MUX("usif uart_dsr", USIF, xrx200_pins_usif_uart_dsr),
+       GRP_MUX("usif uart_dcd", USIF, xrx200_pins_usif_uart_dcd),
+       GRP_MUX("usif uart_ri", USIF, xrx200_pins_usif_uart_ri),
+       GRP_MUX("usif spi_di", USIF, xrx200_pins_usif_spi_di),
+       GRP_MUX("usif spi_do", USIF, xrx200_pins_usif_spi_do),
+       GRP_MUX("usif spi_clk", USIF, xrx200_pins_usif_spi_clk),
+       GRP_MUX("usif spi_cs0", USIF, xrx200_pins_usif_spi_cs0),
+       GRP_MUX("usif spi_cs1", USIF, xrx200_pins_usif_spi_cs1),
+       GRP_MUX("usif spi_cs2", USIF, xrx200_pins_usif_spi_cs2),
+       GRP_MUX("stp", STP, xrx200_pins_stp),
+       GRP_MUX("nmi", NMI, xrx200_pins_nmi),
+       GRP_MUX("gpt1", GPT, xrx200_pins_gpt1),
+       GRP_MUX("gpt2", GPT, xrx200_pins_gpt2),
+       GRP_MUX("gpt3", GPT, xrx200_pins_gpt3),
+       GRP_MUX("clkout0", CGU, xrx200_pins_clkout0),
+       GRP_MUX("clkout1", CGU, xrx200_pins_clkout1),
+       GRP_MUX("clkout2", CGU, xrx200_pins_clkout2),
+       GRP_MUX("clkout3", CGU, xrx200_pins_clkout3),
+       GRP_MUX("gnt1", PCI, xrx200_pins_pci_gnt1),
+       GRP_MUX("gnt2", PCI, xrx200_pins_pci_gnt2),
+       GRP_MUX("gnt3", PCI, xrx200_pins_pci_gnt3),
+       GRP_MUX("gnt4", PCI, xrx200_pins_pci_gnt4),
+       GRP_MUX("req1", PCI, xrx200_pins_pci_req1),
+       GRP_MUX("req2", PCI, xrx200_pins_pci_req2),
+       GRP_MUX("req3", PCI, xrx200_pins_pci_req3),
+       GRP_MUX("req4", PCI, xrx200_pins_pci_req4),
+       GRP_MUX("mdio", MDIO, xrx200_pins_mdio),
+       GRP_MUX("dfe led0", DFE, xrx200_pins_dfe_led0),
+       GRP_MUX("dfe led1", DFE, xrx200_pins_dfe_led1),
+       GRP_MUX("gphy0 led0", GPHY, xrx200_pins_gphy0_led0),
+       GRP_MUX("gphy0 led1", GPHY, xrx200_pins_gphy0_led1),
+       GRP_MUX("gphy0 led2", GPHY, xrx200_pins_gphy0_led2),
+       GRP_MUX("gphy1 led0", GPHY, xrx200_pins_gphy1_led0),
+       GRP_MUX("gphy1 led1", GPHY, xrx200_pins_gphy1_led1),
+       GRP_MUX("gphy1 led2", GPHY, xrx200_pins_gphy1_led2),
+};
+
+static const char * const xrx200_pci_grps[] = {"gnt1", "gnt2",
+                                               "gnt3", "gnt4",
+                                               "req1", "req2",
+                                               "req3", "req4"};
+static const char * const xrx200_spi_grps[] = {"spi_di", "spi_do",
+                                               "spi_clk", "spi_cs1",
+                                               "spi_cs2", "spi_cs3",
+                                               "spi_cs4", "spi_cs5",
+                                               "spi_cs6"};
+static const char * const xrx200_cgu_grps[] = {"clkout0", "clkout1",
+                                               "clkout2", "clkout3"};
+static const char * const xrx200_ebu_grps[] = {"ebu a23", "ebu a24",
+                                               "ebu a25", "ebu cs1",
+                                               "ebu wait", "ebu clk",
+                                               "nand ale", "nand cs1",
+                                               "nand cle", "nand rdy",
+                                               "nand rd"};
+static const char * const xrx200_exin_grps[] = {"exin0", "exin1", "exin2",
+                                               "exin3", "exin4", "exin5"};
+static const char * const xrx200_gpt_grps[] = {"gpt1", "gpt2", "gpt3"};
+static const char * const xrx200_usif_grps[] = {"usif uart_rx", "usif uart_tx",
+                                               "usif uart_rts", "usif uart_cts",
+                                               "usif uart_dtr", "usif uart_dsr",
+                                               "usif uart_dcd", "usif uart_ri",
+                                               "usif spi_di", "usif spi_do",
+                                               "usif spi_clk", "usif spi_cs0",
+                                               "usif spi_cs1", "usif spi_cs2"};
+static const char * const xrx200_stp_grps[] = {"stp"};
+static const char * const xrx200_nmi_grps[] = {"nmi"};
+static const char * const xrx200_mdio_grps[] = {"mdio"};
+static const char * const xrx200_dfe_grps[] = {"dfe led0", "dfe led1"};
+static const char * const xrx200_gphy_grps[] = {"gphy0 led0", "gphy0 led1",
+                                               "gphy0 led2", "gphy1 led0",
+                                               "gphy1 led1", "gphy1 led2"};
+
+static const struct ltq_pmx_func xrx200_funcs[] = {
+       {"spi",         ARRAY_AND_SIZE(xrx200_spi_grps)},
+       {"usif",        ARRAY_AND_SIZE(xrx200_usif_grps)},
+       {"cgu",         ARRAY_AND_SIZE(xrx200_cgu_grps)},
+       {"exin",        ARRAY_AND_SIZE(xrx200_exin_grps)},
+       {"stp",         ARRAY_AND_SIZE(xrx200_stp_grps)},
+       {"gpt",         ARRAY_AND_SIZE(xrx200_gpt_grps)},
+       {"nmi",         ARRAY_AND_SIZE(xrx200_nmi_grps)},
+       {"pci",         ARRAY_AND_SIZE(xrx200_pci_grps)},
+       {"ebu",         ARRAY_AND_SIZE(xrx200_ebu_grps)},
+       {"mdio",        ARRAY_AND_SIZE(xrx200_mdio_grps)},
+       {"dfe",         ARRAY_AND_SIZE(xrx200_dfe_grps)},
+       {"gphy",        ARRAY_AND_SIZE(xrx200_gphy_grps)},
+};
+
+/* ---------  xrx300 related code --------- */
+#define XRX300_MAX_PIN         64
+
+static const struct ltq_mfp_pin xrx300_mfp[] = {
+       /*       pin    f0      f1      f2      f3   */
+       MFP_XWAY(GPIO0, GPIO,   EXIN,   EPHY,   NONE),
+       MFP_XWAY(GPIO1, GPIO,   NONE,   EXIN,   NONE),
+       MFP_XWAY(GPIO2, NONE,   NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO3, GPIO,   CGU,    NONE,   NONE),
+       MFP_XWAY(GPIO4, GPIO,   STP,    DFE,    NONE),
+       MFP_XWAY(GPIO5, GPIO,   STP,    EPHY,   DFE),
+       MFP_XWAY(GPIO6, GPIO,   STP,    NONE,   NONE),
+       MFP_XWAY(GPIO7, NONE,   NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO8, GPIO,   CGU,    GPHY,   EPHY),
+       MFP_XWAY(GPIO9, GPIO,   WIFI,   NONE,   EXIN),
+       MFP_XWAY(GPIO10, GPIO,  USIF,   SPI,    EXIN),
+       MFP_XWAY(GPIO11, GPIO,  USIF,   WIFI,   SPI),
+       MFP_XWAY(GPIO12, NONE,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO13, GPIO,  EBU,    NONE,   NONE),
+       MFP_XWAY(GPIO14, GPIO,  CGU,    USIF,   EPHY),
+       MFP_XWAY(GPIO15, GPIO,  SPI,    NONE,   MCD),
+       MFP_XWAY(GPIO16, GPIO,  SPI,    EXIN,   NONE),
+       MFP_XWAY(GPIO17, GPIO,  SPI,    NONE,   NONE),
+       MFP_XWAY(GPIO18, GPIO,  SPI,    NONE,   NONE),
+       MFP_XWAY(GPIO19, GPIO,  USIF,   NONE,   EPHY),
+       MFP_XWAY(GPIO20, NONE,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO21, NONE,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO22, NONE,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO23, GPIO,  EBU,    NONE,   NONE),
+       MFP_XWAY(GPIO24, GPIO,  EBU,    NONE,   NONE),
+       MFP_XWAY(GPIO25, GPIO,  TDM,    NONE,   NONE),
+       MFP_XWAY(GPIO26, GPIO,  TDM,    NONE,   NONE),
+       MFP_XWAY(GPIO27, GPIO,  TDM,    NONE,   NONE),
+       MFP_XWAY(GPIO28, NONE,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO29, NONE,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO30, NONE,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO31, NONE,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO32, NONE,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO33, NONE,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO34, GPIO,  NONE,   SSI,    NONE),
+       MFP_XWAY(GPIO35, GPIO,  NONE,   SSI,    NONE),
+       MFP_XWAY(GPIO36, GPIO,  NONE,   SSI,    NONE),
+       MFP_XWAY(GPIO37, NONE,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO38, NONE,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO39, NONE,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO40, NONE,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO41, NONE,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO42, GPIO,  MDIO,   NONE,   NONE),
+       MFP_XWAY(GPIO43, GPIO,  MDIO,   NONE,   NONE),
+       MFP_XWAY(GPIO44, NONE,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO45, NONE,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO46, NONE,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO47, NONE,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO48, GPIO,  EBU,    NONE,   NONE),
+       MFP_XWAY(GPIO49, GPIO,  EBU,    NONE,   NONE),
+       MFP_XWAY(GPIO50, GPIO,  EBU,    NONE,   NONE),
+       MFP_XWAY(GPIO51, GPIO,  EBU,    NONE,   NONE),
+       MFP_XWAY(GPIO52, GPIO,  EBU,    NONE,   NONE),
+       MFP_XWAY(GPIO53, GPIO,  EBU,    NONE,   NONE),
+       MFP_XWAY(GPIO54, GPIO,  EBU,    NONE,   NONE),
+       MFP_XWAY(GPIO55, GPIO,  EBU,    NONE,   NONE),
+       MFP_XWAY(GPIO56, GPIO,  EBU,    NONE,   NONE),
+       MFP_XWAY(GPIO57, GPIO,  EBU,    NONE,   NONE),
+       MFP_XWAY(GPIO58, GPIO,  EBU,    TDM,    NONE),
+       MFP_XWAY(GPIO59, GPIO,  EBU,    NONE,   NONE),
+       MFP_XWAY(GPIO60, GPIO,  EBU,    NONE,   NONE),
+       MFP_XWAY(GPIO61, GPIO,  EBU,    NONE,   NONE),
+       MFP_XWAY(GPIO62, NONE,  NONE,   NONE,   NONE),
+       MFP_XWAY(GPIO63, NONE,  NONE,   NONE,   NONE),
+};
+
+static const unsigned xrx300_exin_pin_map[] = {GPIO0, GPIO1, GPIO16, GPIO10, GPIO9};
+
+static const unsigned xrx300_pins_exin0[] = {GPIO0};
+static const unsigned xrx300_pins_exin1[] = {GPIO1};
+static const unsigned xrx300_pins_exin2[] = {GPIO16};
+/* EXIN3 is not available on xrX300 */
+static const unsigned xrx300_pins_exin4[] = {GPIO10};
+static const unsigned xrx300_pins_exin5[] = {GPIO9};
+
+static const unsigned xrx300_pins_usif_uart_rx[] = {GPIO11};
+static const unsigned xrx300_pins_usif_uart_tx[] = {GPIO10};
+
+static const unsigned xrx300_pins_usif_spi_di[] = {GPIO11};
+static const unsigned xrx300_pins_usif_spi_do[] = {GPIO10};
+static const unsigned xrx300_pins_usif_spi_clk[] = {GPIO19};
+static const unsigned xrx300_pins_usif_spi_cs0[] = {GPIO14};
+
+static const unsigned xrx300_pins_stp[] = {GPIO4, GPIO5, GPIO6};
+static const unsigned xrx300_pins_mdio[] = {GPIO42, GPIO43};
+
+static const unsigned xrx300_pins_dfe_led0[] = {GPIO4};
+static const unsigned xrx300_pins_dfe_led1[] = {GPIO5};
+
+static const unsigned xrx300_pins_ephy0_led0[] = {GPIO5};
+static const unsigned xrx300_pins_ephy0_led1[] = {GPIO8};
+static const unsigned xrx300_pins_ephy1_led0[] = {GPIO14};
+static const unsigned xrx300_pins_ephy1_led1[] = {GPIO19};
+
+static const unsigned xrx300_pins_nand_ale[] = {GPIO13};
+static const unsigned xrx300_pins_nand_cs1[] = {GPIO23};
+static const unsigned xrx300_pins_nand_cle[] = {GPIO24};
+static const unsigned xrx300_pins_nand_rdy[] = {GPIO48};
+static const unsigned xrx300_pins_nand_rd[] = {GPIO49};
+static const unsigned xrx300_pins_nand_d1[] = {GPIO50};
+static const unsigned xrx300_pins_nand_d0[] = {GPIO51};
+static const unsigned xrx300_pins_nand_d2[] = {GPIO52};
+static const unsigned xrx300_pins_nand_d7[] = {GPIO53};
+static const unsigned xrx300_pins_nand_d6[] = {GPIO54};
+static const unsigned xrx300_pins_nand_d5[] = {GPIO55};
+static const unsigned xrx300_pins_nand_d4[] = {GPIO56};
+static const unsigned xrx300_pins_nand_d3[] = {GPIO57};
+static const unsigned xrx300_pins_nand_cs0[] = {GPIO58};
+static const unsigned xrx300_pins_nand_wr[] = {GPIO59};
+static const unsigned xrx300_pins_nand_wp[] = {GPIO60};
+static const unsigned xrx300_pins_nand_se[] = {GPIO61};
+
+static const unsigned xrx300_pins_spi_di[] = {GPIO16};
+static const unsigned xrx300_pins_spi_do[] = {GPIO17};
+static const unsigned xrx300_pins_spi_clk[] = {GPIO18};
+static const unsigned xrx300_pins_spi_cs1[] = {GPIO15};
+/* SPI_CS2 is not available on xrX300 */
+/* SPI_CS3 is not available on xrX300 */
+static const unsigned xrx300_pins_spi_cs4[] = {GPIO10};
+/* SPI_CS5 is not available on xrX300 */
+static const unsigned xrx300_pins_spi_cs6[] = {GPIO11};
+
+/* CLKOUT0 is not available on xrX300 */
+/* CLKOUT1 is not available on xrX300 */
+static const unsigned xrx300_pins_clkout2[] = {GPIO3};
+
+static const struct ltq_pin_group xrx300_grps[] = {
+       GRP_MUX("exin0", EXIN, xrx300_pins_exin0),
+       GRP_MUX("exin1", EXIN, xrx300_pins_exin1),
+       GRP_MUX("exin2", EXIN, xrx300_pins_exin2),
+       GRP_MUX("exin4", EXIN, xrx300_pins_exin4),
+       GRP_MUX("exin5", EXIN, xrx300_pins_exin5),
+       GRP_MUX("nand ale", EBU, xrx300_pins_nand_ale),
+       GRP_MUX("nand cs1", EBU, xrx300_pins_nand_cs1),
+       GRP_MUX("nand cle", EBU, xrx300_pins_nand_cle),
+       GRP_MUX("nand rdy", EBU, xrx300_pins_nand_rdy),
+       GRP_MUX("nand rd", EBU, xrx300_pins_nand_rd),
+       GRP_MUX("nand d1", EBU, xrx300_pins_nand_d1),
+       GRP_MUX("nand d0", EBU, xrx300_pins_nand_d0),
+       GRP_MUX("nand d2", EBU, xrx300_pins_nand_d2),
+       GRP_MUX("nand d7", EBU, xrx300_pins_nand_d7),
+       GRP_MUX("nand d6", EBU, xrx300_pins_nand_d6),
+       GRP_MUX("nand d5", EBU, xrx300_pins_nand_d5),
+       GRP_MUX("nand d4", EBU, xrx300_pins_nand_d4),
+       GRP_MUX("nand d3", EBU, xrx300_pins_nand_d3),
+       GRP_MUX("nand cs0", EBU, xrx300_pins_nand_cs0),
+       GRP_MUX("nand wr", EBU, xrx300_pins_nand_wr),
+       GRP_MUX("nand wp", EBU, xrx300_pins_nand_wp),
+       GRP_MUX("nand se", EBU, xrx300_pins_nand_se),
+       GRP_MUX("spi_di", SPI, xrx300_pins_spi_di),
+       GRP_MUX("spi_do", SPI, xrx300_pins_spi_do),
+       GRP_MUX("spi_clk", SPI, xrx300_pins_spi_clk),
+       GRP_MUX("spi_cs1", SPI, xrx300_pins_spi_cs1),
+       GRP_MUX("spi_cs4", SPI, xrx300_pins_spi_cs4),
+       GRP_MUX("spi_cs6", SPI, xrx300_pins_spi_cs6),
+       GRP_MUX("usif uart_rx", USIF, xrx300_pins_usif_uart_rx),
+       GRP_MUX("usif uart_tx", USIF, xrx300_pins_usif_uart_tx),
+       GRP_MUX("usif spi_di", USIF, xrx300_pins_usif_spi_di),
+       GRP_MUX("usif spi_do", USIF, xrx300_pins_usif_spi_do),
+       GRP_MUX("usif spi_clk", USIF, xrx300_pins_usif_spi_clk),
+       GRP_MUX("usif spi_cs0", USIF, xrx300_pins_usif_spi_cs0),
+       GRP_MUX("stp", STP, xrx300_pins_stp),
+       GRP_MUX("clkout2", CGU, xrx300_pins_clkout2),
+       GRP_MUX("mdio", MDIO, xrx300_pins_mdio),
+       GRP_MUX("dfe led0", DFE, xrx300_pins_dfe_led0),
+       GRP_MUX("dfe led1", DFE, xrx300_pins_dfe_led1),
+       GRP_MUX("ephy0 led0", GPHY, xrx300_pins_ephy0_led0),
+       GRP_MUX("ephy0 led1", GPHY, xrx300_pins_ephy0_led1),
+       GRP_MUX("ephy1 led0", GPHY, xrx300_pins_ephy1_led0),
+       GRP_MUX("ephy1 led1", GPHY, xrx300_pins_ephy1_led1),
+};
+
+static const char * const xrx300_spi_grps[] = {"spi_di", "spi_do",
+                                               "spi_clk", "spi_cs1",
+                                               "spi_cs4", "spi_cs6"};
+static const char * const xrx300_cgu_grps[] = {"clkout2"};
+static const char * const xrx300_ebu_grps[] = {"nand ale", "nand cs1",
+                                               "nand cle", "nand rdy",
+                                               "nand rd", "nand d1",
+                                               "nand d0", "nand d2",
+                                               "nand d7", "nand d6",
+                                               "nand d5", "nand d4",
+                                               "nand d3", "nand cs0",
+                                               "nand wr", "nand wp",
+                                               "nand se"};
+static const char * const xrx300_exin_grps[] = {"exin0", "exin1", "exin2",
+                                               "exin4", "exin5"};
+static const char * const xrx300_usif_grps[] = {"usif uart_rx", "usif uart_tx",
+                                               "usif spi_di", "usif spi_do",
+                                               "usif spi_clk", "usif spi_cs0"};
+static const char * const xrx300_stp_grps[] = {"stp"};
+static const char * const xrx300_mdio_grps[] = {"mdio"};
+static const char * const xrx300_dfe_grps[] = {"dfe led0", "dfe led1"};
+static const char * const xrx300_gphy_grps[] = {"ephy0 led0", "ephy0 led1",
+                                               "ephy1 led0", "ephy1 led1"};
+
+static const struct ltq_pmx_func xrx300_funcs[] = {
+       {"spi",         ARRAY_AND_SIZE(xrx300_spi_grps)},
+       {"usif",        ARRAY_AND_SIZE(xrx300_usif_grps)},
+       {"cgu",         ARRAY_AND_SIZE(xrx300_cgu_grps)},
+       {"exin",        ARRAY_AND_SIZE(xrx300_exin_grps)},
+       {"stp",         ARRAY_AND_SIZE(xrx300_stp_grps)},
+       {"ebu",         ARRAY_AND_SIZE(xrx300_ebu_grps)},
+       {"mdio",        ARRAY_AND_SIZE(xrx300_mdio_grps)},
+       {"dfe",         ARRAY_AND_SIZE(xrx300_dfe_grps)},
+       {"ephy",        ARRAY_AND_SIZE(xrx300_gphy_grps)},
+};
+
 /* ---------  pinconf related code --------- */
 static int xway_pinconf_get(struct pinctrl_dev *pctldev,
                                unsigned pin,
@@ -676,6 +1563,10 @@ static int xway_gpio_dir_out(struct gpio_chip *chip, unsigned int pin, int val)
 {
        struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev);
 
+       if (PORT(pin) == PORT3)
+               gpio_setbit(info->membase[0], GPIO3_OD, PORT_PIN(pin));
+       else
+               gpio_setbit(info->membase[0], GPIO_OD(pin), PORT_PIN(pin));
        gpio_setbit(info->membase[0], GPIO_DIR(pin), PORT_PIN(pin));
        xway_gpio_set(chip, pin, val);
 
@@ -695,10 +1586,7 @@ static struct gpio_chip xway_chip = {
 
 
 /* --------- register the pinctrl layer --------- */
-static const unsigned xway_exin_pin_map[] = {GPIO0, GPIO1, GPIO2, GPIO39, GPIO46, GPIO9};
-static const unsigned ase_exin_pins_map[] = {GPIO6, GPIO29, GPIO0};
-
-static struct pinctrl_xway_soc {
+struct pinctrl_xway_soc {
        int pin_count;
        const struct ltq_mfp_pin *mfp;
        const struct ltq_pin_group *grps;
@@ -707,22 +1595,54 @@ static struct pinctrl_xway_soc {
        unsigned int num_funcs;
        const unsigned *exin;
        unsigned int num_exin;
-} soc_cfg[] = {
-       /* legacy xway */
-       {XWAY_MAX_PIN, xway_mfp,
-               xway_grps, ARRAY_SIZE(xway_grps),
-               danube_funcs, ARRAY_SIZE(danube_funcs),
-               xway_exin_pin_map, 3},
-       /* xway xr9 series */
-       {XR9_MAX_PIN, xway_mfp,
-               xway_grps, ARRAY_SIZE(xway_grps),
-               xrx_funcs, ARRAY_SIZE(xrx_funcs),
-               xway_exin_pin_map, 6},
-       /* xway ase series */
-       {XWAY_MAX_PIN, ase_mfp,
-               ase_grps, ARRAY_SIZE(ase_grps),
-               ase_funcs, ARRAY_SIZE(ase_funcs),
-               ase_exin_pins_map, 3},
+};
+
+/* xway xr9 series (DEPRECATED: Use XWAY xRX100/xRX200 Family) */
+static struct pinctrl_xway_soc xr9_pinctrl = {
+       XR9_MAX_PIN, xway_mfp,
+       xway_grps, ARRAY_SIZE(xway_grps),
+       xrx_funcs, ARRAY_SIZE(xrx_funcs),
+       xway_exin_pin_map, 6
+};
+
+/* XWAY AMAZON Family */
+static struct pinctrl_xway_soc ase_pinctrl = {
+       ASE_MAX_PIN, ase_mfp,
+       ase_grps, ARRAY_SIZE(ase_grps),
+       ase_funcs, ARRAY_SIZE(ase_funcs),
+       ase_exin_pin_map, 3
+};
+
+/* XWAY DANUBE Family */
+static struct pinctrl_xway_soc danube_pinctrl = {
+       DANUBE_MAX_PIN, danube_mfp,
+       danube_grps, ARRAY_SIZE(danube_grps),
+       danube_funcs, ARRAY_SIZE(danube_funcs),
+       danube_exin_pin_map, 3
+};
+
+/* XWAY xRX100 Family */
+static struct pinctrl_xway_soc xrx100_pinctrl = {
+       XRX100_MAX_PIN, xrx100_mfp,
+       xrx100_grps, ARRAY_SIZE(xrx100_grps),
+       xrx100_funcs, ARRAY_SIZE(xrx100_funcs),
+       xrx100_exin_pin_map, 6
+};
+
+/* XWAY xRX200 Family */
+static struct pinctrl_xway_soc xrx200_pinctrl = {
+       XRX200_MAX_PIN, xrx200_mfp,
+       xrx200_grps, ARRAY_SIZE(xrx200_grps),
+       xrx200_funcs, ARRAY_SIZE(xrx200_funcs),
+       xrx200_exin_pin_map, 6
+};
+
+/* XWAY xRX300 Family */
+static struct pinctrl_xway_soc xrx300_pinctrl = {
+       XRX300_MAX_PIN, xrx300_mfp,
+       xrx300_grps, ARRAY_SIZE(xrx300_grps),
+       xrx300_funcs, ARRAY_SIZE(xrx300_funcs),
+       xrx300_exin_pin_map, 5
 };
 
 static struct pinctrl_gpio_range xway_gpio_range = {
@@ -731,9 +1651,14 @@ static struct pinctrl_gpio_range xway_gpio_range = {
 };
 
 static const struct of_device_id xway_match[] = {
-       { .compatible = "lantiq,pinctrl-xway", .data = &soc_cfg[0]},
-       { .compatible = "lantiq,pinctrl-xr9", .data = &soc_cfg[1]},
-       { .compatible = "lantiq,pinctrl-ase", .data = &soc_cfg[2]},
+       { .compatible = "lantiq,pinctrl-xway", .data = &danube_pinctrl}, /*DEPRECATED*/
+       { .compatible = "lantiq,pinctrl-xr9", .data = &xr9_pinctrl}, /*DEPRECATED*/
+       { .compatible = "lantiq,pinctrl-ase", .data = &ase_pinctrl}, /*DEPRECATED*/
+       { .compatible = "lantiq,ase-pinctrl", .data = &ase_pinctrl},
+       { .compatible = "lantiq,danube-pinctrl", .data = &danube_pinctrl},
+       { .compatible = "lantiq,xrx100-pinctrl", .data = &xrx100_pinctrl},
+       { .compatible = "lantiq,xrx200-pinctrl", .data = &xrx200_pinctrl},
+       { .compatible = "lantiq,xrx300-pinctrl", .data = &xrx300_pinctrl},
        {},
 };
 MODULE_DEVICE_TABLE(of, xway_match);
@@ -755,7 +1680,7 @@ static int pinmux_xway_probe(struct platform_device *pdev)
        if (match)
                xway_soc = (const struct pinctrl_xway_soc *) match->data;
        else
-               xway_soc = &soc_cfg[0];
+               xway_soc = &danube_pinctrl;
 
        /* find out how many pads we have */
        xway_chip.ngpio = xway_soc->pin_count;
diff --git a/drivers/pinctrl/pxa/Kconfig b/drivers/pinctrl/pxa/Kconfig
new file mode 100644 (file)
index 0000000..990667f
--- /dev/null
@@ -0,0 +1,17 @@
+if (ARCH_PXA || COMPILE_TEST)
+
+config PINCTRL_PXA
+       bool
+       select PINMUX
+       select PINCONF
+       select GENERIC_PINCONF
+
+config PINCTRL_PXA27X
+       tristate "Marvell PXA27x pin controller driver"
+       select PINCTRL_PXA
+       default y if PXA27x
+       help
+         This is the pinctrl, pinmux, pinconf driver for the Marvell
+         PXA2xx block found in the pxa25x and pxa27x platforms.
+
+endif
diff --git a/drivers/pinctrl/pxa/Makefile b/drivers/pinctrl/pxa/Makefile
new file mode 100644 (file)
index 0000000..f1d56af
--- /dev/null
@@ -0,0 +1,2 @@
+# Marvell PXA pin control drivers
+obj-$(CONFIG_PINCTRL_PXA27X)   += pinctrl-pxa2xx.o pinctrl-pxa27x.o
diff --git a/drivers/pinctrl/pxa/pinctrl-pxa27x.c b/drivers/pinctrl/pxa/pinctrl-pxa27x.c
new file mode 100644 (file)
index 0000000..2e2c370
--- /dev/null
@@ -0,0 +1,566 @@
+/*
+ * Marvell PXA27x family pin control
+ *
+ * Copyright (C) 2015 Robert Jarzmik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-pxa2xx.h"
+
+static const struct pxa_desc_pin pxa27x_pins[] = {
+       PXA_GPIO_ONLY_PIN(PXA_PINCTRL_PIN(0)),
+       PXA_GPIO_ONLY_PIN(PXA_PINCTRL_PIN(1)),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(9),
+                    PXA_FUNCTION(0, 3, "FFCTS"),
+                    PXA_FUNCTION(1, 1, "HZ_CLK"),
+                    PXA_FUNCTION(1, 3, "CHOUT<0>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(10),
+                    PXA_FUNCTION(0, 1, "FFDCD"),
+                    PXA_FUNCTION(0, 3, "USB_P3_5"),
+                    PXA_FUNCTION(1, 1, "HZ_CLK"),
+                    PXA_FUNCTION(1, 3, "CHOUT<1>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(11),
+                    PXA_FUNCTION(0, 1, "EXT_SYNC<0>"),
+                    PXA_FUNCTION(0, 2, "SSPRXD2"),
+                    PXA_FUNCTION(0, 3, "USB_P3_1"),
+                    PXA_FUNCTION(1, 1, "CHOUT<0>"),
+                    PXA_FUNCTION(1, 1, "PWM_OUT<2>"),
+                    PXA_FUNCTION(1, 3, "48_MHz")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(12),
+                    PXA_FUNCTION(0, 1, "EXT_SYNC<1>"),
+                    PXA_FUNCTION(0, 2, "CIF_DD<7>"),
+                    PXA_FUNCTION(1, 1, "CHOUT<1>"),
+                    PXA_FUNCTION(1, 1, "PWM_OUT<3>"),
+                    PXA_FUNCTION(1, 3, "48_MHz")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(13),
+                    PXA_FUNCTION(0, 1, "CLK_EXT"),
+                    PXA_FUNCTION(0, 2, "KP_DKIN<7>"),
+                    PXA_FUNCTION(0, 3, "KP_MKIN<7>"),
+                    PXA_FUNCTION(1, 1, "SSPTXD2")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(14),
+                    PXA_FUNCTION(0, 1, "L_VSYNC"),
+                    PXA_FUNCTION(0, 2, "SSPSFRM2"),
+                    PXA_FUNCTION(1, 1, "SSPSFRM2"),
+                    PXA_FUNCTION(1, 3, "UCLK")),
+       PXA_GPIO_ONLY_PIN(PXA_PINCTRL_PIN(15)),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(16),
+                    PXA_FUNCTION(0, 1, "KP_MKIN<5>"),
+                    PXA_FUNCTION(1, 2, "PWM_OUT<0>"),
+                    PXA_FUNCTION(1, 3, "FFTXD")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(17),
+                    PXA_FUNCTION(0, 1, "KP_MKIN<6>"),
+                    PXA_FUNCTION(0, 2, "CIF_DD<6>"),
+                    PXA_FUNCTION(1, 2, "PWM_OUT<1>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(18),
+                    PXA_FUNCTION(0, 1, "RDY")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(19),
+                    PXA_FUNCTION(0, 1, "SSPSCLK2"),
+                    PXA_FUNCTION(0, 3, "FFRXD"),
+                    PXA_FUNCTION(1, 1, "SSPSCLK2"),
+                    PXA_FUNCTION(1, 2, "L_CS"),
+                    PXA_FUNCTION(1, 3, "nURST")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(20),
+                    PXA_FUNCTION(0, 1, "DREQ<0>"),
+                    PXA_FUNCTION(0, 2, "MBREQ"),
+                    PXA_FUNCTION(1, 1, "nSDCS<2>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(21),
+                    PXA_FUNCTION(1, 1, "nSDCS<3>"),
+                    PXA_FUNCTION(1, 2, "DVAL<0>"),
+                    PXA_FUNCTION(1, 3, "MBGNT")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(22),
+                    PXA_FUNCTION(0, 1, "SSPEXTCLK2"),
+                    PXA_FUNCTION(0, 2, "SSPSCLKEN2"),
+                    PXA_FUNCTION(0, 3, "SSPSCLK2"),
+                    PXA_FUNCTION(1, 1, "KP_MKOUT<7>"),
+                    PXA_FUNCTION(1, 2, "SSPSYSCLK2"),
+                    PXA_FUNCTION(1, 3, "SSPSCLK2")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(23),
+                    PXA_FUNCTION(0, 2, "SSPSCLK"),
+                    PXA_FUNCTION(1, 1, "CIF_MCLK"),
+                    PXA_FUNCTION(1, 1, "SSPSCLK")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(24),
+                    PXA_FUNCTION(0, 1, "CIF_FV"),
+                    PXA_FUNCTION(0, 2, "SSPSFRM"),
+                    PXA_FUNCTION(1, 1, "CIF_FV"),
+                    PXA_FUNCTION(1, 2, "SSPSFRM")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(25),
+                    PXA_FUNCTION(0, 1, "CIF_LV"),
+                    PXA_FUNCTION(1, 1, "CIF_LV"),
+                    PXA_FUNCTION(1, 2, "SSPTXD")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(26),
+                    PXA_FUNCTION(0, 1, "SSPRXD"),
+                    PXA_FUNCTION(0, 2, "CIF_PCLK"),
+                    PXA_FUNCTION(0, 3, "FFCTS")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(27),
+                    PXA_FUNCTION(0, 1, "SSPEXTCLK"),
+                    PXA_FUNCTION(0, 2, "SSPSCLKEN"),
+                    PXA_FUNCTION(0, 3, "CIF_DD<0>"),
+                    PXA_FUNCTION(1, 1, "SSPSYSCLK"),
+                    PXA_FUNCTION(1, 3, "FFRTS")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(28),
+                    PXA_FUNCTION(0, 1, "AC97_BITCLK"),
+                    PXA_FUNCTION(0, 2, "I2S_BITCLK"),
+                    PXA_FUNCTION(0, 3, "SSPSFRM"),
+                    PXA_FUNCTION(1, 1, "I2S_BITCLK"),
+                    PXA_FUNCTION(1, 3, "SSPSFRM")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(29),
+                    PXA_FUNCTION(0, 1, "AC97_SDATA_IN_0"),
+                    PXA_FUNCTION(0, 2, "I2S_SDATA_IN"),
+                    PXA_FUNCTION(0, 3, "SSPSCLK"),
+                    PXA_FUNCTION(1, 1, "SSPRXD2"),
+                    PXA_FUNCTION(1, 3, "SSPSCLK")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(30),
+                    PXA_FUNCTION(1, 1, "I2S_SDATA_OUT"),
+                    PXA_FUNCTION(1, 2, "AC97_SDATA_OUT"),
+                    PXA_FUNCTION(1, 3, "USB_P3_2")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(31),
+                    PXA_FUNCTION(1, 1, "I2S_SYNC"),
+                    PXA_FUNCTION(1, 2, "AC97_SYNC"),
+                    PXA_FUNCTION(1, 3, "USB_P3_6")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(32),
+                    PXA_FUNCTION(1, 1, "MSSCLK"),
+                    PXA_FUNCTION(1, 2, "MMCLK")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(33),
+                    PXA_FUNCTION(0, 1, "FFRXD"),
+                    PXA_FUNCTION(0, 2, "FFDSR"),
+                    PXA_FUNCTION(1, 1, "DVAL<1>"),
+                    PXA_FUNCTION(1, 2, "nCS<5>"),
+                    PXA_FUNCTION(1, 3, "MBGNT")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(34),
+                    PXA_FUNCTION(0, 1, "FFRXD"),
+                    PXA_FUNCTION(0, 2, "KP_MKIN<3>"),
+                    PXA_FUNCTION(0, 3, "SSPSCLK3"),
+                    PXA_FUNCTION(1, 1, "USB_P2_2"),
+                    PXA_FUNCTION(1, 3, "SSPSCLK3")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(35),
+                    PXA_FUNCTION(0, 1, "FFCTS"),
+                    PXA_FUNCTION(0, 2, "USB_P2_1"),
+                    PXA_FUNCTION(0, 3, "SSPSFRM3"),
+                    PXA_FUNCTION(1, 2, "KP_MKOUT<6>"),
+                    PXA_FUNCTION(1, 3, "SSPTXD3")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(36),
+                    PXA_FUNCTION(0, 1, "FFDCD"),
+                    PXA_FUNCTION(0, 2, "SSPSCLK2"),
+                    PXA_FUNCTION(0, 3, "KP_MKIN<7>"),
+                    PXA_FUNCTION(1, 1, "USB_P2_4"),
+                    PXA_FUNCTION(1, 2, "SSPSCLK2")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(37),
+                    PXA_FUNCTION(0, 1, "FFDSR"),
+                    PXA_FUNCTION(0, 2, "SSPSFRM2"),
+                    PXA_FUNCTION(0, 3, "KP_MKIN<3>"),
+                    PXA_FUNCTION(1, 1, "USB_P2_8"),
+                    PXA_FUNCTION(1, 2, "SSPSFRM2"),
+                    PXA_FUNCTION(1, 3, "FFTXD")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(38),
+                    PXA_FUNCTION(0, 1, "FFRI"),
+                    PXA_FUNCTION(0, 2, "KP_MKIN<4>"),
+                    PXA_FUNCTION(0, 3, "USB_P2_3"),
+                    PXA_FUNCTION(1, 1, "SSPTXD3"),
+                    PXA_FUNCTION(1, 2, "SSPTXD2"),
+                    PXA_FUNCTION(1, 3, "PWM_OUT<0>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(39),
+                    PXA_FUNCTION(0, 1, "KP_MKIN<4>"),
+                    PXA_FUNCTION(0, 3, "SSPSFRM3"),
+                    PXA_FUNCTION(1, 1, "USB_P2_6"),
+                    PXA_FUNCTION(1, 2, "FFTXD"),
+                    PXA_FUNCTION(1, 3, "SSPSFRM3")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(40),
+                    PXA_FUNCTION(0, 1, "SSPRXD2"),
+                    PXA_FUNCTION(0, 3, "USB_P2_5"),
+                    PXA_FUNCTION(1, 1, "KP_MKOUT<6>"),
+                    PXA_FUNCTION(1, 2, "FFDTR"),
+                    PXA_FUNCTION(1, 3, "SSPSCLK3")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(41),
+                    PXA_FUNCTION(0, 1, "FFRXD"),
+                    PXA_FUNCTION(0, 2, "USB_P2_7"),
+                    PXA_FUNCTION(0, 3, "SSPRXD3"),
+                    PXA_FUNCTION(1, 1, "KP_MKOUT<7>"),
+                    PXA_FUNCTION(1, 2, "FFRTS")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(42),
+                    PXA_FUNCTION(0, 1, "BTRXD"),
+                    PXA_FUNCTION(0, 2, "ICP_RXD"),
+                    PXA_FUNCTION(1, 3, "CIF_MCLK")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(43),
+                    PXA_FUNCTION(0, 3, "CIF_FV"),
+                    PXA_FUNCTION(1, 1, "ICP_TXD"),
+                    PXA_FUNCTION(1, 2, "BTTXD"),
+                    PXA_FUNCTION(1, 3, "CIF_FV")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(44),
+                    PXA_FUNCTION(0, 1, "BTCTS"),
+                    PXA_FUNCTION(0, 3, "CIF_LV"),
+                    PXA_FUNCTION(1, 3, "CIF_LV")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(45),
+                    PXA_FUNCTION(0, 3, "CIF_PCLK"),
+                    PXA_FUNCTION(1, 1, "AC97_SYSCLK"),
+                    PXA_FUNCTION(1, 2, "BTRTS"),
+                    PXA_FUNCTION(1, 3, "SSPSYSCLK3")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(46),
+                    PXA_FUNCTION(0, 1, "ICP_RXD"),
+                    PXA_FUNCTION(0, 2, "STD_RXD"),
+                    PXA_FUNCTION(1, 2, "PWM_OUT<2>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(47),
+                    PXA_FUNCTION(0, 1, "CIF_DD<0>"),
+                    PXA_FUNCTION(1, 1, "STD_TXD"),
+                    PXA_FUNCTION(1, 2, "ICP_TXD"),
+                    PXA_FUNCTION(1, 3, "PWM_OUT<3>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(48),
+                    PXA_FUNCTION(0, 1, "CIF_DD<5>"),
+                    PXA_FUNCTION(1, 1, "BB_OB_DAT<1>"),
+                    PXA_FUNCTION(1, 2, "nPOE")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(49),
+                    PXA_FUNCTION(1, 2, "nPWE")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(50),
+                    PXA_FUNCTION(0, 1, "CIF_DD<3>"),
+                    PXA_FUNCTION(0, 3, "SSPSCLK2"),
+                    PXA_FUNCTION(1, 1, "BB_OB_DAT<2>"),
+                    PXA_FUNCTION(1, 2, "nPIOR"),
+                    PXA_FUNCTION(1, 3, "SSPSCLK2")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(51),
+                    PXA_FUNCTION(0, 1, "CIF_DD<2>"),
+                    PXA_FUNCTION(1, 1, "BB_OB_DAT<3>"),
+                    PXA_FUNCTION(1, 2, "nPIOW")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(52),
+                    PXA_FUNCTION(0, 1, "CIF_DD<4>"),
+                    PXA_FUNCTION(0, 2, "SSPSCLK3"),
+                    PXA_FUNCTION(1, 1, "BB_OB_CLK"),
+                    PXA_FUNCTION(1, 2, "SSPSCLK3")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(53),
+                    PXA_FUNCTION(0, 1, "FFRXD"),
+                    PXA_FUNCTION(0, 2, "USB_P2_3"),
+                    PXA_FUNCTION(1, 1, "BB_OB_STB"),
+                    PXA_FUNCTION(1, 2, "CIF_MCLK"),
+                    PXA_FUNCTION(1, 3, "SSPSYSCLK")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(54),
+                    PXA_FUNCTION(0, 2, "BB_OB_WAIT"),
+                    PXA_FUNCTION(0, 3, "CIF_PCLK"),
+                    PXA_FUNCTION(1, 2, "nPCE<2>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(55),
+                    PXA_FUNCTION(0, 1, "CIF_DD<1>"),
+                    PXA_FUNCTION(0, 2, "BB_IB_DAT<1>"),
+                    PXA_FUNCTION(1, 2, "nPREG")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(56),
+                    PXA_FUNCTION(0, 1, "nPWAIT"),
+                    PXA_FUNCTION(0, 2, "BB_IB_DAT<2>"),
+                    PXA_FUNCTION(1, 1, "USB_P3_4")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(57),
+                    PXA_FUNCTION(0, 1, "nIOS16"),
+                    PXA_FUNCTION(0, 2, "BB_IB_DAT<3>"),
+                    PXA_FUNCTION(1, 3, "SSPTXD")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(58),
+                    PXA_FUNCTION(0, 2, "LDD<0>"),
+                    PXA_FUNCTION(1, 2, "LDD<0>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(59),
+                    PXA_FUNCTION(0, 2, "LDD<1>"),
+                    PXA_FUNCTION(1, 2, "LDD<1>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(60),
+                    PXA_FUNCTION(0, 2, "LDD<2>"),
+                    PXA_FUNCTION(1, 2, "LDD<2>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(61),
+                    PXA_FUNCTION(0, 2, "LDD<3>"),
+                    PXA_FUNCTION(1, 2, "LDD<3>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(62),
+                    PXA_FUNCTION(0, 2, "LDD<4>"),
+                    PXA_FUNCTION(1, 2, "LDD<4>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(63),
+                    PXA_FUNCTION(0, 2, "LDD<5>"),
+                    PXA_FUNCTION(1, 2, "LDD<5>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(64),
+                    PXA_FUNCTION(0, 2, "LDD<6>"),
+                    PXA_FUNCTION(1, 2, "LDD<6>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(65),
+                    PXA_FUNCTION(0, 2, "LDD<7>"),
+                    PXA_FUNCTION(1, 2, "LDD<7>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(66),
+                    PXA_FUNCTION(0, 2, "LDD<8>"),
+                    PXA_FUNCTION(1, 2, "LDD<8>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(67),
+                    PXA_FUNCTION(0, 2, "LDD<9>"),
+                    PXA_FUNCTION(1, 2, "LDD<9>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(68),
+                    PXA_FUNCTION(0, 2, "LDD<10>"),
+                    PXA_FUNCTION(1, 2, "LDD<10>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(69),
+                    PXA_FUNCTION(0, 2, "LDD<11>"),
+                    PXA_FUNCTION(1, 2, "LDD<11>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(70),
+                    PXA_FUNCTION(0, 2, "LDD<12>"),
+                    PXA_FUNCTION(1, 2, "LDD<12>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(71),
+                    PXA_FUNCTION(0, 2, "LDD<13>"),
+                    PXA_FUNCTION(1, 2, "LDD<13>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(72),
+                    PXA_FUNCTION(0, 2, "LDD<14>"),
+                    PXA_FUNCTION(1, 2, "LDD<14>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(73),
+                    PXA_FUNCTION(0, 2, "LDD<15>"),
+                    PXA_FUNCTION(1, 2, "LDD<15>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(74),
+                    PXA_FUNCTION(1, 2, "L_FCLK_RD")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(75),
+                    PXA_FUNCTION(1, 2, "L_LCLK_A0")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(76),
+                    PXA_FUNCTION(1, 2, "L_PCLK_WR")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(77),
+                    PXA_FUNCTION(1, 2, "L_BIAS")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(78),
+                    PXA_FUNCTION(1, 1, "nPCE<2>"),
+                    PXA_FUNCTION(1, 2, "nCS<2>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(79),
+                    PXA_FUNCTION(1, 1, "PSKTSEL"),
+                    PXA_FUNCTION(1, 2, "nCS<3>"),
+                    PXA_FUNCTION(1, 3, "PWM_OUT<2>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(80),
+                    PXA_FUNCTION(0, 1, "DREQ<1>"),
+                    PXA_FUNCTION(0, 2, "MBREQ"),
+                    PXA_FUNCTION(1, 2, "nCS<4>"),
+                    PXA_FUNCTION(1, 3, "PWM_OUT<3>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(81),
+                    PXA_FUNCTION(0, 2, "CIF_DD<0>"),
+                    PXA_FUNCTION(1, 1, "SSPTXD3"),
+                    PXA_FUNCTION(1, 2, "BB_OB_DAT<0>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(82),
+                    PXA_FUNCTION(0, 1, "SSPRXD3"),
+                    PXA_FUNCTION(0, 2, "BB_IB_DAT<0>"),
+                    PXA_FUNCTION(0, 3, "CIF_DD<5>"),
+                    PXA_FUNCTION(1, 3, "FFDTR")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(83),
+                    PXA_FUNCTION(0, 1, "SSPSFRM3"),
+                    PXA_FUNCTION(0, 2, "BB_IB_CLK"),
+                    PXA_FUNCTION(0, 3, "CIF_DD<5>"),
+                    PXA_FUNCTION(1, 1, "SSPSFRM3"),
+                    PXA_FUNCTION(1, 2, "FFTXD"),
+                    PXA_FUNCTION(1, 3, "FFRTS")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(84),
+                    PXA_FUNCTION(0, 1, "SSPCLK3"),
+                    PXA_FUNCTION(0, 2, "BB_IB_STB"),
+                    PXA_FUNCTION(0, 3, "CIF_FV"),
+                    PXA_FUNCTION(1, 1, "SSPCLK3"),
+                    PXA_FUNCTION(1, 3, "CIF_FV")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(85),
+                    PXA_FUNCTION(0, 1, "FFRXD"),
+                    PXA_FUNCTION(0, 2, "DREQ<2>"),
+                    PXA_FUNCTION(0, 3, "CIF_LV"),
+                    PXA_FUNCTION(1, 1, "nPCE<1>"),
+                    PXA_FUNCTION(1, 2, "BB_IB_WAIT"),
+                    PXA_FUNCTION(1, 3, "CIF_LV")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(86),
+                    PXA_FUNCTION(0, 1, "SSPRXD2"),
+                    PXA_FUNCTION(0, 2, "LDD<16>"),
+                    PXA_FUNCTION(0, 3, "USB_P3_5"),
+                    PXA_FUNCTION(1, 1, "nPCE<1>"),
+                    PXA_FUNCTION(1, 2, "LDD<16>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(87),
+                    PXA_FUNCTION(0, 1, "nPCE<2>"),
+                    PXA_FUNCTION(0, 2, "LDD<17>"),
+                    PXA_FUNCTION(0, 3, "USB_P3_1"),
+                    PXA_FUNCTION(1, 1, "SSPTXD2"),
+                    PXA_FUNCTION(1, 2, "LDD<17>"),
+                    PXA_FUNCTION(1, 3, "SSPSFRM2")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(88),
+                    PXA_FUNCTION(0, 1, "USBHPWR<1>"),
+                    PXA_FUNCTION(0, 2, "SSPRXD2"),
+                    PXA_FUNCTION(0, 3, "SSPSFRM2"),
+                    PXA_FUNCTION(1, 2, "SSPTXD2"),
+                    PXA_FUNCTION(1, 3, "SSPSFRM2")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(89),
+                    PXA_FUNCTION(0, 1, "SSPRXD3"),
+                    PXA_FUNCTION(0, 3, "FFRI"),
+                    PXA_FUNCTION(1, 1, "AC97_SYSCLK"),
+                    PXA_FUNCTION(1, 2, "USBHPEN<1>"),
+                    PXA_FUNCTION(1, 3, "SSPTXD2")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(90),
+                    PXA_FUNCTION(0, 1, "KP_MKIN<5>"),
+                    PXA_FUNCTION(0, 3, "USB_P3_5"),
+                    PXA_FUNCTION(1, 1, "CIF_DD<4>"),
+                    PXA_FUNCTION(1, 2, "nURST")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(91),
+                    PXA_FUNCTION(0, 1, "KP_MKIN<6>"),
+                    PXA_FUNCTION(0, 3, "USB_P3_1"),
+                    PXA_FUNCTION(1, 1, "CIF_DD<5>"),
+                    PXA_FUNCTION(1, 2, "UCLK")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(92),
+                    PXA_FUNCTION(0, 1, "MMDAT<0>"),
+                    PXA_FUNCTION(1, 1, "MMDAT<0>"),
+                    PXA_FUNCTION(1, 2, "MSBS")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(93),
+                    PXA_FUNCTION(0, 1, "KP_DKIN<0>"),
+                    PXA_FUNCTION(0, 2, "CIF_DD<6>"),
+                    PXA_FUNCTION(1, 1, "AC97_SDATA_OUT")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(94),
+                    PXA_FUNCTION(0, 1, "KP_DKIN<1>"),
+                    PXA_FUNCTION(0, 2, "CIF_DD<5>"),
+                    PXA_FUNCTION(1, 1, "AC97_SYNC")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(95),
+                    PXA_FUNCTION(0, 1, "KP_DKIN<2>"),
+                    PXA_FUNCTION(0, 2, "CIF_DD<4>"),
+                    PXA_FUNCTION(0, 3, "KP_MKIN<6>"),
+                    PXA_FUNCTION(1, 1, "AC97_RESET_n")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(96),
+                    PXA_FUNCTION(0, 1, "KP_DKIN<3>"),
+                    PXA_FUNCTION(0, 2, "MBREQ"),
+                    PXA_FUNCTION(0, 3, "FFRXD"),
+                    PXA_FUNCTION(1, 2, "DVAL<1>"),
+                    PXA_FUNCTION(1, 3, "KP_MKOUT<6>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(97),
+                    PXA_FUNCTION(0, 1, "KP_DKIN<4>"),
+                    PXA_FUNCTION(0, 2, "DREQ<1>"),
+                    PXA_FUNCTION(0, 3, "KP_MKIN<3>"),
+                    PXA_FUNCTION(1, 2, "MBGNT")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(98),
+                    PXA_FUNCTION(0, 1, "KP_DKIN<5>"),
+                    PXA_FUNCTION(0, 2, "CIF_DD<0>"),
+                    PXA_FUNCTION(0, 3, "KP_MKIN<4>"),
+                    PXA_FUNCTION(1, 1, "AC97_SYSCLK"),
+                    PXA_FUNCTION(1, 3, "FFRTS")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(99),
+                    PXA_FUNCTION(0, 1, "KP_DKIN<6>"),
+                    PXA_FUNCTION(0, 2, "AC97_SDATA_IN_1"),
+                    PXA_FUNCTION(0, 3, "KP_MKIN<5>"),
+                    PXA_FUNCTION(1, 3, "FFTXD")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(100),
+                    PXA_FUNCTION(0, 1, "KP_MKIN<0>"),
+                    PXA_FUNCTION(0, 2, "DREQ<2>"),
+                    PXA_FUNCTION(0, 3, "FFCTS")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(101),
+                    PXA_FUNCTION(0, 1, "KP_MKIN<1>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(102),
+                    PXA_FUNCTION(0, 1, "KP_MKIN<2>"),
+                    PXA_FUNCTION(0, 3, "FFRXD"),
+                    PXA_FUNCTION(1, 1, "nPCE<1>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(103),
+                    PXA_FUNCTION(0, 1, "CIF_DD<3>"),
+                    PXA_FUNCTION(1, 2, "KP_MKOUT<0>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(104),
+                    PXA_FUNCTION(0, 1, "CIF_DD<2>"),
+                    PXA_FUNCTION(1, 1, "PSKTSEL"),
+                    PXA_FUNCTION(1, 2, "KP_MKOUT<1>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(105),
+                    PXA_FUNCTION(0, 1, "CIF_DD<1>"),
+                    PXA_FUNCTION(1, 1, "nPCE<2>"),
+                    PXA_FUNCTION(1, 2, "KP_MKOUT<2>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(106),
+                    PXA_FUNCTION(0, 1, "CIF_DD<9>"),
+                    PXA_FUNCTION(1, 2, "KP_MKOUT<3>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(107),
+                    PXA_FUNCTION(0, 1, "CIF_DD<8>"),
+                    PXA_FUNCTION(1, 2, "KP_MKOUT<4>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(108),
+                    PXA_FUNCTION(0, 1, "CIF_DD<7>"),
+                    PXA_FUNCTION(1, 1, "CHOUT<0>"),
+                    PXA_FUNCTION(1, 2, "KP_MKOUT<5>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(109),
+                    PXA_FUNCTION(0, 1, "MMDAT<1>"),
+                    PXA_FUNCTION(0, 2, "MSSDIO"),
+                    PXA_FUNCTION(1, 1, "MMDAT<1>"),
+                    PXA_FUNCTION(1, 2, "MSSDIO")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(110),
+                    PXA_FUNCTION(0, 1, "MMDAT<2>"),
+                    PXA_FUNCTION(1, 1, "MMDAT<2>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(111),
+                    PXA_FUNCTION(0, 1, "MMDAT<3>"),
+                    PXA_FUNCTION(1, 1, "MMDAT<3>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(112),
+                    PXA_FUNCTION(0, 1, "MMCMD"),
+                    PXA_FUNCTION(0, 2, "nMSINS"),
+                    PXA_FUNCTION(1, 1, "MMCMD")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(113),
+                    PXA_FUNCTION(0, 3, "USB_P3_3"),
+                    PXA_FUNCTION(1, 1, "I2S_SYSCLK"),
+                    PXA_FUNCTION(1, 2, "AC97_RESET_n")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(114),
+                    PXA_FUNCTION(0, 1, "CIF_DD<1>"),
+                    PXA_FUNCTION(1, 1, "UEN"),
+                    PXA_FUNCTION(1, 2, "UVS0")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(115),
+                    PXA_FUNCTION(0, 1, "DREQ<0>"),
+                    PXA_FUNCTION(0, 2, "CIF_DD<3>"),
+                    PXA_FUNCTION(0, 3, "MBREQ"),
+                    PXA_FUNCTION(1, 1, "UEN"),
+                    PXA_FUNCTION(1, 2, "nUVS1"),
+                    PXA_FUNCTION(1, 3, "PWM_OUT<1>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(116),
+                    PXA_FUNCTION(0, 1, "CIF_DD<2>"),
+                    PXA_FUNCTION(0, 2, "AC97_SDATA_IN_0"),
+                    PXA_FUNCTION(0, 3, "UDET"),
+                    PXA_FUNCTION(1, 1, "DVAL<0>"),
+                    PXA_FUNCTION(1, 2, "nUVS2"),
+                    PXA_FUNCTION(1, 3, "MBGNT")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(117),
+                    PXA_FUNCTION(0, 1, "SCL"),
+                    PXA_FUNCTION(1, 1, "SCL")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(118),
+                    PXA_FUNCTION(0, 1, "SDA"),
+                    PXA_FUNCTION(1, 1, "SDA")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(119),
+                    PXA_FUNCTION(0, 1, "USBHPWR<2>")),
+       PXA_GPIO_PIN(PXA_PINCTRL_PIN(120),
+                    PXA_FUNCTION(1, 2, "USBHPEN<2>")),
+};
+
+static int pxa27x_pinctrl_probe(struct platform_device *pdev)
+{
+       int ret, i;
+       void __iomem *base_af[8];
+       void __iomem *base_dir[4];
+       void __iomem *base_sleep[4];
+       struct resource *res;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base_af[0] = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base_af[0]))
+               return PTR_ERR(base_af[0]);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       base_dir[0] = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base_dir[0]))
+               return PTR_ERR(base_dir[0]);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+       base_dir[3] = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base_dir[3]))
+               return PTR_ERR(base_dir[3]);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+       base_sleep[0] = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base_sleep[0]))
+               return PTR_ERR(base_sleep[0]);
+
+       for (i = 0; i < ARRAY_SIZE(base_af); i++)
+               base_af[i] = base_af[0] + sizeof(base_af[0]) * i;
+       for (i = 0; i < 3; i++)
+               base_dir[i] = base_dir[0] + sizeof(base_dir[0]) * i;
+       for (i = 0; i < ARRAY_SIZE(base_sleep); i++)
+               base_sleep[i] = base_sleep[0] + sizeof(base_af[0]) * i;
+
+       ret = pxa2xx_pinctrl_init(pdev, pxa27x_pins, ARRAY_SIZE(pxa27x_pins),
+                                 base_af, base_dir, base_sleep);
+       return ret;
+}
+
+static const struct of_device_id pxa27x_pinctrl_match[] = {
+       { .compatible = "marvell,pxa27x-pinctrl", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, pxa27x_pinctrl_match);
+
+static struct platform_driver pxa27x_pinctrl_driver = {
+       .probe  = pxa27x_pinctrl_probe,
+       .driver = {
+               .name           = "pxa27x-pinctrl",
+               .of_match_table = pxa27x_pinctrl_match,
+       },
+};
+module_platform_driver(pxa27x_pinctrl_driver);
+
+MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");
+MODULE_DESCRIPTION("Marvell PXA27x pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pxa/pinctrl-pxa2xx.c b/drivers/pinctrl/pxa/pinctrl-pxa2xx.c
new file mode 100644 (file)
index 0000000..d90e205
--- /dev/null
@@ -0,0 +1,436 @@
+/*
+ * Marvell PXA2xx family pin control
+ *
+ * Copyright (C) 2015 Robert Jarzmik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ */
+
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "../pinctrl-utils.h"
+#include "pinctrl-pxa2xx.h"
+
+static int pxa2xx_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+       struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+       return pctl->ngroups;
+}
+
+static const char *pxa2xx_pctrl_get_group_name(struct pinctrl_dev *pctldev,
+                                              unsigned tgroup)
+{
+       struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       struct pxa_pinctrl_group *group = pctl->groups + tgroup;
+
+       return group->name;
+}
+
+static int pxa2xx_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
+                                      unsigned tgroup,
+                                      const unsigned **pins,
+                                      unsigned *num_pins)
+{
+       struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       struct pxa_pinctrl_group *group = pctl->groups + tgroup;
+
+       *pins = (unsigned *)&group->pin;
+       *num_pins = 1;
+
+       return 0;
+}
+
+static const struct pinctrl_ops pxa2xx_pctl_ops = {
+#ifdef CONFIG_OF
+       .dt_node_to_map         = pinconf_generic_dt_node_to_map_all,
+       .dt_free_map            = pinctrl_utils_dt_free_map,
+#endif
+       .get_groups_count       = pxa2xx_pctrl_get_groups_count,
+       .get_group_name         = pxa2xx_pctrl_get_group_name,
+       .get_group_pins         = pxa2xx_pctrl_get_group_pins,
+};
+
+static struct pxa_desc_function *
+pxa_desc_by_func_group(struct pxa_pinctrl *pctl, const char *pin_name,
+                      const char *func_name)
+{
+       int i;
+       struct pxa_desc_function *df;
+
+       for (i = 0; i < pctl->npins; i++) {
+               const struct pxa_desc_pin *pin = pctl->ppins + i;
+
+               if (!strcmp(pin->pin.name, pin_name))
+                       for (df = pin->functions; df->name; df++)
+                               if (!strcmp(df->name, func_name))
+                                       return df;
+       }
+
+       return NULL;
+}
+
+static int pxa2xx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
+                                        struct pinctrl_gpio_range *range,
+                                        unsigned pin,
+                                        bool input)
+{
+       struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       unsigned long flags;
+       uint32_t val;
+       void __iomem *gpdr;
+
+       gpdr = pctl->base_gpdr[pin / 32];
+       dev_dbg(pctl->dev, "set_direction(pin=%d): dir=%d\n",
+               pin, !input);
+
+       spin_lock_irqsave(&pctl->lock, flags);
+
+       val = readl_relaxed(gpdr);
+       val = (val & ~BIT(pin % 32)) | (input ? 0 : BIT(pin % 32));
+       writel_relaxed(val, gpdr);
+
+       spin_unlock_irqrestore(&pctl->lock, flags);
+
+       return 0;
+}
+
+static const char *pxa2xx_pmx_get_func_name(struct pinctrl_dev *pctldev,
+                                           unsigned function)
+{
+       struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       struct pxa_pinctrl_function *pf = pctl->functions + function;
+
+       return pf->name;
+}
+
+static int pxa2xx_get_functions_count(struct pinctrl_dev *pctldev)
+{
+       struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+       return pctl->nfuncs;
+}
+
+static int pxa2xx_pmx_get_func_groups(struct pinctrl_dev *pctldev,
+                                     unsigned function,
+                                     const char * const **groups,
+                                     unsigned * const num_groups)
+{
+       struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       struct pxa_pinctrl_function *pf = pctl->functions + function;
+
+       *groups = pf->groups;
+       *num_groups = pf->ngroups;
+
+       return 0;
+}
+
+static int pxa2xx_pmx_set_mux(struct pinctrl_dev *pctldev, unsigned function,
+                             unsigned tgroup)
+{
+       struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       struct pxa_pinctrl_group *group = pctl->groups + tgroup;
+       struct pxa_desc_function *df;
+       int pin, shift;
+       unsigned long flags;
+       void __iomem *gafr, *gpdr;
+       u32 val;
+
+
+       df = pxa_desc_by_func_group(pctl, group->name,
+                                   (pctl->functions + function)->name);
+       if (!df)
+               return -EINVAL;
+
+       pin = group->pin;
+       gafr = pctl->base_gafr[pin / 16];
+       gpdr = pctl->base_gpdr[pin / 32];
+       shift = (pin % 16) << 1;
+       dev_dbg(pctl->dev, "set_mux(pin=%d): af=%d dir=%d\n",
+               pin, df->muxval >> 1, df->muxval & 0x1);
+
+       spin_lock_irqsave(&pctl->lock, flags);
+
+       val = readl_relaxed(gafr);
+       val = (val & ~(0x3 << shift)) | ((df->muxval >> 1) << shift);
+       writel_relaxed(val, gafr);
+
+       val = readl_relaxed(gpdr);
+       val = (val & ~BIT(pin % 32)) | ((df->muxval & 1) ? BIT(pin % 32) : 0);
+       writel_relaxed(val, gpdr);
+
+       spin_unlock_irqrestore(&pctl->lock, flags);
+
+       return 0;
+}
+static const struct pinmux_ops pxa2xx_pinmux_ops = {
+       .get_functions_count = pxa2xx_get_functions_count,
+       .get_function_name = pxa2xx_pmx_get_func_name,
+       .get_function_groups = pxa2xx_pmx_get_func_groups,
+       .set_mux = pxa2xx_pmx_set_mux,
+       .gpio_set_direction = pxa2xx_pmx_gpio_set_direction,
+};
+
+static int pxa2xx_pconf_group_get(struct pinctrl_dev *pctldev,
+                                 unsigned group,
+                                 unsigned long *config)
+{
+       struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       struct pxa_pinctrl_group *g = pctl->groups + group;
+       unsigned long flags;
+       unsigned pin = g->pin;
+       void __iomem *pgsr = pctl->base_pgsr[pin / 32];
+       u32 val;
+
+       spin_lock_irqsave(&pctl->lock, flags);
+       val = readl_relaxed(pgsr) & BIT(pin % 32);
+       *config = val ? PIN_CONFIG_LOW_POWER_MODE : 0;
+       spin_unlock_irqrestore(&pctl->lock, flags);
+
+       dev_dbg(pctl->dev, "get sleep gpio state(pin=%d) %d\n",
+               pin, !!val);
+       return 0;
+}
+
+static int pxa2xx_pconf_group_set(struct pinctrl_dev *pctldev,
+                                 unsigned group,
+                                 unsigned long *configs,
+                                 unsigned num_configs)
+{
+       struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       struct pxa_pinctrl_group *g = pctl->groups + group;
+       unsigned long flags;
+       unsigned pin = g->pin;
+       void __iomem *pgsr = pctl->base_pgsr[pin / 32];
+       int i, is_set = 0;
+       u32 val;
+
+       for (i = 0; i < num_configs; i++) {
+               switch (pinconf_to_config_param(configs[i])) {
+               case PIN_CONFIG_LOW_POWER_MODE:
+                       is_set = pinconf_to_config_argument(configs[i]);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       dev_dbg(pctl->dev, "set sleep gpio state(pin=%d) %d\n",
+               pin, is_set);
+
+       spin_lock_irqsave(&pctl->lock, flags);
+       val = readl_relaxed(pgsr);
+       val = (val & ~BIT(pin % 32)) | (is_set ? BIT(pin % 32) : 0);
+       writel_relaxed(val, pgsr);
+       spin_unlock_irqrestore(&pctl->lock, flags);
+
+       return 0;
+}
+
+static const struct pinconf_ops pxa2xx_pconf_ops = {
+       .pin_config_group_get   = pxa2xx_pconf_group_get,
+       .pin_config_group_set   = pxa2xx_pconf_group_set,
+       .is_generic             = true,
+};
+
+static struct pinctrl_desc pxa2xx_pinctrl_desc = {
+       .confops        = &pxa2xx_pconf_ops,
+       .pctlops        = &pxa2xx_pctl_ops,
+       .pmxops         = &pxa2xx_pinmux_ops,
+};
+
+static const struct pxa_pinctrl_function *
+pxa2xx_find_function(struct pxa_pinctrl *pctl, const char *fname,
+                    const struct pxa_pinctrl_function *functions)
+{
+       const struct pxa_pinctrl_function *func;
+
+       for (func = functions; func->name; func++)
+               if (!strcmp(fname, func->name))
+                       return func;
+
+       return NULL;
+}
+
+static int pxa2xx_build_functions(struct pxa_pinctrl *pctl)
+{
+       int i;
+       struct pxa_pinctrl_function *functions;
+       struct pxa_desc_function *df;
+
+       /*
+        * Each pin can have at most 6 alternate functions, and 2 gpio functions
+        * which are common to each pin. As there are more than 2 pins without
+        * alternate function, 6 * npins is an absolute high limit of the number
+        * of functions.
+        */
+       functions = devm_kcalloc(pctl->dev, pctl->npins * 6,
+                                sizeof(*functions), GFP_KERNEL);
+       if (!functions)
+               return -ENOMEM;
+
+       for (i = 0; i < pctl->npins; i++)
+               for (df = pctl->ppins[i].functions; df->name; df++)
+                       if (!pxa2xx_find_function(pctl, df->name, functions))
+                               (functions + pctl->nfuncs++)->name = df->name;
+       pctl->functions = devm_kmemdup(pctl->dev, functions,
+                                      pctl->nfuncs * sizeof(*functions),
+                                      GFP_KERNEL);
+       if (!pctl->functions)
+               return -ENOMEM;
+
+       devm_kfree(pctl->dev, functions);
+       return 0;
+}
+
+static int pxa2xx_build_groups(struct pxa_pinctrl *pctl)
+{
+       int i, j, ngroups;
+       struct pxa_pinctrl_function *func;
+       struct pxa_desc_function *df;
+       char **gtmp;
+
+       gtmp = devm_kmalloc_array(pctl->dev, pctl->npins, sizeof(*gtmp),
+                                 GFP_KERNEL);
+       if (!gtmp)
+               return -ENOMEM;
+
+       for (i = 0; i < pctl->nfuncs; i++) {
+               ngroups = 0;
+               for (j = 0; j < pctl->npins; j++)
+                       for (df = pctl->ppins[j].functions; df->name;
+                            df++)
+                               if (!strcmp(pctl->functions[i].name,
+                                           df->name))
+                                       gtmp[ngroups++] = (char *)
+                                               pctl->ppins[j].pin.name;
+               func = pctl->functions + i;
+               func->ngroups = ngroups;
+               func->groups =
+                       devm_kmalloc_array(pctl->dev, ngroups,
+                                          sizeof(char *), GFP_KERNEL);
+               if (!func->groups)
+                       return -ENOMEM;
+
+               memcpy(func->groups, gtmp, ngroups * sizeof(*gtmp));
+       }
+
+       devm_kfree(pctl->dev, gtmp);
+       return 0;
+}
+
+static int pxa2xx_build_state(struct pxa_pinctrl *pctl,
+                             const struct pxa_desc_pin *ppins, int npins)
+{
+       struct pxa_pinctrl_group *group;
+       struct pinctrl_pin_desc *pins;
+       int ret, i;
+
+       pctl->npins = npins;
+       pctl->ppins = ppins;
+       pctl->ngroups = npins;
+
+       pctl->desc.npins = npins;
+       pins = devm_kcalloc(pctl->dev, npins, sizeof(*pins), GFP_KERNEL);
+       if (!pins)
+               return -ENOMEM;
+
+       pctl->desc.pins = pins;
+       for (i = 0; i < npins; i++)
+               pins[i] = ppins[i].pin;
+
+       pctl->groups = devm_kmalloc_array(pctl->dev, pctl->ngroups,
+                                         sizeof(*pctl->groups), GFP_KERNEL);
+       if (!pctl->groups)
+               return -ENOMEM;
+
+       for (i = 0; i < npins; i++) {
+               group = pctl->groups + i;
+               group->name = ppins[i].pin.name;
+               group->pin = ppins[i].pin.number;
+       }
+
+       ret = pxa2xx_build_functions(pctl);
+       if (ret)
+               return ret;
+
+       ret = pxa2xx_build_groups(pctl);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+int pxa2xx_pinctrl_init(struct platform_device *pdev,
+                       const struct pxa_desc_pin *ppins, int npins,
+                       void __iomem *base_gafr[], void __iomem *base_gpdr[],
+                       void __iomem *base_pgsr[])
+{
+       struct pxa_pinctrl *pctl;
+       int ret, i, maxpin = 0;
+
+       for (i = 0; i < npins; i++)
+               maxpin = max_t(int, ppins[i].pin.number, maxpin);
+
+       pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
+       if (!pctl)
+               return -ENOMEM;
+       pctl->base_gafr = devm_kcalloc(&pdev->dev, roundup(maxpin, 16),
+                                      sizeof(*pctl->base_gafr), GFP_KERNEL);
+       pctl->base_gpdr = devm_kcalloc(&pdev->dev, roundup(maxpin, 32),
+                                      sizeof(*pctl->base_gpdr), GFP_KERNEL);
+       pctl->base_pgsr = devm_kcalloc(&pdev->dev, roundup(maxpin, 32),
+                                      sizeof(*pctl->base_pgsr), GFP_KERNEL);
+       if (!pctl->base_gafr || !pctl->base_gpdr || !pctl->base_pgsr)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, pctl);
+       spin_lock_init(&pctl->lock);
+
+       pctl->dev = &pdev->dev;
+       pctl->desc = pxa2xx_pinctrl_desc;
+       pctl->desc.name = dev_name(&pdev->dev);
+       pctl->desc.owner = THIS_MODULE;
+
+       for (i = 0; i < roundup(maxpin, 16); i += 16)
+               pctl->base_gafr[i / 16] = base_gafr[i / 16];
+       for (i = 0; i < roundup(maxpin, 32); i += 32) {
+               pctl->base_gpdr[i / 32] = base_gpdr[i / 32];
+               pctl->base_pgsr[i / 32] = base_pgsr[i / 32];
+       }
+
+       ret = pxa2xx_build_state(pctl, ppins, npins);
+       if (ret)
+               return ret;
+
+       pctl->pctl_dev = pinctrl_register(&pctl->desc, &pdev->dev, pctl);
+       if (IS_ERR(pctl->pctl_dev)) {
+               dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
+               return PTR_ERR(pctl->pctl_dev);
+       }
+
+       dev_info(&pdev->dev, "initialized pxa2xx pinctrl driver\n");
+
+       return 0;
+}
+
+int pxa2xx_pinctrl_exit(struct platform_device *pdev)
+{
+       struct pxa_pinctrl *pctl = platform_get_drvdata(pdev);
+
+       pinctrl_unregister(pctl->pctl_dev);
+       return 0;
+}
diff --git a/drivers/pinctrl/pxa/pinctrl-pxa2xx.h b/drivers/pinctrl/pxa/pinctrl-pxa2xx.h
new file mode 100644 (file)
index 0000000..8be1e0b
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Marvell PXA2xx family pin control
+ *
+ * Copyright (C) 2015 Robert Jarzmik
+ *
+ * This program is 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 __PINCTRL_PXA_H
+#define __PINCTRL_PXA_H
+
+#define PXA_FUNCTION(_dir, _af, _name)                         \
+       {                                                       \
+               .name = _name,                                  \
+               .muxval = (_dir | (_af << 1)),                  \
+       }
+
+#define PXA_PIN(_pin, funcs...)                                        \
+       {                                                       \
+               .pin = _pin,                                    \
+               .functions = (struct pxa_desc_function[]){      \
+                       funcs, { } },                           \
+       }
+
+#define PXA_GPIO_PIN(_pin, funcs...)                           \
+       {                                                       \
+               .pin = _pin,                                    \
+               .functions = (struct pxa_desc_function[]){      \
+                       PXA_FUNCTION(0, 0, "gpio_in"),          \
+                       PXA_FUNCTION(1, 0, "gpio_out"),         \
+                       funcs, { } },                           \
+       }
+
+#define PXA_GPIO_ONLY_PIN(_pin)                                        \
+       {                                                       \
+               .pin = _pin,                                    \
+               .functions = (struct pxa_desc_function[]){      \
+                       PXA_FUNCTION(0, 0, "gpio_in"),          \
+                       PXA_FUNCTION(1, 0, "gpio_out"),         \
+                       { } },                                  \
+       }
+
+#define PXA_PINCTRL_PIN(pin)           \
+       PINCTRL_PIN(pin, "P" #pin)
+
+struct pxa_desc_function {
+       const char      *name;
+       u8              muxval;
+};
+
+struct pxa_desc_pin {
+       struct pinctrl_pin_desc         pin;
+       struct pxa_desc_function        *functions;
+};
+
+struct pxa_pinctrl_group {
+       const char      *name;
+       unsigned        pin;
+};
+
+struct pxa_pinctrl_function {
+       const char      *name;
+       const char      **groups;
+       unsigned        ngroups;
+};
+
+struct pxa_pinctrl {
+       spinlock_t                      lock;
+       void __iomem                    **base_gafr;
+       void __iomem                    **base_gpdr;
+       void __iomem                    **base_pgsr;
+       struct device                   *dev;
+       struct pinctrl_desc             desc;
+       struct pinctrl_dev              *pctl_dev;
+       unsigned                        npins;
+       const struct pxa_desc_pin       *ppins;
+       unsigned                        ngroups;
+       struct pxa_pinctrl_group        *groups;
+       unsigned                        nfuncs;
+       struct pxa_pinctrl_function     *functions;
+       char                            *name;
+};
+
+int pxa2xx_pinctrl_init(struct platform_device *pdev,
+                       const struct pxa_desc_pin *ppins, int npins,
+                       void __iomem *base_gafr[], void __iomem *base_gpdr[],
+                       void __iomem *base_gpsr[]);
+
+#endif /* __PINCTRL_PXA_H */
index 383263a92e59a41b227717f06c6b8712117d247c..eeac8cba8a2109fc70e5955fe24ae6c8fbf770d2 100644 (file)
@@ -63,6 +63,14 @@ config PINCTRL_MSM8916
          This is the pinctrl, pinmux, pinconf and gpiolib driver for the
          Qualcomm TLMM block found on the Qualcomm 8916 platform.
 
+config PINCTRL_MSM8996
+       tristate "Qualcomm MSM8996 pin controller driver"
+       depends on GPIOLIB && OF
+       select PINCTRL_MSM
+       help
+         This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+         Qualcomm TLMM block found in the Qualcomm MSM8996 platform.
+
 config PINCTRL_QDF2XXX
        tristate "Qualcomm Technologies QDF2xxx pin controller driver"
        depends on GPIOLIB && ACPI
index 13b190e72c219150a5edcd89991ad2bdca6c0deb..dfb50a9fe04ad23c770ba1c1b24d2a6aa9ce7e8a 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_PINCTRL_MSM8660)   += pinctrl-msm8660.o
 obj-$(CONFIG_PINCTRL_MSM8960)  += pinctrl-msm8960.o
 obj-$(CONFIG_PINCTRL_MSM8X74)  += pinctrl-msm8x74.o
 obj-$(CONFIG_PINCTRL_MSM8916)  += pinctrl-msm8916.o
+obj-$(CONFIG_PINCTRL_MSM8996)   += pinctrl-msm8996.o
 obj-$(CONFIG_PINCTRL_QDF2XXX)  += pinctrl-qdf2xxx.o
 obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o
 obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o
diff --git a/drivers/pinctrl/qcom/pinctrl-msm8996.c b/drivers/pinctrl/qcom/pinctrl-msm8996.c
new file mode 100644 (file)
index 0000000..c257927
--- /dev/null
@@ -0,0 +1,1942 @@
+/*
+ * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+#define FUNCTION(fname)                                        \
+       [msm_mux_##fname] = {                           \
+               .name = #fname,                         \
+               .groups = fname##_groups,               \
+               .ngroups = ARRAY_SIZE(fname##_groups),  \
+       }
+
+#define REG_BASE 0x0
+#define REG_SIZE 0x1000
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9)       \
+       {                                               \
+               .name = "gpio" #id,                     \
+               .pins = gpio##id##_pins,                \
+               .npins = (unsigned)ARRAY_SIZE(gpio##id##_pins), \
+               .funcs = (int[]){                       \
+                       msm_mux_gpio, /* gpio mode */   \
+                       msm_mux_##f1,                   \
+                       msm_mux_##f2,                   \
+                       msm_mux_##f3,                   \
+                       msm_mux_##f4,                   \
+                       msm_mux_##f5,                   \
+                       msm_mux_##f6,                   \
+                       msm_mux_##f7,                   \
+                       msm_mux_##f8,                   \
+                       msm_mux_##f9                    \
+               },                                      \
+               .nfuncs = 10,                           \
+               .ctl_reg = REG_BASE + REG_SIZE * id,    \
+               .io_reg = REG_BASE + 0x4 + REG_SIZE * id,               \
+               .intr_cfg_reg = REG_BASE + 0x8 + REG_SIZE * id,         \
+               .intr_status_reg = REG_BASE + 0xc + REG_SIZE * id,      \
+               .intr_target_reg = REG_BASE + 0x8 + REG_SIZE * id,      \
+               .mux_bit = 2,                   \
+               .pull_bit = 0,                  \
+               .drv_bit = 6,                   \
+               .oe_bit = 9,                    \
+               .in_bit = 0,                    \
+               .out_bit = 1,                   \
+               .intr_enable_bit = 0,           \
+               .intr_status_bit = 0,           \
+               .intr_target_bit = 5,           \
+               .intr_target_kpss_val = 3,      \
+               .intr_raw_status_bit = 4,       \
+               .intr_polarity_bit = 1,         \
+               .intr_detection_bit = 2,        \
+               .intr_detection_width = 2,      \
+       }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv)     \
+       {                                               \
+               .name = #pg_name,                       \
+               .pins = pg_name##_pins,                 \
+               .npins = (unsigned)ARRAY_SIZE(pg_name##_pins),  \
+               .ctl_reg = ctl,                         \
+               .io_reg = 0,                            \
+               .intr_cfg_reg = 0,                      \
+               .intr_status_reg = 0,                   \
+               .intr_target_reg = 0,                   \
+               .mux_bit = -1,                          \
+               .pull_bit = pull,                       \
+               .drv_bit = drv,                         \
+               .oe_bit = -1,                           \
+               .in_bit = -1,                           \
+               .out_bit = -1,                          \
+               .intr_enable_bit = -1,                  \
+               .intr_status_bit = -1,                  \
+               .intr_target_bit = -1,                  \
+               .intr_raw_status_bit = -1,              \
+               .intr_polarity_bit = -1,                \
+               .intr_detection_bit = -1,               \
+               .intr_detection_width = -1,             \
+       }
+static const struct pinctrl_pin_desc msm8996_pins[] = {
+       PINCTRL_PIN(0, "GPIO_0"),
+       PINCTRL_PIN(1, "GPIO_1"),
+       PINCTRL_PIN(2, "GPIO_2"),
+       PINCTRL_PIN(3, "GPIO_3"),
+       PINCTRL_PIN(4, "GPIO_4"),
+       PINCTRL_PIN(5, "GPIO_5"),
+       PINCTRL_PIN(6, "GPIO_6"),
+       PINCTRL_PIN(7, "GPIO_7"),
+       PINCTRL_PIN(8, "GPIO_8"),
+       PINCTRL_PIN(9, "GPIO_9"),
+       PINCTRL_PIN(10, "GPIO_10"),
+       PINCTRL_PIN(11, "GPIO_11"),
+       PINCTRL_PIN(12, "GPIO_12"),
+       PINCTRL_PIN(13, "GPIO_13"),
+       PINCTRL_PIN(14, "GPIO_14"),
+       PINCTRL_PIN(15, "GPIO_15"),
+       PINCTRL_PIN(16, "GPIO_16"),
+       PINCTRL_PIN(17, "GPIO_17"),
+       PINCTRL_PIN(18, "GPIO_18"),
+       PINCTRL_PIN(19, "GPIO_19"),
+       PINCTRL_PIN(20, "GPIO_20"),
+       PINCTRL_PIN(21, "GPIO_21"),
+       PINCTRL_PIN(22, "GPIO_22"),
+       PINCTRL_PIN(23, "GPIO_23"),
+       PINCTRL_PIN(24, "GPIO_24"),
+       PINCTRL_PIN(25, "GPIO_25"),
+       PINCTRL_PIN(26, "GPIO_26"),
+       PINCTRL_PIN(27, "GPIO_27"),
+       PINCTRL_PIN(28, "GPIO_28"),
+       PINCTRL_PIN(29, "GPIO_29"),
+       PINCTRL_PIN(30, "GPIO_30"),
+       PINCTRL_PIN(31, "GPIO_31"),
+       PINCTRL_PIN(32, "GPIO_32"),
+       PINCTRL_PIN(33, "GPIO_33"),
+       PINCTRL_PIN(34, "GPIO_34"),
+       PINCTRL_PIN(35, "GPIO_35"),
+       PINCTRL_PIN(36, "GPIO_36"),
+       PINCTRL_PIN(37, "GPIO_37"),
+       PINCTRL_PIN(38, "GPIO_38"),
+       PINCTRL_PIN(39, "GPIO_39"),
+       PINCTRL_PIN(40, "GPIO_40"),
+       PINCTRL_PIN(41, "GPIO_41"),
+       PINCTRL_PIN(42, "GPIO_42"),
+       PINCTRL_PIN(43, "GPIO_43"),
+       PINCTRL_PIN(44, "GPIO_44"),
+       PINCTRL_PIN(45, "GPIO_45"),
+       PINCTRL_PIN(46, "GPIO_46"),
+       PINCTRL_PIN(47, "GPIO_47"),
+       PINCTRL_PIN(48, "GPIO_48"),
+       PINCTRL_PIN(49, "GPIO_49"),
+       PINCTRL_PIN(50, "GPIO_50"),
+       PINCTRL_PIN(51, "GPIO_51"),
+       PINCTRL_PIN(52, "GPIO_52"),
+       PINCTRL_PIN(53, "GPIO_53"),
+       PINCTRL_PIN(54, "GPIO_54"),
+       PINCTRL_PIN(55, "GPIO_55"),
+       PINCTRL_PIN(56, "GPIO_56"),
+       PINCTRL_PIN(57, "GPIO_57"),
+       PINCTRL_PIN(58, "GPIO_58"),
+       PINCTRL_PIN(59, "GPIO_59"),
+       PINCTRL_PIN(60, "GPIO_60"),
+       PINCTRL_PIN(61, "GPIO_61"),
+       PINCTRL_PIN(62, "GPIO_62"),
+       PINCTRL_PIN(63, "GPIO_63"),
+       PINCTRL_PIN(64, "GPIO_64"),
+       PINCTRL_PIN(65, "GPIO_65"),
+       PINCTRL_PIN(66, "GPIO_66"),
+       PINCTRL_PIN(67, "GPIO_67"),
+       PINCTRL_PIN(68, "GPIO_68"),
+       PINCTRL_PIN(69, "GPIO_69"),
+       PINCTRL_PIN(70, "GPIO_70"),
+       PINCTRL_PIN(71, "GPIO_71"),
+       PINCTRL_PIN(72, "GPIO_72"),
+       PINCTRL_PIN(73, "GPIO_73"),
+       PINCTRL_PIN(74, "GPIO_74"),
+       PINCTRL_PIN(75, "GPIO_75"),
+       PINCTRL_PIN(76, "GPIO_76"),
+       PINCTRL_PIN(77, "GPIO_77"),
+       PINCTRL_PIN(78, "GPIO_78"),
+       PINCTRL_PIN(79, "GPIO_79"),
+       PINCTRL_PIN(80, "GPIO_80"),
+       PINCTRL_PIN(81, "GPIO_81"),
+       PINCTRL_PIN(82, "GPIO_82"),
+       PINCTRL_PIN(83, "GPIO_83"),
+       PINCTRL_PIN(84, "GPIO_84"),
+       PINCTRL_PIN(85, "GPIO_85"),
+       PINCTRL_PIN(86, "GPIO_86"),
+       PINCTRL_PIN(87, "GPIO_87"),
+       PINCTRL_PIN(88, "GPIO_88"),
+       PINCTRL_PIN(89, "GPIO_89"),
+       PINCTRL_PIN(90, "GPIO_90"),
+       PINCTRL_PIN(91, "GPIO_91"),
+       PINCTRL_PIN(92, "GPIO_92"),
+       PINCTRL_PIN(93, "GPIO_93"),
+       PINCTRL_PIN(94, "GPIO_94"),
+       PINCTRL_PIN(95, "GPIO_95"),
+       PINCTRL_PIN(96, "GPIO_96"),
+       PINCTRL_PIN(97, "GPIO_97"),
+       PINCTRL_PIN(98, "GPIO_98"),
+       PINCTRL_PIN(99, "GPIO_99"),
+       PINCTRL_PIN(100, "GPIO_100"),
+       PINCTRL_PIN(101, "GPIO_101"),
+       PINCTRL_PIN(102, "GPIO_102"),
+       PINCTRL_PIN(103, "GPIO_103"),
+       PINCTRL_PIN(104, "GPIO_104"),
+       PINCTRL_PIN(105, "GPIO_105"),
+       PINCTRL_PIN(106, "GPIO_106"),
+       PINCTRL_PIN(107, "GPIO_107"),
+       PINCTRL_PIN(108, "GPIO_108"),
+       PINCTRL_PIN(109, "GPIO_109"),
+       PINCTRL_PIN(110, "GPIO_110"),
+       PINCTRL_PIN(111, "GPIO_111"),
+       PINCTRL_PIN(112, "GPIO_112"),
+       PINCTRL_PIN(113, "GPIO_113"),
+       PINCTRL_PIN(114, "GPIO_114"),
+       PINCTRL_PIN(115, "GPIO_115"),
+       PINCTRL_PIN(116, "GPIO_116"),
+       PINCTRL_PIN(117, "GPIO_117"),
+       PINCTRL_PIN(118, "GPIO_118"),
+       PINCTRL_PIN(119, "GPIO_119"),
+       PINCTRL_PIN(120, "GPIO_120"),
+       PINCTRL_PIN(121, "GPIO_121"),
+       PINCTRL_PIN(122, "GPIO_122"),
+       PINCTRL_PIN(123, "GPIO_123"),
+       PINCTRL_PIN(124, "GPIO_124"),
+       PINCTRL_PIN(125, "GPIO_125"),
+       PINCTRL_PIN(126, "GPIO_126"),
+       PINCTRL_PIN(127, "GPIO_127"),
+       PINCTRL_PIN(128, "GPIO_128"),
+       PINCTRL_PIN(129, "GPIO_129"),
+       PINCTRL_PIN(130, "GPIO_130"),
+       PINCTRL_PIN(131, "GPIO_131"),
+       PINCTRL_PIN(132, "GPIO_132"),
+       PINCTRL_PIN(133, "GPIO_133"),
+       PINCTRL_PIN(134, "GPIO_134"),
+       PINCTRL_PIN(135, "GPIO_135"),
+       PINCTRL_PIN(136, "GPIO_136"),
+       PINCTRL_PIN(137, "GPIO_137"),
+       PINCTRL_PIN(138, "GPIO_138"),
+       PINCTRL_PIN(139, "GPIO_139"),
+       PINCTRL_PIN(140, "GPIO_140"),
+       PINCTRL_PIN(141, "GPIO_141"),
+       PINCTRL_PIN(142, "GPIO_142"),
+       PINCTRL_PIN(143, "GPIO_143"),
+       PINCTRL_PIN(144, "GPIO_144"),
+       PINCTRL_PIN(145, "GPIO_145"),
+       PINCTRL_PIN(146, "GPIO_146"),
+       PINCTRL_PIN(147, "GPIO_147"),
+       PINCTRL_PIN(148, "GPIO_148"),
+       PINCTRL_PIN(149, "GPIO_149"),
+       PINCTRL_PIN(150, "SDC1_CLK"),
+       PINCTRL_PIN(151, "SDC1_CMD"),
+       PINCTRL_PIN(152, "SDC1_DATA"),
+       PINCTRL_PIN(153, "SDC2_CLK"),
+       PINCTRL_PIN(154, "SDC2_CMD"),
+       PINCTRL_PIN(155, "SDC2_DATA"),
+       PINCTRL_PIN(156, "SDC1_RCLK"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+       static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+DECLARE_MSM_GPIO_PINS(134);
+DECLARE_MSM_GPIO_PINS(135);
+DECLARE_MSM_GPIO_PINS(136);
+DECLARE_MSM_GPIO_PINS(137);
+DECLARE_MSM_GPIO_PINS(138);
+DECLARE_MSM_GPIO_PINS(139);
+DECLARE_MSM_GPIO_PINS(140);
+DECLARE_MSM_GPIO_PINS(141);
+DECLARE_MSM_GPIO_PINS(142);
+DECLARE_MSM_GPIO_PINS(143);
+DECLARE_MSM_GPIO_PINS(144);
+DECLARE_MSM_GPIO_PINS(145);
+DECLARE_MSM_GPIO_PINS(146);
+DECLARE_MSM_GPIO_PINS(147);
+DECLARE_MSM_GPIO_PINS(148);
+DECLARE_MSM_GPIO_PINS(149);
+
+static const unsigned int sdc1_clk_pins[] = { 150 };
+static const unsigned int sdc1_cmd_pins[] = { 151 };
+static const unsigned int sdc1_data_pins[] = { 152 };
+static const unsigned int sdc2_clk_pins[] = { 153 };
+static const unsigned int sdc2_cmd_pins[] = { 154 };
+static const unsigned int sdc2_data_pins[] = { 155 };
+static const unsigned int sdc1_rclk_pins[] = { 156 };
+
+enum msm8996_functions {
+       msm_mux_adsp_ext,
+       msm_mux_atest_bbrx0,
+       msm_mux_atest_bbrx1,
+       msm_mux_atest_char,
+       msm_mux_atest_char0,
+       msm_mux_atest_char1,
+       msm_mux_atest_char2,
+       msm_mux_atest_char3,
+       msm_mux_atest_gpsadc0,
+       msm_mux_atest_gpsadc1,
+       msm_mux_atest_tsens,
+       msm_mux_atest_tsens2,
+       msm_mux_atest_usb1,
+       msm_mux_atest_usb10,
+       msm_mux_atest_usb11,
+       msm_mux_atest_usb12,
+       msm_mux_atest_usb13,
+       msm_mux_atest_usb2,
+       msm_mux_atest_usb20,
+       msm_mux_atest_usb21,
+       msm_mux_atest_usb22,
+       msm_mux_atest_usb23,
+       msm_mux_audio_ref,
+       msm_mux_bimc_dte0,
+       msm_mux_bimc_dte1,
+       msm_mux_blsp10_spi,
+       msm_mux_blsp11_i2c_scl_b,
+       msm_mux_blsp11_i2c_sda_b,
+       msm_mux_blsp11_uart_rx_b,
+       msm_mux_blsp11_uart_tx_b,
+       msm_mux_blsp1_spi,
+       msm_mux_blsp2_spi,
+       msm_mux_blsp_i2c1,
+       msm_mux_blsp_i2c10,
+       msm_mux_blsp_i2c11,
+       msm_mux_blsp_i2c12,
+       msm_mux_blsp_i2c2,
+       msm_mux_blsp_i2c3,
+       msm_mux_blsp_i2c4,
+       msm_mux_blsp_i2c5,
+       msm_mux_blsp_i2c6,
+       msm_mux_blsp_i2c7,
+       msm_mux_blsp_i2c8,
+       msm_mux_blsp_i2c9,
+       msm_mux_blsp_spi1,
+       msm_mux_blsp_spi10,
+       msm_mux_blsp_spi11,
+       msm_mux_blsp_spi12,
+       msm_mux_blsp_spi2,
+       msm_mux_blsp_spi3,
+       msm_mux_blsp_spi4,
+       msm_mux_blsp_spi5,
+       msm_mux_blsp_spi6,
+       msm_mux_blsp_spi7,
+       msm_mux_blsp_spi8,
+       msm_mux_blsp_spi9,
+       msm_mux_blsp_uart1,
+       msm_mux_blsp_uart10,
+       msm_mux_blsp_uart11,
+       msm_mux_blsp_uart12,
+       msm_mux_blsp_uart2,
+       msm_mux_blsp_uart3,
+       msm_mux_blsp_uart4,
+       msm_mux_blsp_uart5,
+       msm_mux_blsp_uart6,
+       msm_mux_blsp_uart7,
+       msm_mux_blsp_uart8,
+       msm_mux_blsp_uart9,
+       msm_mux_blsp_uim1,
+       msm_mux_blsp_uim10,
+       msm_mux_blsp_uim11,
+       msm_mux_blsp_uim12,
+       msm_mux_blsp_uim2,
+       msm_mux_blsp_uim3,
+       msm_mux_blsp_uim4,
+       msm_mux_blsp_uim5,
+       msm_mux_blsp_uim6,
+       msm_mux_blsp_uim7,
+       msm_mux_blsp_uim8,
+       msm_mux_blsp_uim9,
+       msm_mux_btfm_slimbus,
+       msm_mux_cam_mclk,
+       msm_mux_cci_async,
+       msm_mux_cci_i2c,
+       msm_mux_cci_timer0,
+       msm_mux_cci_timer1,
+       msm_mux_cci_timer2,
+       msm_mux_cci_timer3,
+       msm_mux_cci_timer4,
+       msm_mux_cri_trng,
+       msm_mux_cri_trng0,
+       msm_mux_cri_trng1,
+       msm_mux_dac_calib0,
+       msm_mux_dac_calib1,
+       msm_mux_dac_calib10,
+       msm_mux_dac_calib11,
+       msm_mux_dac_calib12,
+       msm_mux_dac_calib13,
+       msm_mux_dac_calib14,
+       msm_mux_dac_calib15,
+       msm_mux_dac_calib16,
+       msm_mux_dac_calib17,
+       msm_mux_dac_calib18,
+       msm_mux_dac_calib19,
+       msm_mux_dac_calib2,
+       msm_mux_dac_calib20,
+       msm_mux_dac_calib21,
+       msm_mux_dac_calib22,
+       msm_mux_dac_calib23,
+       msm_mux_dac_calib24,
+       msm_mux_dac_calib25,
+       msm_mux_dac_calib26,
+       msm_mux_dac_calib3,
+       msm_mux_dac_calib4,
+       msm_mux_dac_calib5,
+       msm_mux_dac_calib6,
+       msm_mux_dac_calib7,
+       msm_mux_dac_calib8,
+       msm_mux_dac_calib9,
+       msm_mux_dac_gpio,
+       msm_mux_dbg_out,
+       msm_mux_ddr_bist,
+       msm_mux_edp_hot,
+       msm_mux_edp_lcd,
+       msm_mux_gcc_gp1_clk_a,
+       msm_mux_gcc_gp1_clk_b,
+       msm_mux_gcc_gp2_clk_a,
+       msm_mux_gcc_gp2_clk_b,
+       msm_mux_gcc_gp3_clk_a,
+       msm_mux_gcc_gp3_clk_b,
+       msm_mux_gsm_tx,
+       msm_mux_hdmi_cec,
+       msm_mux_hdmi_ddc,
+       msm_mux_hdmi_hot,
+       msm_mux_hdmi_rcv,
+       msm_mux_isense_dbg,
+       msm_mux_ldo_en,
+       msm_mux_ldo_update,
+       msm_mux_lpass_slimbus,
+       msm_mux_m_voc,
+       msm_mux_mdp_vsync,
+       msm_mux_mdp_vsync_p_b,
+       msm_mux_mdp_vsync_s_b,
+       msm_mux_modem_tsync,
+       msm_mux_mss_lte,
+       msm_mux_nav_dr,
+       msm_mux_nav_pps,
+       msm_mux_pa_indicator,
+       msm_mux_pci_e0,
+       msm_mux_pci_e1,
+       msm_mux_pci_e2,
+       msm_mux_pll_bypassnl,
+       msm_mux_pll_reset,
+       msm_mux_pri_mi2s,
+       msm_mux_prng_rosc,
+       msm_mux_pwr_crypto,
+       msm_mux_pwr_modem,
+       msm_mux_pwr_nav,
+       msm_mux_qdss_cti,
+       msm_mux_qdss_cti_trig_in_a,
+       msm_mux_qdss_cti_trig_in_b,
+       msm_mux_qdss_cti_trig_out_a,
+       msm_mux_qdss_cti_trig_out_b,
+       msm_mux_qdss_stm0,
+       msm_mux_qdss_stm1,
+       msm_mux_qdss_stm10,
+       msm_mux_qdss_stm11,
+       msm_mux_qdss_stm12,
+       msm_mux_qdss_stm13,
+       msm_mux_qdss_stm14,
+       msm_mux_qdss_stm15,
+       msm_mux_qdss_stm16,
+       msm_mux_qdss_stm17,
+       msm_mux_qdss_stm18,
+       msm_mux_qdss_stm19,
+       msm_mux_qdss_stm2,
+       msm_mux_qdss_stm20,
+       msm_mux_qdss_stm21,
+       msm_mux_qdss_stm22,
+       msm_mux_qdss_stm23,
+       msm_mux_qdss_stm24,
+       msm_mux_qdss_stm25,
+       msm_mux_qdss_stm26,
+       msm_mux_qdss_stm27,
+       msm_mux_qdss_stm28,
+       msm_mux_qdss_stm29,
+       msm_mux_qdss_stm3,
+       msm_mux_qdss_stm30,
+       msm_mux_qdss_stm31,
+       msm_mux_qdss_stm4,
+       msm_mux_qdss_stm5,
+       msm_mux_qdss_stm6,
+       msm_mux_qdss_stm7,
+       msm_mux_qdss_stm8,
+       msm_mux_qdss_stm9,
+       msm_mux_qdss_traceclk_a,
+       msm_mux_qdss_traceclk_b,
+       msm_mux_qdss_tracectl_a,
+       msm_mux_qdss_tracectl_b,
+       msm_mux_qdss_tracedata_11,
+       msm_mux_qdss_tracedata_12,
+       msm_mux_qdss_tracedata_a,
+       msm_mux_qdss_tracedata_b,
+       msm_mux_qspi0,
+       msm_mux_qspi1,
+       msm_mux_qspi2,
+       msm_mux_qspi3,
+       msm_mux_qspi_clk,
+       msm_mux_qspi_cs,
+       msm_mux_qua_mi2s,
+       msm_mux_sd_card,
+       msm_mux_sd_write,
+       msm_mux_sdc40,
+       msm_mux_sdc41,
+       msm_mux_sdc42,
+       msm_mux_sdc43,
+       msm_mux_sdc4_clk,
+       msm_mux_sdc4_cmd,
+       msm_mux_sec_mi2s,
+       msm_mux_spkr_i2s,
+       msm_mux_ssbi1,
+       msm_mux_ssbi2,
+       msm_mux_ssc_irq,
+       msm_mux_ter_mi2s,
+       msm_mux_tsense_pwm1,
+       msm_mux_tsense_pwm2,
+       msm_mux_tsif1_clk,
+       msm_mux_tsif1_data,
+       msm_mux_tsif1_en,
+       msm_mux_tsif1_error,
+       msm_mux_tsif1_sync,
+       msm_mux_tsif2_clk,
+       msm_mux_tsif2_data,
+       msm_mux_tsif2_en,
+       msm_mux_tsif2_error,
+       msm_mux_tsif2_sync,
+       msm_mux_uim1,
+       msm_mux_uim2,
+       msm_mux_uim3,
+       msm_mux_uim4,
+       msm_mux_uim_batt,
+       msm_mux_vfr_1,
+       msm_mux_gpio,
+       msm_mux_NA,
+};
+
+static const char * const gpio_groups[] = {
+       "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+       "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+       "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+       "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+       "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+       "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+       "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+       "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+       "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+       "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+       "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+       "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+       "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91",
+       "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+       "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104",
+       "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+       "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116",
+       "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122",
+       "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128",
+       "gpio129", "gpio130", "gpio131", "gpio132", "gpio133", "gpio134",
+       "gpio135", "gpio136", "gpio137", "gpio138", "gpio139", "gpio140",
+       "gpio141", "gpio142", "gpio143", "gpio144", "gpio145", "gpio146",
+       "gpio147", "gpio148", "gpio149"
+};
+
+
+static const char * const blsp_uart1_groups[] = {
+       "gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const blsp_spi1_groups[] = {
+       "gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const blsp_i2c1_groups[] = {
+       "gpio2", "gpio3",
+};
+static const char * const blsp_uim1_groups[] = {
+       "gpio0", "gpio1",
+};
+static const char * const atest_tsens_groups[] = {
+       "gpio3",
+};
+static const char * const bimc_dte1_groups[] = {
+       "gpio3", "gpio5",
+};
+static const char * const blsp_spi8_groups[] = {
+       "gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const blsp_uart8_groups[] = {
+       "gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const blsp_uim8_groups[] = {
+       "gpio4", "gpio5",
+};
+static const char * const qdss_cti_trig_out_b_groups[] = {
+       "gpio4",
+};
+static const char * const dac_calib0_groups[] = {
+       "gpio4", "gpio41",
+};
+static const char * const bimc_dte0_groups[] = {
+       "gpio4", "gpio6",
+};
+static const char * const qdss_cti_trig_in_b_groups[] = {
+       "gpio5",
+};
+static const char * const dac_calib1_groups[] = {
+       "gpio5", "gpio42",
+};
+static const char * const dac_calib2_groups[] = {
+       "gpio6", "gpio43",
+};
+static const char * const atest_tsens2_groups[] = {
+       "gpio7",
+};
+static const char * const blsp_spi10_groups[] = {
+       "gpio8", "gpio9", "gpio10", "gpio11",
+};
+static const char * const blsp_uart10_groups[] = {
+       "gpio8", "gpio9", "gpio10", "gpio11",
+};
+static const char * const blsp_uim10_groups[] = {
+       "gpio8", "gpio9",
+};
+static const char * const atest_bbrx1_groups[] = {
+       "gpio8",
+};
+static const char * const atest_usb12_groups[] = {
+       "gpio9",
+};
+static const char * const mdp_vsync_groups[] = {
+       "gpio10", "gpio11", "gpio12",
+};
+static const char * const edp_lcd_groups[] = {
+       "gpio10",
+};
+static const char * const blsp_i2c10_groups[] = {
+       "gpio10", "gpio11",
+};
+static const char * const atest_usb11_groups[] = {
+       "gpio10",
+};
+static const char * const atest_gpsadc0_groups[] = {
+       "gpio11",
+};
+static const char * const edp_hot_groups[] = {
+       "gpio11",
+};
+static const char * const atest_usb10_groups[] = {
+       "gpio11",
+};
+static const char * const m_voc_groups[] = {
+       "gpio12",
+};
+static const char * const dac_gpio_groups[] = {
+       "gpio12",
+};
+static const char * const atest_char_groups[] = {
+       "gpio12",
+};
+static const char * const cam_mclk_groups[] = {
+       "gpio13", "gpio14", "gpio15", "gpio16",
+};
+static const char * const pll_bypassnl_groups[] = {
+       "gpio13",
+};
+static const char * const qdss_stm7_groups[] = {
+       "gpio13",
+};
+static const char * const blsp_i2c8_groups[] = {
+       "gpio6", "gpio7",
+};
+static const char * const atest_usb1_groups[] = {
+       "gpio7",
+};
+static const char * const atest_usb13_groups[] = {
+       "gpio8",
+};
+static const char * const atest_bbrx0_groups[] = {
+       "gpio9",
+};
+static const char * const atest_gpsadc1_groups[] = {
+       "gpio10",
+};
+static const char * const qdss_tracedata_b_groups[] = {
+       "gpio13", "gpio14", "gpio15", "gpio16", "gpio17", "gpio18", "gpio19",
+       "gpio21", "gpio22", "gpio23", "gpio26", "gpio29", "gpio57", "gpio58",
+       "gpio92", "gpio93",
+};
+static const char * const pll_reset_groups[] = {
+       "gpio14",
+};
+static const char * const qdss_stm6_groups[] = {
+       "gpio14",
+};
+static const char * const qdss_stm5_groups[] = {
+       "gpio15",
+};
+static const char * const qdss_stm4_groups[] = {
+       "gpio16",
+};
+static const char * const atest_usb2_groups[] = {
+       "gpio16",
+};
+static const char * const dac_calib3_groups[] = {
+       "gpio17", "gpio44",
+};
+static const char * const cci_i2c_groups[] = {
+       "gpio17", "gpio18", "gpio19", "gpio20",
+};
+static const char * const qdss_stm3_groups[] = {
+       "gpio17",
+};
+static const char * const atest_usb23_groups[] = {
+       "gpio17",
+};
+static const char * const atest_char3_groups[] = {
+       "gpio17",
+};
+static const char * const dac_calib4_groups[] = {
+       "gpio18", "gpio45",
+};
+static const char * const qdss_stm2_groups[] = {
+       "gpio18",
+};
+static const char * const atest_usb22_groups[] = {
+       "gpio18",
+};
+static const char * const atest_char2_groups[] = {
+       "gpio18",
+};
+static const char * const dac_calib5_groups[] = {
+       "gpio19", "gpio46",
+};
+static const char * const qdss_stm1_groups[] = {
+       "gpio19",
+};
+static const char * const atest_usb21_groups[] = {
+       "gpio19",
+};
+static const char * const atest_char1_groups[] = {
+       "gpio19",
+};
+static const char * const dac_calib6_groups[] = {
+       "gpio20", "gpio47",
+};
+static const char * const dbg_out_groups[] = {
+       "gpio20",
+};
+static const char * const qdss_stm0_groups[] = {
+       "gpio20",
+};
+static const char * const atest_usb20_groups[] = {
+       "gpio20",
+};
+static const char * const atest_char0_groups[] = {
+       "gpio20",
+};
+static const char * const dac_calib7_groups[] = {
+       "gpio21", "gpio48",
+};
+static const char * const cci_timer0_groups[] = {
+       "gpio21",
+};
+static const char * const qdss_stm13_groups[] = {
+       "gpio21",
+};
+static const char * const dac_calib8_groups[] = {
+       "gpio22", "gpio49",
+};
+static const char * const cci_timer1_groups[] = {
+       "gpio22",
+};
+static const char * const qdss_stm12_groups[] = {
+       "gpio22",
+};
+static const char * const dac_calib9_groups[] = {
+       "gpio23", "gpio50",
+};
+static const char * const cci_timer2_groups[] = {
+       "gpio23",
+};
+static const char * const qdss_stm11_groups[] = {
+       "gpio23",
+};
+static const char * const dac_calib10_groups[] = {
+       "gpio24", "gpio51",
+};
+static const char * const cci_timer3_groups[] = {
+       "gpio24",
+};
+static const char * const cci_async_groups[] = {
+       "gpio24", "gpio25", "gpio26",
+};
+static const char * const blsp1_spi_groups[] = {
+       "gpio24", "gpio27", "gpio28", "gpio90",
+};
+static const char * const qdss_stm10_groups[] = {
+       "gpio24",
+};
+static const char * const qdss_cti_trig_in_a_groups[] = {
+       "gpio24",
+};
+static const char * const dac_calib11_groups[] = {
+       "gpio25", "gpio52",
+};
+static const char * const cci_timer4_groups[] = {
+       "gpio25",
+};
+static const char * const blsp_spi6_groups[] = {
+       "gpio25", "gpio26", "gpio27", "gpio28",
+};
+static const char * const blsp_uart6_groups[] = {
+       "gpio25", "gpio26", "gpio27", "gpio28",
+};
+static const char * const blsp_uim6_groups[] = {
+       "gpio25", "gpio26",
+};
+static const char * const blsp2_spi_groups[] = {
+       "gpio25", "gpio29", "gpio30",
+};
+static const char * const qdss_stm9_groups[] = {
+       "gpio25",
+};
+static const char * const qdss_cti_trig_out_a_groups[] = {
+       "gpio25",
+};
+static const char * const dac_calib12_groups[] = {
+       "gpio26", "gpio53",
+};
+static const char * const qdss_stm8_groups[] = {
+       "gpio26",
+};
+static const char * const dac_calib13_groups[] = {
+       "gpio27", "gpio54",
+};
+static const char * const blsp_i2c6_groups[] = {
+       "gpio27", "gpio28",
+};
+static const char * const qdss_tracectl_a_groups[] = {
+       "gpio27",
+};
+static const char * const dac_calib14_groups[] = {
+       "gpio28", "gpio55",
+};
+static const char * const qdss_traceclk_a_groups[] = {
+       "gpio28",
+};
+static const char * const dac_calib15_groups[] = {
+       "gpio29", "gpio56",
+};
+static const char * const dac_calib16_groups[] = {
+       "gpio30", "gpio57",
+};
+static const char * const hdmi_rcv_groups[] = {
+       "gpio30",
+};
+static const char * const dac_calib17_groups[] = {
+       "gpio31", "gpio58",
+};
+static const char * const pwr_modem_groups[] = {
+       "gpio31",
+};
+static const char * const hdmi_cec_groups[] = {
+       "gpio31",
+};
+static const char * const pwr_nav_groups[] = {
+       "gpio32",
+};
+static const char * const dac_calib18_groups[] = {
+       "gpio32", "gpio59",
+};
+static const char * const hdmi_ddc_groups[] = {
+       "gpio32", "gpio33",
+};
+static const char * const pwr_crypto_groups[] = {
+       "gpio33",
+};
+static const char * const dac_calib19_groups[] = {
+       "gpio33", "gpio60",
+};
+static const char * const dac_calib20_groups[] = {
+       "gpio34", "gpio61",
+};
+static const char * const hdmi_hot_groups[] = {
+       "gpio34",
+};
+static const char * const dac_calib21_groups[] = {
+       "gpio35", "gpio62",
+};
+static const char * const pci_e0_groups[] = {
+       "gpio35", "gpio36",
+};
+static const char * const dac_calib22_groups[] = {
+       "gpio36", "gpio63",
+};
+static const char * const dac_calib23_groups[] = {
+       "gpio37", "gpio64",
+};
+static const char * const blsp_i2c2_groups[] = {
+       "gpio43", "gpio44",
+};
+static const char * const blsp_spi3_groups[] = {
+       "gpio45", "gpio46", "gpio47", "gpio48",
+};
+static const char * const blsp_uart3_groups[] = {
+       "gpio45", "gpio46", "gpio47", "gpio48",
+};
+static const char * const blsp_uim3_groups[] = {
+       "gpio45", "gpio46",
+};
+static const char * const blsp_i2c3_groups[] = {
+       "gpio47", "gpio48",
+};
+static const char * const dac_calib24_groups[] = {
+       "gpio38", "gpio65",
+};
+static const char * const dac_calib25_groups[] = {
+       "gpio39", "gpio66",
+};
+static const char * const tsif1_sync_groups[] = {
+       "gpio39",
+};
+static const char * const sd_write_groups[] = {
+       "gpio40",
+};
+static const char * const tsif1_error_groups[] = {
+       "gpio40",
+};
+static const char * const blsp_spi2_groups[] = {
+       "gpio41", "gpio42", "gpio43", "gpio44",
+};
+static const char * const blsp_uart2_groups[] = {
+       "gpio41", "gpio42", "gpio43", "gpio44",
+};
+static const char * const blsp_uim2_groups[] = {
+       "gpio41", "gpio42",
+};
+static const char * const qdss_cti_groups[] = {
+       "gpio41", "gpio42", "gpio100", "gpio101",
+};
+static const char * const uim3_groups[] = {
+       "gpio49", "gpio50", "gpio51", "gpio52",
+};
+static const char * const blsp_spi9_groups[] = {
+       "gpio49", "gpio50", "gpio51", "gpio52",
+};
+static const char * const blsp_uart9_groups[] = {
+       "gpio49", "gpio50", "gpio51", "gpio52",
+};
+static const char * const blsp_uim9_groups[] = {
+       "gpio49", "gpio50",
+};
+static const char * const blsp10_spi_groups[] = {
+       "gpio49", "gpio50", "gpio51", "gpio52", "gpio88",
+};
+static const char * const blsp_i2c9_groups[] = {
+       "gpio51", "gpio52",
+};
+static const char * const blsp_spi7_groups[] = {
+       "gpio53", "gpio54", "gpio55", "gpio56",
+};
+static const char * const blsp_uart7_groups[] = {
+       "gpio53", "gpio54", "gpio55", "gpio56",
+};
+static const char * const blsp_uim7_groups[] = {
+       "gpio53", "gpio54",
+};
+static const char * const qdss_tracedata_a_groups[] = {
+       "gpio53", "gpio54", "gpio63", "gpio64", "gpio65", "gpio66", "gpio67",
+       "gpio74", "gpio75", "gpio76", "gpio77", "gpio85", "gpio86", "gpio87",
+       "gpio89", "gpio90",
+};
+static const char * const blsp_i2c7_groups[] = {
+       "gpio55", "gpio56",
+};
+static const char * const qua_mi2s_groups[] = {
+       "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+};
+static const char * const gcc_gp1_clk_a_groups[] = {
+       "gpio57",
+};
+static const char * const uim4_groups[] = {
+       "gpio58", "gpio59", "gpio60", "gpio61",
+};
+static const char * const blsp_spi11_groups[] = {
+       "gpio58", "gpio59", "gpio60", "gpio61",
+};
+static const char * const blsp_uart11_groups[] = {
+       "gpio58", "gpio59", "gpio60", "gpio61",
+};
+static const char * const blsp_uim11_groups[] = {
+       "gpio58", "gpio59",
+};
+static const char * const gcc_gp2_clk_a_groups[] = {
+       "gpio58",
+};
+static const char * const gcc_gp3_clk_a_groups[] = {
+       "gpio59",
+};
+static const char * const blsp_i2c11_groups[] = {
+       "gpio60", "gpio61",
+};
+static const char * const cri_trng0_groups[] = {
+       "gpio60",
+};
+static const char * const cri_trng1_groups[] = {
+       "gpio61",
+};
+static const char * const cri_trng_groups[] = {
+       "gpio62",
+};
+static const char * const qdss_stm18_groups[] = {
+       "gpio63",
+};
+static const char * const pri_mi2s_groups[] = {
+       "gpio64", "gpio65", "gpio66", "gpio67", "gpio68",
+};
+static const char * const qdss_stm17_groups[] = {
+       "gpio64",
+};
+static const char * const blsp_spi4_groups[] = {
+       "gpio65", "gpio66", "gpio67", "gpio68",
+};
+static const char * const blsp_uart4_groups[] = {
+       "gpio65", "gpio66", "gpio67", "gpio68",
+};
+static const char * const blsp_uim4_groups[] = {
+       "gpio65", "gpio66",
+};
+static const char * const qdss_stm16_groups[] = {
+       "gpio65",
+};
+static const char * const qdss_stm15_groups[] = {
+       "gpio66",
+};
+static const char * const dac_calib26_groups[] = {
+       "gpio67",
+};
+static const char * const blsp_i2c4_groups[] = {
+       "gpio67", "gpio68",
+};
+static const char * const qdss_stm14_groups[] = {
+       "gpio67",
+};
+static const char * const spkr_i2s_groups[] = {
+       "gpio69", "gpio70", "gpio71", "gpio72",
+};
+static const char * const audio_ref_groups[] = {
+       "gpio69",
+};
+static const char * const lpass_slimbus_groups[] = {
+       "gpio70", "gpio71", "gpio72",
+};
+static const char * const isense_dbg_groups[] = {
+       "gpio70",
+};
+static const char * const tsense_pwm1_groups[] = {
+       "gpio71",
+};
+static const char * const tsense_pwm2_groups[] = {
+       "gpio71",
+};
+static const char * const btfm_slimbus_groups[] = {
+       "gpio73", "gpio74",
+};
+static const char * const ter_mi2s_groups[] = {
+       "gpio74", "gpio75", "gpio76", "gpio77", "gpio78",
+};
+static const char * const qdss_stm22_groups[] = {
+       "gpio74",
+};
+static const char * const qdss_stm21_groups[] = {
+       "gpio75",
+};
+static const char * const qdss_stm20_groups[] = {
+       "gpio76",
+};
+static const char * const qdss_stm19_groups[] = {
+       "gpio77",
+};
+static const char * const ssc_irq_groups[] = {
+       "gpio78", "gpio79", "gpio80", "gpio117", "gpio118", "gpio119",
+       "gpio120", "gpio121", "gpio122", "gpio123", "gpio124", "gpio125",
+};
+static const char * const gcc_gp1_clk_b_groups[] = {
+       "gpio78",
+};
+static const char * const sec_mi2s_groups[] = {
+       "gpio79", "gpio80", "gpio81", "gpio82", "gpio83",
+};
+static const char * const blsp_spi5_groups[] = {
+       "gpio81", "gpio82", "gpio83", "gpio84",
+};
+static const char * const blsp_uart5_groups[] = {
+       "gpio81", "gpio82", "gpio83", "gpio84",
+};
+static const char * const blsp_uim5_groups[] = {
+       "gpio81", "gpio82",
+};
+static const char * const gcc_gp2_clk_b_groups[] = {
+       "gpio81",
+};
+static const char * const gcc_gp3_clk_b_groups[] = {
+       "gpio82",
+};
+static const char * const blsp_i2c5_groups[] = {
+       "gpio83", "gpio84",
+};
+static const char * const blsp_spi12_groups[] = {
+       "gpio85", "gpio86", "gpio87", "gpio88",
+};
+static const char * const blsp_uart12_groups[] = {
+       "gpio85", "gpio86", "gpio87", "gpio88",
+};
+static const char * const blsp_uim12_groups[] = {
+       "gpio85", "gpio86",
+};
+static const char * const qdss_stm25_groups[] = {
+       "gpio85",
+};
+static const char * const qdss_stm31_groups[] = {
+       "gpio86",
+};
+static const char * const blsp_i2c12_groups[] = {
+       "gpio87", "gpio88",
+};
+static const char * const qdss_stm30_groups[] = {
+       "gpio87",
+};
+static const char * const qdss_stm29_groups[] = {
+       "gpio88",
+};
+static const char * const tsif1_clk_groups[] = {
+       "gpio89",
+};
+static const char * const qdss_stm28_groups[] = {
+       "gpio89",
+};
+static const char * const tsif1_en_groups[] = {
+       "gpio90",
+};
+static const char * const tsif1_data_groups[] = {
+       "gpio91",
+};
+static const char * const sdc4_cmd_groups[] = {
+       "gpio91",
+};
+static const char * const qdss_stm27_groups[] = {
+       "gpio91",
+};
+static const char * const qdss_traceclk_b_groups[] = {
+       "gpio91",
+};
+static const char * const tsif2_error_groups[] = {
+       "gpio92",
+};
+static const char * const sdc43_groups[] = {
+       "gpio92",
+};
+static const char * const vfr_1_groups[] = {
+       "gpio92",
+};
+static const char * const qdss_stm26_groups[] = {
+       "gpio92",
+};
+static const char * const tsif2_clk_groups[] = {
+       "gpio93",
+};
+static const char * const sdc4_clk_groups[] = {
+       "gpio93",
+};
+static const char * const qdss_stm24_groups[] = {
+       "gpio93",
+};
+static const char * const tsif2_en_groups[] = {
+       "gpio94",
+};
+static const char * const sdc42_groups[] = {
+       "gpio94",
+};
+static const char * const qdss_stm23_groups[] = {
+       "gpio94",
+};
+static const char * const qdss_tracectl_b_groups[] = {
+       "gpio94",
+};
+static const char * const sd_card_groups[] = {
+       "gpio95",
+};
+static const char * const tsif2_data_groups[] = {
+       "gpio95",
+};
+static const char * const sdc41_groups[] = {
+       "gpio95",
+};
+static const char * const tsif2_sync_groups[] = {
+       "gpio96",
+};
+static const char * const sdc40_groups[] = {
+       "gpio96",
+};
+static const char * const mdp_vsync_p_b_groups[] = {
+       "gpio97",
+};
+static const char * const ldo_en_groups[] = {
+       "gpio97",
+};
+static const char * const mdp_vsync_s_b_groups[] = {
+       "gpio98",
+};
+static const char * const ldo_update_groups[] = {
+       "gpio98",
+};
+static const char * const blsp11_uart_tx_b_groups[] = {
+       "gpio100",
+};
+static const char * const blsp11_uart_rx_b_groups[] = {
+       "gpio101",
+};
+static const char * const blsp11_i2c_sda_b_groups[] = {
+       "gpio102",
+};
+static const char * const prng_rosc_groups[] = {
+       "gpio102",
+};
+static const char * const blsp11_i2c_scl_b_groups[] = {
+       "gpio103",
+};
+static const char * const uim2_groups[] = {
+       "gpio105", "gpio106", "gpio107", "gpio108",
+};
+static const char * const uim1_groups[] = {
+       "gpio109", "gpio110", "gpio111", "gpio112",
+};
+static const char * const uim_batt_groups[] = {
+       "gpio113",
+};
+static const char * const pci_e2_groups[] = {
+       "gpio114", "gpio115", "gpio116",
+};
+static const char * const pa_indicator_groups[] = {
+       "gpio116",
+};
+static const char * const adsp_ext_groups[] = {
+       "gpio118",
+};
+static const char * const ddr_bist_groups[] = {
+       "gpio121", "gpio122", "gpio123", "gpio124",
+};
+static const char * const qdss_tracedata_11_groups[] = {
+       "gpio123",
+};
+static const char * const qdss_tracedata_12_groups[] = {
+       "gpio124",
+};
+static const char * const modem_tsync_groups[] = {
+       "gpio128",
+};
+static const char * const nav_dr_groups[] = {
+       "gpio128",
+};
+static const char * const nav_pps_groups[] = {
+       "gpio128",
+};
+static const char * const pci_e1_groups[] = {
+       "gpio130", "gpio131", "gpio132",
+};
+static const char * const gsm_tx_groups[] = {
+       "gpio134", "gpio135",
+};
+static const char * const qspi_cs_groups[] = {
+       "gpio138", "gpio141",
+};
+static const char * const ssbi2_groups[] = {
+       "gpio139",
+};
+static const char * const ssbi1_groups[] = {
+       "gpio140",
+};
+static const char * const mss_lte_groups[] = {
+       "gpio144", "gpio145",
+};
+static const char * const qspi_clk_groups[] = {
+       "gpio145",
+};
+static const char * const qspi0_groups[] = {
+       "gpio146",
+};
+static const char * const qspi1_groups[] = {
+       "gpio147",
+};
+static const char * const qspi2_groups[] = {
+       "gpio148",
+};
+static const char * const qspi3_groups[] = {
+       "gpio149",
+};
+
+static const struct msm_function msm8996_functions[] = {
+       FUNCTION(adsp_ext),
+       FUNCTION(atest_bbrx0),
+       FUNCTION(atest_bbrx1),
+       FUNCTION(atest_char),
+       FUNCTION(atest_char0),
+       FUNCTION(atest_char1),
+       FUNCTION(atest_char2),
+       FUNCTION(atest_char3),
+       FUNCTION(atest_gpsadc0),
+       FUNCTION(atest_gpsadc1),
+       FUNCTION(atest_tsens),
+       FUNCTION(atest_tsens2),
+       FUNCTION(atest_usb1),
+       FUNCTION(atest_usb10),
+       FUNCTION(atest_usb11),
+       FUNCTION(atest_usb12),
+       FUNCTION(atest_usb13),
+       FUNCTION(atest_usb2),
+       FUNCTION(atest_usb20),
+       FUNCTION(atest_usb21),
+       FUNCTION(atest_usb22),
+       FUNCTION(atest_usb23),
+       FUNCTION(audio_ref),
+       FUNCTION(bimc_dte0),
+       FUNCTION(bimc_dte1),
+       FUNCTION(blsp10_spi),
+       FUNCTION(blsp11_i2c_scl_b),
+       FUNCTION(blsp11_i2c_sda_b),
+       FUNCTION(blsp11_uart_rx_b),
+       FUNCTION(blsp11_uart_tx_b),
+       FUNCTION(blsp1_spi),
+       FUNCTION(blsp2_spi),
+       FUNCTION(blsp_i2c1),
+       FUNCTION(blsp_i2c10),
+       FUNCTION(blsp_i2c11),
+       FUNCTION(blsp_i2c12),
+       FUNCTION(blsp_i2c2),
+       FUNCTION(blsp_i2c3),
+       FUNCTION(blsp_i2c4),
+       FUNCTION(blsp_i2c5),
+       FUNCTION(blsp_i2c6),
+       FUNCTION(blsp_i2c7),
+       FUNCTION(blsp_i2c8),
+       FUNCTION(blsp_i2c9),
+       FUNCTION(blsp_spi1),
+       FUNCTION(blsp_spi10),
+       FUNCTION(blsp_spi11),
+       FUNCTION(blsp_spi12),
+       FUNCTION(blsp_spi2),
+       FUNCTION(blsp_spi3),
+       FUNCTION(blsp_spi4),
+       FUNCTION(blsp_spi5),
+       FUNCTION(blsp_spi6),
+       FUNCTION(blsp_spi7),
+       FUNCTION(blsp_spi8),
+       FUNCTION(blsp_spi9),
+       FUNCTION(blsp_uart1),
+       FUNCTION(blsp_uart10),
+       FUNCTION(blsp_uart11),
+       FUNCTION(blsp_uart12),
+       FUNCTION(blsp_uart2),
+       FUNCTION(blsp_uart3),
+       FUNCTION(blsp_uart4),
+       FUNCTION(blsp_uart5),
+       FUNCTION(blsp_uart6),
+       FUNCTION(blsp_uart7),
+       FUNCTION(blsp_uart8),
+       FUNCTION(blsp_uart9),
+       FUNCTION(blsp_uim1),
+       FUNCTION(blsp_uim10),
+       FUNCTION(blsp_uim11),
+       FUNCTION(blsp_uim12),
+       FUNCTION(blsp_uim2),
+       FUNCTION(blsp_uim3),
+       FUNCTION(blsp_uim4),
+       FUNCTION(blsp_uim5),
+       FUNCTION(blsp_uim6),
+       FUNCTION(blsp_uim7),
+       FUNCTION(blsp_uim8),
+       FUNCTION(blsp_uim9),
+       FUNCTION(btfm_slimbus),
+       FUNCTION(cam_mclk),
+       FUNCTION(cci_async),
+       FUNCTION(cci_i2c),
+       FUNCTION(cci_timer0),
+       FUNCTION(cci_timer1),
+       FUNCTION(cci_timer2),
+       FUNCTION(cci_timer3),
+       FUNCTION(cci_timer4),
+       FUNCTION(cri_trng),
+       FUNCTION(cri_trng0),
+       FUNCTION(cri_trng1),
+       FUNCTION(dac_calib0),
+       FUNCTION(dac_calib1),
+       FUNCTION(dac_calib10),
+       FUNCTION(dac_calib11),
+       FUNCTION(dac_calib12),
+       FUNCTION(dac_calib13),
+       FUNCTION(dac_calib14),
+       FUNCTION(dac_calib15),
+       FUNCTION(dac_calib16),
+       FUNCTION(dac_calib17),
+       FUNCTION(dac_calib18),
+       FUNCTION(dac_calib19),
+       FUNCTION(dac_calib2),
+       FUNCTION(dac_calib20),
+       FUNCTION(dac_calib21),
+       FUNCTION(dac_calib22),
+       FUNCTION(dac_calib23),
+       FUNCTION(dac_calib24),
+       FUNCTION(dac_calib25),
+       FUNCTION(dac_calib26),
+       FUNCTION(dac_calib3),
+       FUNCTION(dac_calib4),
+       FUNCTION(dac_calib5),
+       FUNCTION(dac_calib6),
+       FUNCTION(dac_calib7),
+       FUNCTION(dac_calib8),
+       FUNCTION(dac_calib9),
+       FUNCTION(dac_gpio),
+       FUNCTION(dbg_out),
+       FUNCTION(ddr_bist),
+       FUNCTION(edp_hot),
+       FUNCTION(edp_lcd),
+       FUNCTION(gcc_gp1_clk_a),
+       FUNCTION(gcc_gp1_clk_b),
+       FUNCTION(gcc_gp2_clk_a),
+       FUNCTION(gcc_gp2_clk_b),
+       FUNCTION(gcc_gp3_clk_a),
+       FUNCTION(gcc_gp3_clk_b),
+       FUNCTION(gpio),
+       FUNCTION(gsm_tx),
+       FUNCTION(hdmi_cec),
+       FUNCTION(hdmi_ddc),
+       FUNCTION(hdmi_hot),
+       FUNCTION(hdmi_rcv),
+       FUNCTION(isense_dbg),
+       FUNCTION(ldo_en),
+       FUNCTION(ldo_update),
+       FUNCTION(lpass_slimbus),
+       FUNCTION(m_voc),
+       FUNCTION(mdp_vsync),
+       FUNCTION(mdp_vsync_p_b),
+       FUNCTION(mdp_vsync_s_b),
+       FUNCTION(modem_tsync),
+       FUNCTION(mss_lte),
+       FUNCTION(nav_dr),
+       FUNCTION(nav_pps),
+       FUNCTION(pa_indicator),
+       FUNCTION(pci_e0),
+       FUNCTION(pci_e1),
+       FUNCTION(pci_e2),
+       FUNCTION(pll_bypassnl),
+       FUNCTION(pll_reset),
+       FUNCTION(pri_mi2s),
+       FUNCTION(prng_rosc),
+       FUNCTION(pwr_crypto),
+       FUNCTION(pwr_modem),
+       FUNCTION(pwr_nav),
+       FUNCTION(qdss_cti),
+       FUNCTION(qdss_cti_trig_in_a),
+       FUNCTION(qdss_cti_trig_in_b),
+       FUNCTION(qdss_cti_trig_out_a),
+       FUNCTION(qdss_cti_trig_out_b),
+       FUNCTION(qdss_stm0),
+       FUNCTION(qdss_stm1),
+       FUNCTION(qdss_stm10),
+       FUNCTION(qdss_stm11),
+       FUNCTION(qdss_stm12),
+       FUNCTION(qdss_stm13),
+       FUNCTION(qdss_stm14),
+       FUNCTION(qdss_stm15),
+       FUNCTION(qdss_stm16),
+       FUNCTION(qdss_stm17),
+       FUNCTION(qdss_stm18),
+       FUNCTION(qdss_stm19),
+       FUNCTION(qdss_stm2),
+       FUNCTION(qdss_stm20),
+       FUNCTION(qdss_stm21),
+       FUNCTION(qdss_stm22),
+       FUNCTION(qdss_stm23),
+       FUNCTION(qdss_stm24),
+       FUNCTION(qdss_stm25),
+       FUNCTION(qdss_stm26),
+       FUNCTION(qdss_stm27),
+       FUNCTION(qdss_stm28),
+       FUNCTION(qdss_stm29),
+       FUNCTION(qdss_stm3),
+       FUNCTION(qdss_stm30),
+       FUNCTION(qdss_stm31),
+       FUNCTION(qdss_stm4),
+       FUNCTION(qdss_stm5),
+       FUNCTION(qdss_stm6),
+       FUNCTION(qdss_stm7),
+       FUNCTION(qdss_stm8),
+       FUNCTION(qdss_stm9),
+       FUNCTION(qdss_traceclk_a),
+       FUNCTION(qdss_traceclk_b),
+       FUNCTION(qdss_tracectl_a),
+       FUNCTION(qdss_tracectl_b),
+       FUNCTION(qdss_tracedata_11),
+       FUNCTION(qdss_tracedata_12),
+       FUNCTION(qdss_tracedata_a),
+       FUNCTION(qdss_tracedata_b),
+       FUNCTION(qspi0),
+       FUNCTION(qspi1),
+       FUNCTION(qspi2),
+       FUNCTION(qspi3),
+       FUNCTION(qspi_clk),
+       FUNCTION(qspi_cs),
+       FUNCTION(qua_mi2s),
+       FUNCTION(sd_card),
+       FUNCTION(sd_write),
+       FUNCTION(sdc40),
+       FUNCTION(sdc41),
+       FUNCTION(sdc42),
+       FUNCTION(sdc43),
+       FUNCTION(sdc4_clk),
+       FUNCTION(sdc4_cmd),
+       FUNCTION(sec_mi2s),
+       FUNCTION(spkr_i2s),
+       FUNCTION(ssbi1),
+       FUNCTION(ssbi2),
+       FUNCTION(ssc_irq),
+       FUNCTION(ter_mi2s),
+       FUNCTION(tsense_pwm1),
+       FUNCTION(tsense_pwm2),
+       FUNCTION(tsif1_clk),
+       FUNCTION(tsif1_data),
+       FUNCTION(tsif1_en),
+       FUNCTION(tsif1_error),
+       FUNCTION(tsif1_sync),
+       FUNCTION(tsif2_clk),
+       FUNCTION(tsif2_data),
+       FUNCTION(tsif2_en),
+       FUNCTION(tsif2_error),
+       FUNCTION(tsif2_sync),
+       FUNCTION(uim1),
+       FUNCTION(uim2),
+       FUNCTION(uim3),
+       FUNCTION(uim4),
+       FUNCTION(uim_batt),
+       FUNCTION(vfr_1),
+};
+
+static const struct msm_pingroup msm8996_groups[] = {
+       PINGROUP(0, blsp_spi1, blsp_uart1, blsp_uim1, NA, NA, NA, NA, NA, NA),
+       PINGROUP(1, blsp_spi1, blsp_uart1, blsp_uim1, NA, NA, NA, NA, NA, NA),
+       PINGROUP(2, blsp_spi1, blsp_uart1, blsp_i2c1, NA, NA, NA, NA, NA, NA),
+       PINGROUP(3, blsp_spi1, blsp_uart1, blsp_i2c1, NA, atest_tsens,
+                bimc_dte1, NA, NA, NA),
+       PINGROUP(4, blsp_spi8, blsp_uart8, blsp_uim8, NA, qdss_cti_trig_out_b,
+                dac_calib0, bimc_dte0, NA, NA),
+       PINGROUP(5, blsp_spi8, blsp_uart8, blsp_uim8, NA, qdss_cti_trig_in_b,
+                dac_calib1, bimc_dte1, NA, NA),
+       PINGROUP(6, blsp_spi8, blsp_uart8, blsp_i2c8, NA, dac_calib2,
+                bimc_dte0, NA, NA, NA),
+       PINGROUP(7, blsp_spi8, blsp_uart8, blsp_i2c8, NA, atest_tsens2,
+                atest_usb1, NA, NA, NA),
+       PINGROUP(8, blsp_spi10, blsp_uart10, blsp_uim10, NA, atest_bbrx1,
+                atest_usb13, NA, NA, NA),
+       PINGROUP(9, blsp_spi10, blsp_uart10, blsp_uim10, atest_bbrx0,
+                atest_usb12, NA, NA, NA, NA),
+       PINGROUP(10, mdp_vsync, blsp_spi10, blsp_uart10, blsp_i2c10,
+                atest_gpsadc1, atest_usb11, NA, NA, NA),
+       PINGROUP(11, mdp_vsync, blsp_spi10, blsp_uart10, blsp_i2c10,
+                atest_gpsadc0, atest_usb10, NA, NA, NA),
+       PINGROUP(12, mdp_vsync, m_voc, dac_gpio, atest_char, NA, NA, NA, NA,
+                NA),
+       PINGROUP(13, cam_mclk, pll_bypassnl, qdss_stm7, qdss_tracedata_b, NA,
+                NA, NA, NA, NA),
+       PINGROUP(14, cam_mclk, pll_reset, qdss_stm6, qdss_tracedata_b, NA, NA,
+                NA, NA, NA),
+       PINGROUP(15, cam_mclk, qdss_stm5, qdss_tracedata_b, NA, NA, NA, NA, NA,
+                NA),
+       PINGROUP(16, cam_mclk, qdss_stm4, qdss_tracedata_b, NA, atest_usb2, NA,
+                NA, NA, NA),
+       PINGROUP(17, cci_i2c, qdss_stm3, qdss_tracedata_b, dac_calib3,
+                atest_usb23, atest_char3, NA, NA, NA),
+       PINGROUP(18, cci_i2c, qdss_stm2, qdss_tracedata_b, dac_calib4,
+                atest_usb22, atest_char2, NA, NA, NA),
+       PINGROUP(19, cci_i2c, qdss_stm1, qdss_tracedata_b, dac_calib5,
+                atest_usb21, atest_char1, NA, NA, NA),
+       PINGROUP(20, cci_i2c, dbg_out, qdss_stm0, dac_calib6, atest_usb20,
+                atest_char0, NA, NA, NA),
+       PINGROUP(21, cci_timer0, qdss_stm13, qdss_tracedata_b, dac_calib7, NA,
+                NA, NA, NA, NA),
+       PINGROUP(22, cci_timer1, qdss_stm12, qdss_tracedata_b, dac_calib8, NA,
+                NA, NA, NA, NA),
+       PINGROUP(23, cci_timer2, blsp1_spi, qdss_stm11, qdss_tracedata_b,
+                dac_calib9, NA, NA, NA, NA),
+       PINGROUP(24, cci_timer3, cci_async, blsp1_spi, qdss_stm10,
+                qdss_cti_trig_in_a, dac_calib10, NA, NA, NA),
+       PINGROUP(25, cci_timer4, cci_async, blsp_spi6, blsp_uart6, blsp_uim6,
+                blsp2_spi, qdss_stm9, qdss_cti_trig_out_a, dac_calib11),
+       PINGROUP(26, cci_async, blsp_spi6, blsp_uart6, blsp_uim6, qdss_stm8,
+                qdss_tracedata_b, dac_calib12, NA, NA),
+       PINGROUP(27, blsp_spi6, blsp_uart6, blsp_i2c6, blsp1_spi,
+                qdss_tracectl_a, dac_calib13, NA, NA, NA),
+       PINGROUP(28, blsp_spi6, blsp_uart6, blsp_i2c6, blsp1_spi,
+                qdss_traceclk_a, dac_calib14, NA, NA, NA),
+       PINGROUP(29, blsp2_spi, NA, qdss_tracedata_b, dac_calib15, NA, NA, NA,
+                NA, NA),
+       PINGROUP(30, hdmi_rcv, blsp2_spi, dac_calib16, NA, NA, NA, NA, NA, NA),
+       PINGROUP(31, hdmi_cec, pwr_modem, dac_calib17, NA, NA, NA, NA, NA, NA),
+       PINGROUP(32, hdmi_ddc, pwr_nav, NA, dac_calib18, NA, NA, NA, NA, NA),
+       PINGROUP(33, hdmi_ddc, pwr_crypto, NA, dac_calib19, NA, NA, NA, NA, NA),
+       PINGROUP(34, hdmi_hot, NA, dac_calib20, NA, NA, NA, NA, NA, NA),
+       PINGROUP(35, pci_e0, NA, dac_calib21, NA, NA, NA, NA, NA, NA),
+       PINGROUP(36, pci_e0, NA, dac_calib22, NA, NA, NA, NA, NA, NA),
+       PINGROUP(37, NA, dac_calib23, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(38, NA, dac_calib24, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(39, tsif1_sync, NA, dac_calib25, NA, NA, NA, NA, NA, NA),
+       PINGROUP(40, sd_write, tsif1_error, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(41, blsp_spi2, blsp_uart2, blsp_uim2, NA, qdss_cti,
+                dac_calib0, NA, NA, NA),
+       PINGROUP(42, blsp_spi2, blsp_uart2, blsp_uim2, NA, qdss_cti,
+                dac_calib1, NA, NA, NA),
+       PINGROUP(43, blsp_spi2, blsp_uart2, blsp_i2c2, NA, dac_calib2, NA, NA,
+                NA, NA),
+       PINGROUP(44, blsp_spi2, blsp_uart2, blsp_i2c2, NA, dac_calib3, NA, NA,
+                NA, NA),
+       PINGROUP(45, blsp_spi3, blsp_uart3, blsp_uim3, NA, dac_calib4, NA, NA,
+                NA, NA),
+       PINGROUP(46, blsp_spi3, blsp_uart3, blsp_uim3, NA, dac_calib5, NA, NA,
+                NA, NA),
+       PINGROUP(47, blsp_spi3, blsp_uart3, blsp_i2c3, dac_calib6, NA, NA, NA,
+                NA, NA),
+       PINGROUP(48, blsp_spi3, blsp_uart3, blsp_i2c3, dac_calib7, NA, NA, NA,
+                NA, NA),
+       PINGROUP(49, uim3, blsp_spi9, blsp_uart9, blsp_uim9, blsp10_spi,
+                dac_calib8, NA, NA, NA),
+       PINGROUP(50, uim3, blsp_spi9, blsp_uart9, blsp_uim9, blsp10_spi,
+                dac_calib9, NA, NA, NA),
+       PINGROUP(51, uim3, blsp_spi9, blsp_uart9, blsp_i2c9, blsp10_spi,
+                dac_calib10, NA, NA, NA),
+       PINGROUP(52, uim3, blsp_spi9, blsp_uart9, blsp_i2c9,
+                blsp10_spi, dac_calib11, NA, NA, NA),
+       PINGROUP(53, blsp_spi7, blsp_uart7, blsp_uim7, NA, qdss_tracedata_a,
+                dac_calib12, NA, NA, NA),
+       PINGROUP(54, blsp_spi7, blsp_uart7, blsp_uim7, NA, NA,
+                qdss_tracedata_a, dac_calib13, NA, NA),
+       PINGROUP(55, blsp_spi7, blsp_uart7, blsp_i2c7, NA, dac_calib14, NA, NA,
+                NA, NA),
+       PINGROUP(56, blsp_spi7, blsp_uart7, blsp_i2c7, NA, dac_calib15, NA, NA,
+                NA, NA),
+       PINGROUP(57, qua_mi2s, gcc_gp1_clk_a, NA, qdss_tracedata_b,
+                dac_calib16, NA, NA, NA, NA),
+       PINGROUP(58, qua_mi2s, uim4, blsp_spi11, blsp_uart11, blsp_uim11,
+                gcc_gp2_clk_a, NA, qdss_tracedata_b, dac_calib17),
+       PINGROUP(59, qua_mi2s, uim4, blsp_spi11, blsp_uart11, blsp_uim11,
+                gcc_gp3_clk_a, NA, dac_calib18, NA),
+       PINGROUP(60, qua_mi2s, uim4, blsp_spi11, blsp_uart11, blsp_i2c11,
+                cri_trng0, NA, dac_calib19, NA),
+       PINGROUP(61, qua_mi2s, uim4, blsp_spi11, blsp_uart11,
+                blsp_i2c11, cri_trng1, NA, dac_calib20, NA),
+       PINGROUP(62, qua_mi2s, cri_trng, NA, dac_calib21, NA, NA, NA, NA, NA),
+       PINGROUP(63, qua_mi2s, NA, NA, qdss_stm18, qdss_tracedata_a,
+                dac_calib22, NA, NA, NA),
+       PINGROUP(64, pri_mi2s, NA, qdss_stm17, qdss_tracedata_a, dac_calib23,
+                NA, NA, NA, NA),
+       PINGROUP(65, pri_mi2s, blsp_spi4, blsp_uart4, blsp_uim4, NA,
+                qdss_stm16, qdss_tracedata_a, dac_calib24, NA),
+       PINGROUP(66, pri_mi2s, blsp_spi4, blsp_uart4, blsp_uim4, NA,
+                qdss_stm15, qdss_tracedata_a, dac_calib25, NA),
+       PINGROUP(67, pri_mi2s, blsp_spi4, blsp_uart4, blsp_i2c4, qdss_stm14,
+                qdss_tracedata_a, dac_calib26, NA, NA),
+       PINGROUP(68, pri_mi2s, blsp_spi4, blsp_uart4, blsp_i2c4, NA, NA, NA,
+                NA, NA),
+       PINGROUP(69, spkr_i2s, audio_ref, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(70, lpass_slimbus, spkr_i2s, isense_dbg, NA, NA, NA, NA, NA,
+                NA),
+       PINGROUP(71, lpass_slimbus, spkr_i2s, tsense_pwm1, tsense_pwm2, NA, NA,
+                NA, NA, NA),
+       PINGROUP(72, lpass_slimbus, spkr_i2s, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(73, btfm_slimbus, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(74, btfm_slimbus, ter_mi2s, qdss_stm22, qdss_tracedata_a, NA,
+                NA, NA, NA, NA),
+       PINGROUP(75, ter_mi2s, qdss_stm21, qdss_tracedata_a, NA, NA, NA, NA,
+                NA, NA),
+       PINGROUP(76, ter_mi2s, qdss_stm20, qdss_tracedata_a, NA, NA, NA, NA,
+                NA, NA),
+       PINGROUP(77, ter_mi2s, qdss_stm19, qdss_tracedata_a, NA, NA, NA, NA,
+                NA, NA),
+       PINGROUP(78, ter_mi2s, gcc_gp1_clk_b, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(79, sec_mi2s, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(80, sec_mi2s, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(81, sec_mi2s, blsp_spi5, blsp_uart5, blsp_uim5, gcc_gp2_clk_b,
+                NA, NA, NA, NA),
+       PINGROUP(82, sec_mi2s, blsp_spi5, blsp_uart5, blsp_uim5, gcc_gp3_clk_b,
+                NA, NA, NA, NA),
+       PINGROUP(83, sec_mi2s, blsp_spi5, blsp_uart5, blsp_i2c5, NA, NA, NA,
+                NA, NA),
+       PINGROUP(84, blsp_spi5, blsp_uart5, blsp_i2c5, NA, NA, NA, NA, NA, NA),
+       PINGROUP(85, blsp_spi12, blsp_uart12, blsp_uim12, NA, qdss_stm25,
+                qdss_tracedata_a, NA, NA, NA),
+       PINGROUP(86, blsp_spi12, blsp_uart12, blsp_uim12, NA, NA, qdss_stm31,
+                qdss_tracedata_a, NA, NA),
+       PINGROUP(87, blsp_spi12, blsp_uart12, blsp_i2c12, NA, qdss_stm30,
+                qdss_tracedata_a, NA, NA, NA),
+       PINGROUP(88, blsp_spi12, blsp_uart12, blsp_i2c12, blsp10_spi, NA,
+                qdss_stm29, NA, NA, NA),
+       PINGROUP(89, tsif1_clk, qdss_stm28, qdss_tracedata_a, NA, NA, NA, NA,
+                NA, NA),
+       PINGROUP(90, tsif1_en, blsp1_spi, qdss_tracedata_a, NA, NA, NA, NA, NA,
+                NA),
+       PINGROUP(91, tsif1_data, sdc4_cmd, qdss_stm27, qdss_traceclk_b, NA, NA,
+                NA, NA, NA),
+       PINGROUP(92, tsif2_error, sdc43, vfr_1, qdss_stm26, qdss_tracedata_b,
+                NA, NA, NA, NA),
+       PINGROUP(93, tsif2_clk, sdc4_clk, NA, qdss_stm24, qdss_tracedata_b, NA,
+                NA, NA, NA),
+       PINGROUP(94, tsif2_en, sdc42, NA, qdss_stm23, qdss_tracectl_b, NA, NA,
+                NA, NA),
+       PINGROUP(95, tsif2_data, sdc41, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(96, tsif2_sync, sdc40, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(97, NA, NA, mdp_vsync_p_b, ldo_en, NA, NA, NA, NA, NA),
+       PINGROUP(98, NA, NA, mdp_vsync_s_b, ldo_update, NA, NA, NA, NA, NA),
+       PINGROUP(99, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(100, NA, NA, blsp11_uart_tx_b, qdss_cti, NA, NA, NA, NA, NA),
+       PINGROUP(101, NA, blsp11_uart_rx_b, qdss_cti, NA, NA, NA, NA, NA, NA),
+       PINGROUP(102, NA, blsp11_i2c_sda_b, prng_rosc, NA, NA, NA, NA, NA, NA),
+       PINGROUP(103, NA, blsp11_i2c_scl_b, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(104, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(105, uim2, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(106, uim2, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(107, uim2, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(108, uim2, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(109, uim1, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(110, uim1, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(111, uim1, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(112, uim1, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(113, uim_batt, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(114, NA, pci_e2, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(115, NA, pci_e2, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(116, NA, pa_indicator, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(117, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(118, adsp_ext, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(119, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(120, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(121, ddr_bist, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(122, ddr_bist, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(123, ddr_bist, qdss_tracedata_11, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(124, ddr_bist, qdss_tracedata_12, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(125, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(126, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(127, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(128, NA, modem_tsync, nav_dr, nav_pps, NA, NA, NA, NA, NA),
+       PINGROUP(129, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(130, pci_e1, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(131, pci_e1, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(132, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(133, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(134, gsm_tx, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(135, gsm_tx, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(136, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(137, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(138, NA, qspi_cs, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(139, NA, ssbi2, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(140, NA, ssbi1, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(141, NA, qspi_cs, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(142, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(143, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(144, mss_lte, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(145, mss_lte, qspi_clk, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(146, NA, qspi0, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(147, NA, qspi1, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(148, NA, qspi2, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(149, NA, qspi3, NA, NA, NA, NA, NA, NA, NA),
+       SDC_QDSD_PINGROUP(sdc1_clk, 0x12c000, 13, 6),
+       SDC_QDSD_PINGROUP(sdc1_cmd, 0x12c000, 11, 3),
+       SDC_QDSD_PINGROUP(sdc1_data, 0x12c000, 9, 0),
+       SDC_QDSD_PINGROUP(sdc2_clk, 0x12d000, 14, 6),
+       SDC_QDSD_PINGROUP(sdc2_cmd, 0x12d000, 11, 3),
+       SDC_QDSD_PINGROUP(sdc2_data, 0x12d000, 9, 0),
+       SDC_QDSD_PINGROUP(sdc1_rclk, 0x12c000, 15, 0),
+};
+
+static const struct msm_pinctrl_soc_data msm8996_pinctrl = {
+       .pins = msm8996_pins,
+       .npins = ARRAY_SIZE(msm8996_pins),
+       .functions = msm8996_functions,
+       .nfunctions = ARRAY_SIZE(msm8996_functions),
+       .groups = msm8996_groups,
+       .ngroups = ARRAY_SIZE(msm8996_groups),
+       .ngpios = 150,
+};
+
+static int msm8996_pinctrl_probe(struct platform_device *pdev)
+{
+       return msm_pinctrl_probe(pdev, &msm8996_pinctrl);
+}
+
+static const struct of_device_id msm8996_pinctrl_of_match[] = {
+       { .compatible = "qcom,msm8996-pinctrl", },
+       { }
+};
+
+static struct platform_driver msm8996_pinctrl_driver = {
+       .driver = {
+               .name = "msm8996-pinctrl",
+               .of_match_table = msm8996_pinctrl_of_match,
+       },
+       .probe = msm8996_pinctrl_probe,
+       .remove = msm_pinctrl_remove,
+};
+
+static int __init msm8996_pinctrl_init(void)
+{
+       return platform_driver_register(&msm8996_pinctrl_driver);
+}
+arch_initcall(msm8996_pinctrl_init);
+
+static void __exit msm8996_pinctrl_exit(void)
+{
+       platform_driver_unregister(&msm8996_pinctrl_driver);
+}
+module_exit(msm8996_pinctrl_exit);
+
+MODULE_DESCRIPTION("Qualcomm msm8996 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, msm8996_pinctrl_of_match);
index e9ff3bc150bbc7ee441c91f591dbc19f3a4bf438..f448534edf467d31c6fb3cc3a59adcccf8eea797 100644 (file)
@@ -32,6 +32,9 @@
 
 static struct msm_pinctrl_soc_data qdf2xxx_pinctrl;
 
+/* A reasonable limit to the number of GPIOS */
+#define MAX_GPIOS      256
+
 static int qdf2xxx_pinctrl_probe(struct platform_device *pdev)
 {
        struct pinctrl_pin_desc *pins;
@@ -42,11 +45,13 @@ static int qdf2xxx_pinctrl_probe(struct platform_device *pdev)
 
        /* Query the number of GPIOs from ACPI */
        ret = device_property_read_u32(&pdev->dev, "num-gpios", &num_gpios);
-       if (ret < 0)
+       if (ret < 0) {
+               dev_warn(&pdev->dev, "missing num-gpios property\n");
                return ret;
+       }
 
-       if (!num_gpios) {
-               dev_warn(&pdev->dev, "missing num-gpios property\n");
+       if (!num_gpios || num_gpios > MAX_GPIOS) {
+               dev_warn(&pdev->dev, "invalid num-gpios property\n");
                return -ENODEV;
        }
 
@@ -55,6 +60,9 @@ static int qdf2xxx_pinctrl_probe(struct platform_device *pdev)
        groups = devm_kcalloc(&pdev->dev, num_gpios,
                sizeof(struct msm_pingroup), GFP_KERNEL);
 
+       if (!pins || !groups)
+               return -ENOMEM;
+
        for (i = 0; i < num_gpios; i++) {
                pins[i].number = i;
 
index 6c42ca14d2fd315d9e43faca2a48315815d53bd8..77f6a5cb10081f80dba4a39e1e6711f5da0e9277 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/gpio.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_irq.h>
 #include <linux/pinctrl/pinconf-generic.h>
 #include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinmux.h>
@@ -693,18 +694,19 @@ static int pmic_gpio_probe(struct platform_device *pdev)
        struct pmic_gpio_pad *pad, *pads;
        struct pmic_gpio_state *state;
        int ret, npins, i;
-       u32 res[2];
+       u32 reg;
 
-       ret = of_property_read_u32_array(dev->of_node, "reg", res, 2);
+       ret = of_property_read_u32(dev->of_node, "reg", &reg);
        if (ret < 0) {
-               dev_err(dev, "missing base address and/or range");
+               dev_err(dev, "missing base address");
                return ret;
        }
 
-       npins = res[1] / PMIC_GPIO_ADDRESS_RANGE;
-
+       npins = platform_irq_count(pdev);
        if (!npins)
                return -EINVAL;
+       if (npins < 0)
+               return npins;
 
        BUG_ON(npins > ARRAY_SIZE(pmic_gpio_groups));
 
@@ -752,7 +754,7 @@ static int pmic_gpio_probe(struct platform_device *pdev)
                if (pad->irq < 0)
                        return pad->irq;
 
-               pad->base = res[0] + i * PMIC_GPIO_ADDRESS_RANGE;
+               pad->base = reg + i * PMIC_GPIO_ADDRESS_RANGE;
 
                ret = pmic_gpio_populate(state, pad);
                if (ret < 0)
@@ -804,6 +806,7 @@ static int pmic_gpio_remove(struct platform_device *pdev)
 static const struct of_device_id pmic_gpio_of_match[] = {
        { .compatible = "qcom,pm8916-gpio" },   /* 4 GPIO's */
        { .compatible = "qcom,pm8941-gpio" },   /* 36 GPIO's */
+       { .compatible = "qcom,pm8994-gpio" },   /* 22 GPIO's */
        { .compatible = "qcom,pma8084-gpio" },  /* 22 GPIO's */
        { },
 };
index 9ce0e30e33e81b024ecee8169d86b165ce1d69d7..2df4f29175ae9cd588a398af8a62cfdeb097f267 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/gpio.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_irq.h>
 #include <linux/pinctrl/pinconf-generic.h>
 #include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinmux.h>
@@ -795,17 +796,19 @@ static int pmic_mpp_probe(struct platform_device *pdev)
        struct pmic_mpp_pad *pad, *pads;
        struct pmic_mpp_state *state;
        int ret, npins, i;
-       u32 res[2];
+       u32 reg;
 
-       ret = of_property_read_u32_array(dev->of_node, "reg", res, 2);
+       ret = of_property_read_u32(dev->of_node, "reg", &reg);
        if (ret < 0) {
-               dev_err(dev, "missing base address and/or range");
+               dev_err(dev, "missing base address");
                return ret;
        }
 
-       npins = res[1] / PMIC_MPP_ADDRESS_RANGE;
+       npins = platform_irq_count(pdev);
        if (!npins)
                return -EINVAL;
+       if (npins < 0)
+               return npins;
 
        BUG_ON(npins > ARRAY_SIZE(pmic_mpp_groups));
 
@@ -854,7 +857,7 @@ static int pmic_mpp_probe(struct platform_device *pdev)
                if (pad->irq < 0)
                        return pad->irq;
 
-               pad->base = res[0] + i * PMIC_MPP_ADDRESS_RANGE;
+               pad->base = reg + i * PMIC_MPP_ADDRESS_RANGE;
 
                ret = pmic_mpp_populate(state, pad);
                if (ret < 0)
@@ -907,6 +910,7 @@ static const struct of_device_id pmic_mpp_of_match[] = {
        { .compatible = "qcom,pm8841-mpp" },    /* 4 MPP's */
        { .compatible = "qcom,pm8916-mpp" },    /* 4 MPP's */
        { .compatible = "qcom,pm8941-mpp" },    /* 8 MPP's */
+       { .compatible = "qcom,pm8994-mpp" },    /* 8 MPP's */
        { .compatible = "qcom,pma8084-mpp" },   /* 8 MPP's */
        { },
 };
index 19a3c3bc2f1f7213d31ea8f23ef56b815031a3a0..e51176ec83d2b50f092729ab0515bc0fa604d01b 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/of_device.h>
+#include <linux/of_irq.h>
 
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
 
@@ -650,11 +651,12 @@ static int pm8xxx_pin_populate(struct pm8xxx_gpio *pctrl,
 }
 
 static const struct of_device_id pm8xxx_gpio_of_match[] = {
-       { .compatible = "qcom,pm8018-gpio", .data = (void *)6 },
-       { .compatible = "qcom,pm8038-gpio", .data = (void *)12 },
-       { .compatible = "qcom,pm8058-gpio", .data = (void *)40 },
-       { .compatible = "qcom,pm8917-gpio", .data = (void *)38 },
-       { .compatible = "qcom,pm8921-gpio", .data = (void *)44 },
+       { .compatible = "qcom,pm8018-gpio" },
+       { .compatible = "qcom,pm8038-gpio" },
+       { .compatible = "qcom,pm8058-gpio" },
+       { .compatible = "qcom,pm8917-gpio" },
+       { .compatible = "qcom,pm8921-gpio" },
+       { .compatible = "qcom,ssbi-gpio" },
        { },
 };
 MODULE_DEVICE_TABLE(of, pm8xxx_gpio_of_match);
@@ -665,14 +667,19 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev)
        struct pinctrl_pin_desc *pins;
        struct pm8xxx_gpio *pctrl;
        int ret;
-       int i;
+       int i, npins;
 
        pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
        if (!pctrl)
                return -ENOMEM;
 
        pctrl->dev = &pdev->dev;
-       pctrl->npins = (unsigned long)of_device_get_match_data(&pdev->dev);
+       npins = platform_irq_count(pdev);
+       if (!npins)
+               return -EINVAL;
+       if (npins < 0)
+               return npins;
+       pctrl->npins = npins;
 
        pctrl->regmap = dev_get_regmap(pdev->dev.parent, NULL);
        if (!pctrl->regmap) {
index b868ef1766a0910e50dbfe43b80e650cea19739f..e9f01de51e182e41a3fbfb9e4d4f565d0c131fdd 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/of_device.h>
+#include <linux/of_irq.h>
 
 #include <dt-bindings/pinctrl/qcom,pmic-mpp.h>
 
@@ -741,11 +742,12 @@ static int pm8xxx_pin_populate(struct pm8xxx_mpp *pctrl,
 }
 
 static const struct of_device_id pm8xxx_mpp_of_match[] = {
-       { .compatible = "qcom,pm8018-mpp", .data = (void *)6 },
-       { .compatible = "qcom,pm8038-mpp", .data = (void *)6 },
-       { .compatible = "qcom,pm8917-mpp", .data = (void *)10 },
-       { .compatible = "qcom,pm8821-mpp", .data = (void *)4 },
-       { .compatible = "qcom,pm8921-mpp", .data = (void *)12 },
+       { .compatible = "qcom,pm8018-mpp" },
+       { .compatible = "qcom,pm8038-mpp" },
+       { .compatible = "qcom,pm8917-mpp" },
+       { .compatible = "qcom,pm8821-mpp" },
+       { .compatible = "qcom,pm8921-mpp" },
+       { .compatible = "qcom,ssbi-mpp" },
        { },
 };
 MODULE_DEVICE_TABLE(of, pm8xxx_mpp_of_match);
@@ -756,14 +758,19 @@ static int pm8xxx_mpp_probe(struct platform_device *pdev)
        struct pinctrl_pin_desc *pins;
        struct pm8xxx_mpp *pctrl;
        int ret;
-       int i;
+       int i, npins;
 
        pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
        if (!pctrl)
                return -ENOMEM;
 
        pctrl->dev = &pdev->dev;
-       pctrl->npins = (unsigned long)of_device_get_match_data(&pdev->dev);
+       npins = platform_irq_count(pdev);
+       if (!npins)
+               return -EINVAL;
+       if (npins < 0)
+               return npins;
+       pctrl->npins = npins;
 
        pctrl->regmap = dev_get_regmap(pdev->dev.parent, NULL);
        if (!pctrl->regmap) {
index 71ccf6a90b222d14a02f771862d8c227cc115b80..16e2293cc2bcdcc2c01cfc03d26982edc9376962 100644 (file)
@@ -1150,6 +1150,109 @@ const struct samsung_pin_ctrl exynos5260_pin_ctrl[] __initconst = {
        },
 };
 
+/* pin banks of exynos5410 pin-controller 0 */
+static const struct samsung_pin_bank_data exynos5410_pin_banks0[] __initconst = {
+       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
+       EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08),
+       EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpb0", 0x0c),
+       EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpb1", 0x10),
+       EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpb2", 0x14),
+       EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpb3", 0x18),
+       EXYNOS_PIN_BANK_EINTG(7, 0x0E0, "gpc0", 0x1c),
+       EXYNOS_PIN_BANK_EINTG(4, 0x100, "gpc3", 0x20),
+       EXYNOS_PIN_BANK_EINTG(7, 0x120, "gpc1", 0x24),
+       EXYNOS_PIN_BANK_EINTG(7, 0x140, "gpc2", 0x28),
+       EXYNOS_PIN_BANK_EINTN(2, 0x160, "gpm5"),
+       EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpd1", 0x2c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x1A0, "gpe0", 0x30),
+       EXYNOS_PIN_BANK_EINTG(2, 0x1C0, "gpe1", 0x34),
+       EXYNOS_PIN_BANK_EINTG(6, 0x1E0, "gpf0", 0x38),
+       EXYNOS_PIN_BANK_EINTG(8, 0x200, "gpf1", 0x3c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x220, "gpg0", 0x40),
+       EXYNOS_PIN_BANK_EINTG(8, 0x240, "gpg1", 0x44),
+       EXYNOS_PIN_BANK_EINTG(2, 0x260, "gpg2", 0x48),
+       EXYNOS_PIN_BANK_EINTG(4, 0x280, "gph0", 0x4c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x2A0, "gph1", 0x50),
+       EXYNOS_PIN_BANK_EINTN(8, 0x2C0, "gpm7"),
+       EXYNOS_PIN_BANK_EINTN(6, 0x2E0, "gpy0"),
+       EXYNOS_PIN_BANK_EINTN(4, 0x300, "gpy1"),
+       EXYNOS_PIN_BANK_EINTN(6, 0x320, "gpy2"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x340, "gpy3"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x360, "gpy4"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x380, "gpy5"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x3A0, "gpy6"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x3C0, "gpy7"),
+       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 exynos5410 pin-controller 1 */
+static const struct samsung_pin_bank_data exynos5410_pin_banks1[] __initconst = {
+       EXYNOS_PIN_BANK_EINTG(5, 0x000, "gpj0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpj1", 0x04),
+       EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpj2", 0x08),
+       EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpj3", 0x0c),
+       EXYNOS_PIN_BANK_EINTG(2, 0x080, "gpj4", 0x10),
+       EXYNOS_PIN_BANK_EINTG(8, 0x0A0, "gpk0", 0x14),
+       EXYNOS_PIN_BANK_EINTG(8, 0x0C0, "gpk1", 0x18),
+       EXYNOS_PIN_BANK_EINTG(8, 0x0E0, "gpk2", 0x1c),
+       EXYNOS_PIN_BANK_EINTG(7, 0x100, "gpk3", 0x20),
+};
+
+/* pin banks of exynos5410 pin-controller 2 */
+static const struct samsung_pin_bank_data exynos5410_pin_banks2[] __initconst = {
+       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpv0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpv1", 0x04),
+       EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpv2", 0x08),
+       EXYNOS_PIN_BANK_EINTG(8, 0x080, "gpv3", 0x0c),
+       EXYNOS_PIN_BANK_EINTG(2, 0x0C0, "gpv4", 0x10),
+};
+
+/* pin banks of exynos5410 pin-controller 3 */
+static const struct samsung_pin_bank_data exynos5410_pin_banks3[] __initconst = {
+       EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
+};
+
+/*
+ * Samsung pinctrl driver data for Exynos5410 SoC. Exynos5410 SoC includes
+ * four gpio/pin-mux/pinconfig controllers.
+ */
+const struct samsung_pin_ctrl exynos5410_pin_ctrl[] __initconst = {
+       {
+               /* pin-controller instance 0 data */
+               .pin_banks      = exynos5410_pin_banks0,
+               .nr_banks       = ARRAY_SIZE(exynos5410_pin_banks0),
+               .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 1 data */
+               .pin_banks      = exynos5410_pin_banks1,
+               .nr_banks       = ARRAY_SIZE(exynos5410_pin_banks1),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .suspend        = exynos_pinctrl_suspend,
+               .resume         = exynos_pinctrl_resume,
+       }, {
+               /* pin-controller instance 2 data */
+               .pin_banks      = exynos5410_pin_banks2,
+               .nr_banks       = ARRAY_SIZE(exynos5410_pin_banks2),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .suspend        = exynos_pinctrl_suspend,
+               .resume         = exynos_pinctrl_resume,
+       }, {
+               /* pin-controller instance 3 data */
+               .pin_banks      = exynos5410_pin_banks3,
+               .nr_banks       = ARRAY_SIZE(exynos5410_pin_banks3),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .suspend        = exynos_pinctrl_suspend,
+               .resume         = exynos_pinctrl_resume,
+       },
+};
+
 /* pin banks of exynos5420 pin-controller 0 */
 static const struct samsung_pin_bank_data exynos5420_pin_banks0[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpy7", 0x00),
index 3f622ccd8eabd74a3f0df889298254dbcdee1510..48294e7449a4e212d95cd90418b160b4e7fba0ad 100644 (file)
@@ -1222,6 +1222,8 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = {
                .data = (void *)exynos5250_pin_ctrl },
        { .compatible = "samsung,exynos5260-pinctrl",
                .data = (void *)exynos5260_pin_ctrl },
+       { .compatible = "samsung,exynos5410-pinctrl",
+               .data = (void *)exynos5410_pin_ctrl },
        { .compatible = "samsung,exynos5420-pinctrl",
                .data = (void *)exynos5420_pin_ctrl },
        { .compatible = "samsung,exynos5433-pinctrl",
index c1239ff6157d0d5bbfc3524e7664c617660eb94b..cd31bfaf62cb6e33d296e1ba9171933a64434ac4 100644 (file)
@@ -270,6 +270,7 @@ 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[];
 extern const struct samsung_pin_ctrl exynos5420_pin_ctrl[];
 extern const struct samsung_pin_ctrl exynos5433_pin_ctrl[];
 extern const struct samsung_pin_ctrl exynos7_pin_ctrl[];
index 02118ab336fcbd6c7b91bc7058e0460a0834e5c1..1cbbe04d7df657e8fa11bfddc93433739a9a73ec 100644 (file)
@@ -258,18 +258,18 @@ static const u16 pinmux_data[] = {
 
        /* GPSR0 */
        /* V9 */
-       PINMUX_DATA(JT_SEL_MARK, FN_JT_SEL),
+       PINMUX_SINGLE(JT_SEL),
        /* U9 */
-       PINMUX_DATA(ERR_RST_REQB_MARK, FN_ERR_RST_REQB),
+       PINMUX_SINGLE(ERR_RST_REQB),
        /* V8 */
-       PINMUX_DATA(REF_CLKO_MARK, FN_REF_CLKO),
+       PINMUX_SINGLE(REF_CLKO),
        /* U8 */
-       PINMUX_DATA(EXT_CLKI_MARK, FN_EXT_CLKI),
+       PINMUX_SINGLE(EXT_CLKI),
        /* B22*/
        PINMUX_IPSR_NOFN(LCD3_1_0_PORT18, LCD3_PXCLK, SEL_LCD3_1_0_00),
        PINMUX_IPSR_NOFN(LCD3_1_0_PORT18, YUV3_CLK_O, SEL_LCD3_1_0_01),
        /* C21 */
-       PINMUX_DATA(LCD3_PXCLKB_MARK, FN_LCD3_PXCLKB),
+       PINMUX_SINGLE(LCD3_PXCLKB),
        /* A21 */
        PINMUX_IPSR_NOFN(LCD3_1_0_PORT20, LCD3_CLK_I, SEL_LCD3_1_0_00),
        PINMUX_IPSR_NOFN(LCD3_1_0_PORT20, YUV3_CLK_I, SEL_LCD3_1_0_01),
@@ -285,17 +285,17 @@ static const u16 pinmux_data[] = {
 
        /* GPSR1 */
        /* A20 */
-       PINMUX_DATA(LCD3_R0_MARK, FN_LCD3_R0),
+       PINMUX_SINGLE(LCD3_R0),
        /* B20 */
-       PINMUX_DATA(LCD3_R1_MARK, FN_LCD3_R1),
+       PINMUX_SINGLE(LCD3_R1),
        /* A19 */
-       PINMUX_DATA(LCD3_R2_MARK, FN_LCD3_R2),
+       PINMUX_SINGLE(LCD3_R2),
        /* B19 */
-       PINMUX_DATA(LCD3_R3_MARK, FN_LCD3_R3),
+       PINMUX_SINGLE(LCD3_R3),
        /* C19 */
-       PINMUX_DATA(LCD3_R4_MARK, FN_LCD3_R4),
+       PINMUX_SINGLE(LCD3_R4),
        /* B18 */
-       PINMUX_DATA(LCD3_R5_MARK, FN_LCD3_R5),
+       PINMUX_SINGLE(LCD3_R5),
        /* C18 */
        PINMUX_IPSR_NOFN(LCD3_9_8_PORT38, LCD3_R6, SEL_LCD3_9_8_00),
        PINMUX_IPSR_NOFN(LCD3_9_8_PORT38, TP33_CLK, SEL_LCD3_9_8_10),
@@ -367,9 +367,9 @@ static const u16 pinmux_data[] = {
        PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, YUV3_D15, SEL_LCD3_11_10_01),
        PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, TP33_DATA15, SEL_LCD3_11_10_10),
        /* AA9 */
-       PINMUX_DATA(IIC0_SCL_MARK, FN_IIC0_SCL),
+       PINMUX_SINGLE(IIC0_SCL),
        /* AA8 */
-       PINMUX_DATA(IIC0_SDA_MARK, FN_IIC0_SDA),
+       PINMUX_SINGLE(IIC0_SDA),
        /* Y9 */
        PINMUX_IPSR_NOFN(IIC_1_0_PORT46, IIC1_SCL, SEL_IIC_1_0_00),
        PINMUX_IPSR_NOFN(IIC_1_0_PORT46, UART3_RX, SEL_IIC_1_0_01),
@@ -377,51 +377,51 @@ static const u16 pinmux_data[] = {
        PINMUX_IPSR_NOFN(IIC_1_0_PORT47, IIC1_SDA, SEL_IIC_1_0_00),
        PINMUX_IPSR_NOFN(IIC_1_0_PORT47, UART3_TX, SEL_IIC_1_0_01),
        /* AC19 */
-       PINMUX_DATA(SD_CKI_MARK, FN_SD_CKI),
+       PINMUX_SINGLE(SD_CKI),
        /* AB18 */
-       PINMUX_DATA(SDI0_CKO_MARK, FN_SDI0_CKO),
+       PINMUX_SINGLE(SDI0_CKO),
        /* AC18 */
-       PINMUX_DATA(SDI0_CKI_MARK, FN_SDI0_CKI),
+       PINMUX_SINGLE(SDI0_CKI),
        /* Y12 */
-       PINMUX_DATA(SDI0_CMD_MARK, FN_SDI0_CMD),
+       PINMUX_SINGLE(SDI0_CMD),
        /* AA13 */
-       PINMUX_DATA(SDI0_DATA0_MARK, FN_SDI0_DATA0),
+       PINMUX_SINGLE(SDI0_DATA0),
        /* Y13 */
-       PINMUX_DATA(SDI0_DATA1_MARK, FN_SDI0_DATA1),
+       PINMUX_SINGLE(SDI0_DATA1),
        /* AA14 */
-       PINMUX_DATA(SDI0_DATA2_MARK, FN_SDI0_DATA2),
+       PINMUX_SINGLE(SDI0_DATA2),
        /* Y14 */
-       PINMUX_DATA(SDI0_DATA3_MARK, FN_SDI0_DATA3),
+       PINMUX_SINGLE(SDI0_DATA3),
        /* AA15 */
-       PINMUX_DATA(SDI0_DATA4_MARK, FN_SDI0_DATA4),
+       PINMUX_SINGLE(SDI0_DATA4),
        /* Y15 */
-       PINMUX_DATA(SDI0_DATA5_MARK, FN_SDI0_DATA5),
+       PINMUX_SINGLE(SDI0_DATA5),
        /* AA16 */
-       PINMUX_DATA(SDI0_DATA6_MARK, FN_SDI0_DATA6),
+       PINMUX_SINGLE(SDI0_DATA6),
        /* Y16 */
-       PINMUX_DATA(SDI0_DATA7_MARK, FN_SDI0_DATA7),
+       PINMUX_SINGLE(SDI0_DATA7),
        /* AB22 */
-       PINMUX_DATA(SDI1_CKO_MARK, FN_SDI1_CKO),
+       PINMUX_SINGLE(SDI1_CKO),
        /* AA23 */
-       PINMUX_DATA(SDI1_CKI_MARK, FN_SDI1_CKI),
+       PINMUX_SINGLE(SDI1_CKI),
        /* AC21 */
-       PINMUX_DATA(SDI1_CMD_MARK, FN_SDI1_CMD),
+       PINMUX_SINGLE(SDI1_CMD),
 
        /* GPSR2 */
        /* AB21 */
-       PINMUX_DATA(SDI1_DATA0_MARK, FN_SDI1_DATA0),
+       PINMUX_SINGLE(SDI1_DATA0),
        /* AB20 */
-       PINMUX_DATA(SDI1_DATA1_MARK, FN_SDI1_DATA1),
+       PINMUX_SINGLE(SDI1_DATA1),
        /* AB19 */
-       PINMUX_DATA(SDI1_DATA2_MARK, FN_SDI1_DATA2),
+       PINMUX_SINGLE(SDI1_DATA2),
        /* AA19 */
-       PINMUX_DATA(SDI1_DATA3_MARK, FN_SDI1_DATA3),
+       PINMUX_SINGLE(SDI1_DATA3),
        /* J23 */
-       PINMUX_DATA(AB_CLK_MARK, FN_AB_CLK),
+       PINMUX_SINGLE(AB_CLK),
        /* D21 */
-       PINMUX_DATA(AB_CSB0_MARK, FN_AB_CSB0),
+       PINMUX_SINGLE(AB_CSB0),
        /* E21 */
-       PINMUX_DATA(AB_CSB1_MARK, FN_AB_CSB1),
+       PINMUX_SINGLE(AB_CSB1),
        /* F20 */
        PINMUX_IPSR_NOFN(AB_1_0_PORT71, AB_CSB2, SEL_AB_1_0_00),
        PINMUX_IPSR_NOFN(AB_1_0_PORT71, CF_CSB0, SEL_AB_1_0_10),
@@ -514,7 +514,7 @@ static const u16 pinmux_data[] = {
 
        /* GPSR3 */
        /* M21 */
-       PINMUX_DATA(AB_A20_MARK, FN_AB_A20),
+       PINMUX_SINGLE(AB_A20),
        /* N21 */
        PINMUX_IPSR_NOFN(AB_9_8_PORT97, AB_A21, SEL_AB_9_8_00),
        PINMUX_IPSR_NOFN(AB_9_8_PORT97, SDI2_CKO, SEL_AB_9_8_01),
@@ -541,13 +541,13 @@ static const u16 pinmux_data[] = {
        PINMUX_IPSR_NOFN(AB_13_12_PORT104, AB_A28, SEL_AB_13_12_00),
        PINMUX_IPSR_NOFN(AB_13_12_PORT104, AB_BEN1, SEL_AB_13_12_10),
        /* B8 */
-       PINMUX_DATA(USI0_CS1_MARK, FN_USI0_CS1),
+       PINMUX_SINGLE(USI0_CS1),
        /* B9 */
-       PINMUX_DATA(USI0_CS2_MARK, FN_USI0_CS2),
+       PINMUX_SINGLE(USI0_CS2),
        /* C10 */
-       PINMUX_DATA(USI1_DI_MARK, FN_USI1_DI),
+       PINMUX_SINGLE(USI1_DI),
        /* D10 */
-       PINMUX_DATA(USI1_DO_MARK, FN_USI1_DO),
+       PINMUX_SINGLE(USI1_DO),
        /* AB5 */
        PINMUX_IPSR_NOFN(USI_1_0_PORT109, USI2_CLK, SEL_USI_1_0_00),
        PINMUX_IPSR_NOFN(USI_1_0_PORT109, DTV_BCLK_B, SEL_USI_1_0_01),
@@ -587,49 +587,49 @@ static const u16 pinmux_data[] = {
        PINMUX_IPSR_NOFN(USI_9_8_PORT121, PWM1, SEL_USI_9_8_00),
        PINMUX_IPSR_NOFN(USI_9_8_PORT121, USI4_DO, SEL_USI_9_8_01),
        /* V20 */
-       PINMUX_DATA(NTSC_CLK_MARK, FN_NTSC_CLK),
+       PINMUX_SINGLE(NTSC_CLK),
        /* P20 */
-       PINMUX_DATA(NTSC_DATA0_MARK, FN_NTSC_DATA0),
+       PINMUX_SINGLE(NTSC_DATA0),
        /* P18 */
-       PINMUX_DATA(NTSC_DATA1_MARK, FN_NTSC_DATA1),
+       PINMUX_SINGLE(NTSC_DATA1),
        /* R20 */
-       PINMUX_DATA(NTSC_DATA2_MARK, FN_NTSC_DATA2),
+       PINMUX_SINGLE(NTSC_DATA2),
        /* R18 */
-       PINMUX_DATA(NTSC_DATA3_MARK, FN_NTSC_DATA3),
+       PINMUX_SINGLE(NTSC_DATA3),
        /* T20 */
-       PINMUX_DATA(NTSC_DATA4_MARK, FN_NTSC_DATA4),
+       PINMUX_SINGLE(NTSC_DATA4),
 
        /* GPRS3 */
        /* T18 */
-       PINMUX_DATA(NTSC_DATA5_MARK, FN_NTSC_DATA5),
+       PINMUX_SINGLE(NTSC_DATA5),
        /* U20 */
-       PINMUX_DATA(NTSC_DATA6_MARK, FN_NTSC_DATA6),
+       PINMUX_SINGLE(NTSC_DATA6),
        /* U18 */
-       PINMUX_DATA(NTSC_DATA7_MARK, FN_NTSC_DATA7),
+       PINMUX_SINGLE(NTSC_DATA7),
        /* W23 */
-       PINMUX_DATA(CAM_CLKO_MARK, FN_CAM_CLKO),
+       PINMUX_SINGLE(CAM_CLKO),
        /* Y23 */
-       PINMUX_DATA(CAM_CLKI_MARK, FN_CAM_CLKI),
+       PINMUX_SINGLE(CAM_CLKI),
        /* W22 */
-       PINMUX_DATA(CAM_VS_MARK, FN_CAM_VS),
+       PINMUX_SINGLE(CAM_VS),
        /* V21 */
-       PINMUX_DATA(CAM_HS_MARK, FN_CAM_HS),
+       PINMUX_SINGLE(CAM_HS),
        /* T21 */
-       PINMUX_DATA(CAM_YUV0_MARK, FN_CAM_YUV0),
+       PINMUX_SINGLE(CAM_YUV0),
        /* T22 */
-       PINMUX_DATA(CAM_YUV1_MARK, FN_CAM_YUV1),
+       PINMUX_SINGLE(CAM_YUV1),
        /* T23 */
-       PINMUX_DATA(CAM_YUV2_MARK, FN_CAM_YUV2),
+       PINMUX_SINGLE(CAM_YUV2),
        /* U21 */
-       PINMUX_DATA(CAM_YUV3_MARK, FN_CAM_YUV3),
+       PINMUX_SINGLE(CAM_YUV3),
        /* U22 */
-       PINMUX_DATA(CAM_YUV4_MARK, FN_CAM_YUV4),
+       PINMUX_SINGLE(CAM_YUV4),
        /* U23 */
-       PINMUX_DATA(CAM_YUV5_MARK, FN_CAM_YUV5),
+       PINMUX_SINGLE(CAM_YUV5),
        /* V22 */
-       PINMUX_DATA(CAM_YUV6_MARK, FN_CAM_YUV6),
+       PINMUX_SINGLE(CAM_YUV6),
        /* V23 */
-       PINMUX_DATA(CAM_YUV7_MARK, FN_CAM_YUV7),
+       PINMUX_SINGLE(CAM_YUV7),
        /* K22 */
        PINMUX_IPSR_NOFN(HSI_1_0_PORT143, USI5_CLK_B, SEL_HSI_1_0_01),
        /* K23 */
@@ -647,17 +647,17 @@ static const u16 pinmux_data[] = {
        /* M22 */
        PINMUX_IPSR_NOFN(HSI_1_0_PORT150, USI5_DI_B, SEL_HSI_1_0_01),
        /* D13 */
-       PINMUX_DATA(JT_TDO_MARK, FN_JT_TDO),
+       PINMUX_SINGLE(JT_TDO),
        /* F13 */
-       PINMUX_DATA(JT_TDOEN_MARK, FN_JT_TDOEN),
+       PINMUX_SINGLE(JT_TDOEN),
        /* AA12 */
-       PINMUX_DATA(USB_VBUS_MARK, FN_USB_VBUS),
+       PINMUX_SINGLE(USB_VBUS),
        /* A12 */
-       PINMUX_DATA(LOWPWR_MARK, FN_LOWPWR),
+       PINMUX_SINGLE(LOWPWR),
        /* Y11 */
-       PINMUX_DATA(UART1_RX_MARK, FN_UART1_RX),
+       PINMUX_SINGLE(UART1_RX),
        /* Y10 */
-       PINMUX_DATA(UART1_TX_MARK, FN_UART1_TX),
+       PINMUX_SINGLE(UART1_TX),
        /* AA10 */
        PINMUX_IPSR_NOFN(UART_1_0_PORT157, UART1_CTSB, SEL_UART_1_0_00),
        PINMUX_IPSR_NOFN(UART_1_0_PORT157, UART2_RX, SEL_UART_1_0_01),
@@ -749,7 +749,7 @@ static const unsigned int cf_ctrl_mux[] = {
 };
 
 static const unsigned int cf_data8_pins[] = {
-       /* CF_D[0:8] */
+       /* CF_D[0:7] */
        77, 78, 79, 80,
        81, 82, 83, 84,
 };
index 279e9dd442e4472989e32cdc9126d23c88593693..7f7c8a6e76e88f29904c9f791c0bf47ccf7ad69b 100644 (file)
@@ -2214,7 +2214,7 @@ static const unsigned int lcd1_data9_mux[] = {
        LCD1_D8_MARK,
 };
 static const unsigned int lcd1_data12_pins[] = {
-       /* D[0:12] */
+       /* D[0:11] */
        4, 3, 2, 1, 0, 91, 92, 23,
        93, 94, 21, 201,
 };
index bbd35dc1a0c4c35a512a501d5f7d3d3a3b67ea8c..ad09a670c2ffbe70bd3505e75609b8c9b02fe9de 100644 (file)
@@ -548,17 +548,17 @@ enum {
 static const u16 pinmux_data[] = {
        PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
 
-       PINMUX_DATA(PENC0_MARK,         FN_PENC0),
-       PINMUX_DATA(PENC1_MARK,         FN_PENC1),
-       PINMUX_DATA(A1_MARK,            FN_A1),
-       PINMUX_DATA(A2_MARK,            FN_A2),
-       PINMUX_DATA(A3_MARK,            FN_A3),
-       PINMUX_DATA(WE0_MARK,           FN_WE0),
-       PINMUX_DATA(AUDIO_CLKA_MARK,    FN_AUDIO_CLKA),
-       PINMUX_DATA(AUDIO_CLKB_MARK,    FN_AUDIO_CLKB),
-       PINMUX_DATA(SSI_SCK34_MARK,     FN_SSI_SCK34),
-       PINMUX_DATA(AVS1_MARK,          FN_AVS1),
-       PINMUX_DATA(AVS2_MARK,          FN_AVS2),
+       PINMUX_SINGLE(PENC0),
+       PINMUX_SINGLE(PENC1),
+       PINMUX_SINGLE(A1),
+       PINMUX_SINGLE(A2),
+       PINMUX_SINGLE(A3),
+       PINMUX_SINGLE(WE0),
+       PINMUX_SINGLE(AUDIO_CLKA),
+       PINMUX_SINGLE(AUDIO_CLKB),
+       PINMUX_SINGLE(SSI_SCK34),
+       PINMUX_SINGLE(AVS1),
+       PINMUX_SINGLE(AVS2),
 
        /* IPSR0 */
        PINMUX_IPSR_DATA(IP0_1_0,       PRESETOUT),
index ed4e0788035c50b4f51985e1d4eb91e0345c2452..bd17eccb6a8901a8880dcaeb7e87fbcccc040f2b 100644 (file)
 
 #include "sh_pfc.h"
 
-#define PORT_GP_9(bank, fn, sfx)                                       \
-       PORT_GP_1(bank, 0, fn, sfx), PORT_GP_1(bank, 1, fn, sfx),       \
-       PORT_GP_1(bank, 2, fn, sfx), PORT_GP_1(bank, 3, fn, sfx),       \
-       PORT_GP_1(bank, 4, fn, sfx), PORT_GP_1(bank, 5, fn, sfx),       \
-       PORT_GP_1(bank, 6, fn, sfx), PORT_GP_1(bank, 7, fn, sfx),       \
-       PORT_GP_1(bank, 8, fn, sfx)
-
 #define CPU_ALL_PORT(fn, sfx)                                          \
        PORT_GP_32(0, fn, sfx),                                         \
        PORT_GP_32(1, fn, sfx),                                         \
@@ -609,14 +602,14 @@ enum {
 static const u16 pinmux_data[] = {
        PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
 
-       PINMUX_DATA(AVS1_MARK, FN_AVS1),
-       PINMUX_DATA(AVS1_MARK, FN_AVS1),
-       PINMUX_DATA(A17_MARK, FN_A17),
-       PINMUX_DATA(A18_MARK, FN_A18),
-       PINMUX_DATA(A19_MARK, FN_A19),
+       PINMUX_SINGLE(AVS1),
+       PINMUX_SINGLE(AVS1),
+       PINMUX_SINGLE(A17),
+       PINMUX_SINGLE(A18),
+       PINMUX_SINGLE(A19),
 
-       PINMUX_DATA(USB_PENC0_MARK, FN_USB_PENC0),
-       PINMUX_DATA(USB_PENC1_MARK, FN_USB_PENC1),
+       PINMUX_SINGLE(USB_PENC0),
+       PINMUX_SINGLE(USB_PENC1),
 
        PINMUX_IPSR_DATA(IP0_2_0, USB_PENC2),
        PINMUX_IPSR_MSEL(IP0_2_0, SCK0, SEL_SCIF0_0),
@@ -2289,6 +2282,35 @@ static const unsigned int scif5_clk_d_pins[] = {
 static const unsigned int scif5_clk_d_mux[] = {
        SCK5_D_MARK,
 };
+/* - SCIF Clock ------------------------------------------------------------- */
+static const unsigned int scif_clk_pins[] = {
+       /* SCIF_CLK */
+       RCAR_GP_PIN(4, 28),
+};
+static const unsigned int scif_clk_mux[] = {
+       SCIF_CLK_MARK,
+};
+static const unsigned int scif_clk_b_pins[] = {
+       /* SCIF_CLK */
+       RCAR_GP_PIN(4, 5),
+};
+static const unsigned int scif_clk_b_mux[] = {
+       SCIF_CLK_B_MARK,
+};
+static const unsigned int scif_clk_c_pins[] = {
+       /* SCIF_CLK */
+       RCAR_GP_PIN(4, 18),
+};
+static const unsigned int scif_clk_c_mux[] = {
+       SCIF_CLK_C_MARK,
+};
+static const unsigned int scif_clk_d_pins[] = {
+       /* SCIF_CLK */
+       RCAR_GP_PIN(2, 29),
+};
+static const unsigned int scif_clk_d_mux[] = {
+       SCIF_CLK_D_MARK,
+};
 /* - SDHI0 ------------------------------------------------------------------ */
 static const unsigned int sdhi0_data1_pins[] = {
        /* D0 */
@@ -2700,6 +2722,10 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(scif5_clk_c),
        SH_PFC_PIN_GROUP(scif5_data_d),
        SH_PFC_PIN_GROUP(scif5_clk_d),
+       SH_PFC_PIN_GROUP(scif_clk),
+       SH_PFC_PIN_GROUP(scif_clk_b),
+       SH_PFC_PIN_GROUP(scif_clk_c),
+       SH_PFC_PIN_GROUP(scif_clk_d),
        SH_PFC_PIN_GROUP(sdhi0_data1),
        SH_PFC_PIN_GROUP(sdhi0_data4),
        SH_PFC_PIN_GROUP(sdhi0_ctrl),
@@ -2909,6 +2935,13 @@ static const char * const scif5_groups[] = {
        "scif5_clk_d",
 };
 
+static const char * const scif_clk_groups[] = {
+       "scif_clk",
+       "scif_clk_b",
+       "scif_clk_c",
+       "scif_clk_d",
+};
+
 static const char * const sdhi0_groups[] = {
        "sdhi0_data1",
        "sdhi0_data4",
@@ -3004,6 +3037,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
        SH_PFC_FUNCTION(scif3),
        SH_PFC_FUNCTION(scif4),
        SH_PFC_FUNCTION(scif5),
+       SH_PFC_FUNCTION(scif_clk),
        SH_PFC_FUNCTION(usb0),
        SH_PFC_FUNCTION(usb1),
        SH_PFC_FUNCTION(usb2),
index d9924b0d53b789c36cf47fd7c5c133b12c32c729..a8b629bc7a557b2f7eccdf459f3700cd36e0d3a9 100644 (file)
 #include "core.h"
 #include "sh_pfc.h"
 
-#define PORT_GP_30(bank, fn, sfx)                                      \
-       PORT_GP_1(bank, 0,  fn, sfx), PORT_GP_1(bank, 1,  fn, sfx),     \
-       PORT_GP_1(bank, 2,  fn, sfx), PORT_GP_1(bank, 3,  fn, sfx),     \
-       PORT_GP_1(bank, 4,  fn, sfx), PORT_GP_1(bank, 5,  fn, sfx),     \
-       PORT_GP_1(bank, 6,  fn, sfx), PORT_GP_1(bank, 7,  fn, sfx),     \
-       PORT_GP_1(bank, 8,  fn, sfx), PORT_GP_1(bank, 9,  fn, sfx),     \
-       PORT_GP_1(bank, 10, fn, sfx), PORT_GP_1(bank, 11, fn, sfx),     \
-       PORT_GP_1(bank, 12, fn, sfx), PORT_GP_1(bank, 13, fn, sfx),     \
-       PORT_GP_1(bank, 14, fn, sfx), PORT_GP_1(bank, 15, fn, sfx),     \
-       PORT_GP_1(bank, 16, fn, sfx), PORT_GP_1(bank, 17, fn, sfx),     \
-       PORT_GP_1(bank, 18, fn, sfx), PORT_GP_1(bank, 19, fn, sfx),     \
-       PORT_GP_1(bank, 20, fn, sfx), PORT_GP_1(bank, 21, fn, sfx),     \
-       PORT_GP_1(bank, 22, fn, sfx), PORT_GP_1(bank, 23, fn, sfx),     \
-       PORT_GP_1(bank, 24, fn, sfx), PORT_GP_1(bank, 25, fn, sfx),     \
-       PORT_GP_1(bank, 26, fn, sfx), PORT_GP_1(bank, 27, fn, sfx),     \
-       PORT_GP_1(bank, 28, fn, sfx), PORT_GP_1(bank, 29, fn, sfx)
-
 #define CPU_ALL_PORT(fn, sfx)                                          \
        PORT_GP_32(0, fn, sfx),                                         \
        PORT_GP_30(1, fn, sfx),                                         \
@@ -806,15 +789,15 @@ enum {
 static const u16 pinmux_data[] = {
        PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
 
-       PINMUX_DATA(VI1_DATA7_VI1_B7_MARK, FN_VI1_DATA7_VI1_B7),
-       PINMUX_DATA(USB0_PWEN_MARK, FN_USB0_PWEN),
-       PINMUX_DATA(USB0_OVC_VBUS_MARK, FN_USB0_OVC_VBUS),
-       PINMUX_DATA(USB2_PWEN_MARK, FN_USB2_PWEN),
-       PINMUX_DATA(USB2_OVC_MARK, FN_USB2_OVC),
-       PINMUX_DATA(AVS1_MARK, FN_AVS1),
-       PINMUX_DATA(AVS2_MARK, FN_AVS2),
-       PINMUX_DATA(DU_DOTCLKIN0_MARK, FN_DU_DOTCLKIN0),
-       PINMUX_DATA(DU_DOTCLKIN2_MARK, FN_DU_DOTCLKIN2),
+       PINMUX_SINGLE(VI1_DATA7_VI1_B7),
+       PINMUX_SINGLE(USB0_PWEN),
+       PINMUX_SINGLE(USB0_OVC_VBUS),
+       PINMUX_SINGLE(USB2_PWEN),
+       PINMUX_SINGLE(USB2_OVC),
+       PINMUX_SINGLE(AVS1),
+       PINMUX_SINGLE(AVS2),
+       PINMUX_SINGLE(DU_DOTCLKIN0),
+       PINMUX_SINGLE(DU_DOTCLKIN2),
 
        PINMUX_IPSR_DATA(IP0_2_0, D0),
        PINMUX_IPSR_MSEL(IP0_2_0, MSIOF3_SCK_B, SEL_SOF3_1),
@@ -3236,6 +3219,21 @@ static const unsigned int scifb2_data_c_pins[] = {
 static const unsigned int scifb2_data_c_mux[] = {
        SCIFB2_RXD_C_MARK, SCIFB2_TXD_C_MARK,
 };
+/* - SCIF Clock ------------------------------------------------------------- */
+static const unsigned int scif_clk_pins[] = {
+       /* SCIF_CLK */
+       RCAR_GP_PIN(4, 26),
+};
+static const unsigned int scif_clk_mux[] = {
+       SCIF_CLK_MARK,
+};
+static const unsigned int scif_clk_b_pins[] = {
+       /* SCIF_CLK */
+       RCAR_GP_PIN(5, 4),
+};
+static const unsigned int scif_clk_b_mux[] = {
+       SCIF_CLK_B_MARK,
+};
 /* - SDHI0 ------------------------------------------------------------------ */
 static const unsigned int sdhi0_data1_pins[] = {
        /* D0 */
@@ -4139,6 +4137,8 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(scifb2_clk_b),
        SH_PFC_PIN_GROUP(scifb2_ctrl_b),
        SH_PFC_PIN_GROUP(scifb2_data_c),
+       SH_PFC_PIN_GROUP(scif_clk),
+       SH_PFC_PIN_GROUP(scif_clk_b),
        SH_PFC_PIN_GROUP(sdhi0_data1),
        SH_PFC_PIN_GROUP(sdhi0_data4),
        SH_PFC_PIN_GROUP(sdhi0_ctrl),
@@ -4555,6 +4555,11 @@ static const char * const scifb2_groups[] = {
        "scifb2_data_c",
 };
 
+static const char * const scif_clk_groups[] = {
+       "scif_clk",
+       "scif_clk_b",
+};
+
 static const char * const sdhi0_groups[] = {
        "sdhi0_data1",
        "sdhi0_data4",
@@ -4729,6 +4734,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
        SH_PFC_FUNCTION(scifb0),
        SH_PFC_FUNCTION(scifb1),
        SH_PFC_FUNCTION(scifb2),
+       SH_PFC_FUNCTION(scif_clk),
        SH_PFC_FUNCTION(sdhi0),
        SH_PFC_FUNCTION(sdhi1),
        SH_PFC_FUNCTION(sdhi2),
index 87a4f44147c1d5bcd9c286e86475b0e8370f9a86..4cfbb94ad5d0bcc035439cfdf8b8bcf8a9bb9312 100644 (file)
@@ -2,6 +2,7 @@
  * r8a7791 processor support - PFC hardware block.
  *
  * Copyright (C) 2013 Renesas Electronics Corporation
+ * Copyright (C) 2014-2015 Cogent Embedded, 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
 #include "core.h"
 #include "sh_pfc.h"
 
-#define PORT_GP_26(bank, fn, sfx)                                      \
-       PORT_GP_1(bank, 0,  fn, sfx), PORT_GP_1(bank, 1,  fn, sfx),     \
-       PORT_GP_1(bank, 2,  fn, sfx), PORT_GP_1(bank, 3,  fn, sfx),     \
-       PORT_GP_1(bank, 4,  fn, sfx), PORT_GP_1(bank, 5,  fn, sfx),     \
-       PORT_GP_1(bank, 6,  fn, sfx), PORT_GP_1(bank, 7,  fn, sfx),     \
-       PORT_GP_1(bank, 8,  fn, sfx), PORT_GP_1(bank, 9,  fn, sfx),     \
-       PORT_GP_1(bank, 10, fn, sfx), PORT_GP_1(bank, 11, fn, sfx),     \
-       PORT_GP_1(bank, 12, fn, sfx), PORT_GP_1(bank, 13, fn, sfx),     \
-       PORT_GP_1(bank, 14, fn, sfx), PORT_GP_1(bank, 15, fn, sfx),     \
-       PORT_GP_1(bank, 16, fn, sfx), PORT_GP_1(bank, 17, fn, sfx),     \
-       PORT_GP_1(bank, 18, fn, sfx), PORT_GP_1(bank, 19, fn, sfx),     \
-       PORT_GP_1(bank, 20, fn, sfx), PORT_GP_1(bank, 21, fn, sfx),     \
-       PORT_GP_1(bank, 22, fn, sfx), PORT_GP_1(bank, 23, fn, sfx),     \
-       PORT_GP_1(bank, 24, fn, sfx), PORT_GP_1(bank, 25, fn, sfx)
-
 #define CPU_ALL_PORT(fn, sfx)                                          \
        PORT_GP_32(0, fn, sfx),                                         \
        PORT_GP_26(1, fn, sfx),                                         \
@@ -787,23 +773,23 @@ enum {
 static const u16 pinmux_data[] = {
        PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
 
-       PINMUX_DATA(EX_CS0_N_MARK, FN_EX_CS0_N),
-       PINMUX_DATA(RD_N_MARK, FN_RD_N),
-       PINMUX_DATA(AUDIO_CLKA_MARK, FN_AUDIO_CLKA),
-       PINMUX_DATA(VI0_CLK_MARK, FN_VI0_CLK),
-       PINMUX_DATA(VI0_DATA0_VI0_B0_MARK, FN_VI0_DATA0_VI0_B0),
-       PINMUX_DATA(VI0_DATA1_VI0_B1_MARK, FN_VI0_DATA1_VI0_B1),
-       PINMUX_DATA(VI0_DATA2_VI0_B2_MARK, FN_VI0_DATA2_VI0_B2),
-       PINMUX_DATA(VI0_DATA4_VI0_B4_MARK, FN_VI0_DATA4_VI0_B4),
-       PINMUX_DATA(VI0_DATA5_VI0_B5_MARK, FN_VI0_DATA5_VI0_B5),
-       PINMUX_DATA(VI0_DATA6_VI0_B6_MARK, FN_VI0_DATA6_VI0_B6),
-       PINMUX_DATA(VI0_DATA7_VI0_B7_MARK, FN_VI0_DATA7_VI0_B7),
-       PINMUX_DATA(USB0_PWEN_MARK, FN_USB0_PWEN),
-       PINMUX_DATA(USB0_OVC_MARK, FN_USB0_OVC),
-       PINMUX_DATA(USB1_PWEN_MARK, FN_USB1_PWEN),
-       PINMUX_DATA(USB1_OVC_MARK, FN_USB1_OVC),
-       PINMUX_DATA(DU0_DOTCLKIN_MARK, FN_DU0_DOTCLKIN),
-       PINMUX_DATA(SD1_CLK_MARK, FN_SD1_CLK),
+       PINMUX_SINGLE(EX_CS0_N),
+       PINMUX_SINGLE(RD_N),
+       PINMUX_SINGLE(AUDIO_CLKA),
+       PINMUX_SINGLE(VI0_CLK),
+       PINMUX_SINGLE(VI0_DATA0_VI0_B0),
+       PINMUX_SINGLE(VI0_DATA1_VI0_B1),
+       PINMUX_SINGLE(VI0_DATA2_VI0_B2),
+       PINMUX_SINGLE(VI0_DATA4_VI0_B4),
+       PINMUX_SINGLE(VI0_DATA5_VI0_B5),
+       PINMUX_SINGLE(VI0_DATA6_VI0_B6),
+       PINMUX_SINGLE(VI0_DATA7_VI0_B7),
+       PINMUX_SINGLE(USB0_PWEN),
+       PINMUX_SINGLE(USB0_OVC),
+       PINMUX_SINGLE(USB1_PWEN),
+       PINMUX_SINGLE(USB1_OVC),
+       PINMUX_SINGLE(DU0_DOTCLKIN),
+       PINMUX_SINGLE(SD1_CLK),
 
        /* IPSR0 */
        PINMUX_IPSR_DATA(IP0_0, D0),
@@ -1740,6 +1726,82 @@ static const unsigned int audio_clkout_mux[] = {
        AUDIO_CLKOUT_MARK,
 };
 
+/* - AVB -------------------------------------------------------------------- */
+static const unsigned int avb_link_pins[] = {
+       RCAR_GP_PIN(5, 14),
+};
+static const unsigned int avb_link_mux[] = {
+       AVB_LINK_MARK,
+};
+static const unsigned int avb_magic_pins[] = {
+       RCAR_GP_PIN(5, 11),
+};
+static const unsigned int avb_magic_mux[] = {
+       AVB_MAGIC_MARK,
+};
+static const unsigned int avb_phy_int_pins[] = {
+       RCAR_GP_PIN(5, 16),
+};
+static const unsigned int avb_phy_int_mux[] = {
+       AVB_PHY_INT_MARK,
+};
+static const unsigned int avb_mdio_pins[] = {
+       RCAR_GP_PIN(5, 12), RCAR_GP_PIN(5, 9),
+};
+static const unsigned int avb_mdio_mux[] = {
+       AVB_MDC_MARK, AVB_MDIO_MARK,
+};
+static const unsigned int avb_mii_pins[] = {
+       RCAR_GP_PIN(5, 18), RCAR_GP_PIN(5, 19), RCAR_GP_PIN(5, 20),
+       RCAR_GP_PIN(5, 21),
+
+       RCAR_GP_PIN(5, 0), RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 2),
+       RCAR_GP_PIN(5, 3),
+
+       RCAR_GP_PIN(5, 8), RCAR_GP_PIN(5, 13), RCAR_GP_PIN(5, 10),
+       RCAR_GP_PIN(5, 15), RCAR_GP_PIN(5, 26), RCAR_GP_PIN(5, 27),
+       RCAR_GP_PIN(5, 28), RCAR_GP_PIN(5, 29),
+};
+static const unsigned int avb_mii_mux[] = {
+       AVB_TXD0_MARK, AVB_TXD1_MARK, AVB_TXD2_MARK,
+       AVB_TXD3_MARK,
+
+       AVB_RXD0_MARK, AVB_RXD1_MARK, AVB_RXD2_MARK,
+       AVB_RXD3_MARK,
+
+       AVB_RX_ER_MARK, AVB_RX_CLK_MARK, AVB_RX_DV_MARK,
+       AVB_CRS_MARK, AVB_TX_EN_MARK, AVB_TX_ER_MARK,
+       AVB_TX_CLK_MARK, AVB_COL_MARK,
+};
+static const unsigned int avb_gmii_pins[] = {
+       RCAR_GP_PIN(5, 18), RCAR_GP_PIN(5, 19), RCAR_GP_PIN(5, 20),
+       RCAR_GP_PIN(5, 21), RCAR_GP_PIN(5, 22), RCAR_GP_PIN(5, 23),
+       RCAR_GP_PIN(5, 24), RCAR_GP_PIN(5, 25),
+
+       RCAR_GP_PIN(5, 0), RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 2),
+       RCAR_GP_PIN(5, 3), RCAR_GP_PIN(5, 4), RCAR_GP_PIN(5, 5),
+       RCAR_GP_PIN(5, 6), RCAR_GP_PIN(5, 7),
+
+       RCAR_GP_PIN(5, 8), RCAR_GP_PIN(5, 13), RCAR_GP_PIN(5, 10),
+       RCAR_GP_PIN(5, 15), RCAR_GP_PIN(5, 30), RCAR_GP_PIN(5, 17),
+       RCAR_GP_PIN(5, 26), RCAR_GP_PIN(5, 27), RCAR_GP_PIN(5, 28),
+       RCAR_GP_PIN(5, 29),
+};
+static const unsigned int avb_gmii_mux[] = {
+       AVB_TXD0_MARK, AVB_TXD1_MARK, AVB_TXD2_MARK,
+       AVB_TXD3_MARK, AVB_TXD4_MARK, AVB_TXD5_MARK,
+       AVB_TXD6_MARK, AVB_TXD7_MARK,
+
+       AVB_RXD0_MARK, AVB_RXD1_MARK, AVB_RXD2_MARK,
+       AVB_RXD3_MARK, AVB_RXD4_MARK, AVB_RXD5_MARK,
+       AVB_RXD6_MARK, AVB_RXD7_MARK,
+
+       AVB_RX_ER_MARK, AVB_RX_CLK_MARK, AVB_RX_DV_MARK,
+       AVB_CRS_MARK, AVB_GTX_CLK_MARK, AVB_GTXREFCLK_MARK,
+       AVB_TX_EN_MARK, AVB_TX_ER_MARK, AVB_TX_CLK_MARK,
+       AVB_COL_MARK,
+};
+
 /* - CAN -------------------------------------------------------------------- */
 
 static const unsigned int can0_data_pins[] = {
@@ -3602,6 +3664,23 @@ static const unsigned int scifb2_data_d_pins[] = {
 static const unsigned int scifb2_data_d_mux[] = {
        SCIFB2_RXD_D_MARK, SCIFB2_TXD_D_MARK,
 };
+
+/* - SCIF Clock ------------------------------------------------------------- */
+static const unsigned int scif_clk_pins[] = {
+       /* SCIF_CLK */
+       RCAR_GP_PIN(2, 29),
+};
+static const unsigned int scif_clk_mux[] = {
+       SCIF_CLK_MARK,
+};
+static const unsigned int scif_clk_b_pins[] = {
+       /* SCIF_CLK */
+       RCAR_GP_PIN(7, 19),
+};
+static const unsigned int scif_clk_b_mux[] = {
+       SCIF_CLK_B_MARK,
+};
+
 /* - SDHI0 ------------------------------------------------------------------ */
 static const unsigned int sdhi0_data1_pins[] = {
        /* D0 */
@@ -4258,6 +4337,12 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(audio_clk_b_b),
        SH_PFC_PIN_GROUP(audio_clk_c),
        SH_PFC_PIN_GROUP(audio_clkout),
+       SH_PFC_PIN_GROUP(avb_link),
+       SH_PFC_PIN_GROUP(avb_magic),
+       SH_PFC_PIN_GROUP(avb_phy_int),
+       SH_PFC_PIN_GROUP(avb_mdio),
+       SH_PFC_PIN_GROUP(avb_mii),
+       SH_PFC_PIN_GROUP(avb_gmii),
        SH_PFC_PIN_GROUP(can0_data),
        SH_PFC_PIN_GROUP(can0_data_b),
        SH_PFC_PIN_GROUP(can0_data_c),
@@ -4510,6 +4595,8 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(scifb2_data_c),
        SH_PFC_PIN_GROUP(scifb2_clk_c),
        SH_PFC_PIN_GROUP(scifb2_data_d),
+       SH_PFC_PIN_GROUP(scif_clk),
+       SH_PFC_PIN_GROUP(scif_clk_b),
        SH_PFC_PIN_GROUP(sdhi0_data1),
        SH_PFC_PIN_GROUP(sdhi0_data4),
        SH_PFC_PIN_GROUP(sdhi0_ctrl),
@@ -4597,6 +4684,15 @@ static const char * const audio_clk_groups[] = {
        "audio_clkout",
 };
 
+static const char * const avb_groups[] = {
+       "avb_link",
+       "avb_magic",
+       "avb_phy_int",
+       "avb_mdio",
+       "avb_mii",
+       "avb_gmii",
+};
+
 static const char * const can0_groups[] = {
        "can0_data",
        "can0_data_b",
@@ -4976,6 +5072,11 @@ static const char * const scifb2_groups[] = {
        "scifb2_data_d",
 };
 
+static const char * const scif_clk_groups[] = {
+       "scif_clk",
+       "scif_clk_b",
+};
+
 static const char * const sdhi0_groups[] = {
        "sdhi0_data1",
        "sdhi0_data4",
@@ -5081,6 +5182,7 @@ static const char * const vin2_groups[] = {
 
 static const struct sh_pfc_function pinmux_functions[] = {
        SH_PFC_FUNCTION(audio_clk),
+       SH_PFC_FUNCTION(avb),
        SH_PFC_FUNCTION(can0),
        SH_PFC_FUNCTION(can1),
        SH_PFC_FUNCTION(du),
@@ -5126,6 +5228,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
        SH_PFC_FUNCTION(scifb0),
        SH_PFC_FUNCTION(scifb1),
        SH_PFC_FUNCTION(scifb2),
+       SH_PFC_FUNCTION(scif_clk),
        SH_PFC_FUNCTION(sdhi0),
        SH_PFC_FUNCTION(sdhi1),
        SH_PFC_FUNCTION(sdhi2),
index 086f6798b1294564e425e0ab93c129fab16831ea..3718c7846bfd5cd3cfce84076449b388432e8081 100644 (file)
 #include "core.h"
 #include "sh_pfc.h"
 
-#define PORT_GP_26(bank, fn, sfx)                                      \
-       PORT_GP_1(bank, 0,  fn, sfx), PORT_GP_1(bank, 1,  fn, sfx),     \
-       PORT_GP_1(bank, 2,  fn, sfx), PORT_GP_1(bank, 3,  fn, sfx),     \
-       PORT_GP_1(bank, 4,  fn, sfx), PORT_GP_1(bank, 5,  fn, sfx),     \
-       PORT_GP_1(bank, 6,  fn, sfx), PORT_GP_1(bank, 7,  fn, sfx),     \
-       PORT_GP_1(bank, 8,  fn, sfx), PORT_GP_1(bank, 9,  fn, sfx),     \
-       PORT_GP_1(bank, 10, fn, sfx), PORT_GP_1(bank, 11, fn, sfx),     \
-       PORT_GP_1(bank, 12, fn, sfx), PORT_GP_1(bank, 13, fn, sfx),     \
-       PORT_GP_1(bank, 14, fn, sfx), PORT_GP_1(bank, 15, fn, sfx),     \
-       PORT_GP_1(bank, 16, fn, sfx), PORT_GP_1(bank, 17, fn, sfx),     \
-       PORT_GP_1(bank, 18, fn, sfx), PORT_GP_1(bank, 19, fn, sfx),     \
-       PORT_GP_1(bank, 20, fn, sfx), PORT_GP_1(bank, 21, fn, sfx),     \
-       PORT_GP_1(bank, 22, fn, sfx), PORT_GP_1(bank, 23, fn, sfx),     \
-       PORT_GP_1(bank, 24, fn, sfx), PORT_GP_1(bank, 25, fn, sfx)
-
-#define PORT_GP_28(bank, fn, sfx)                                      \
-       PORT_GP_26(bank, fn, sfx),                                      \
-       PORT_GP_1(bank, 26, fn, sfx), PORT_GP_1(bank, 27, fn, sfx)
-
 #define CPU_ALL_PORT(fn, sfx)                                          \
        PORT_GP_32(0, fn, sfx),                                         \
        PORT_GP_26(1, fn, sfx),                                         \
@@ -618,28 +599,28 @@ enum {
 static const u16 pinmux_data[] = {
        PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
 
-       PINMUX_DATA(A2_MARK, FN_A2),
-       PINMUX_DATA(WE0_N_MARK, FN_WE0_N),
-       PINMUX_DATA(WE1_N_MARK, FN_WE1_N),
-       PINMUX_DATA(DACK0_MARK, FN_DACK0),
-       PINMUX_DATA(USB0_PWEN_MARK, FN_USB0_PWEN),
-       PINMUX_DATA(USB0_OVC_MARK, FN_USB0_OVC),
-       PINMUX_DATA(USB1_PWEN_MARK, FN_USB1_PWEN),
-       PINMUX_DATA(USB1_OVC_MARK, FN_USB1_OVC),
-       PINMUX_DATA(SD0_CLK_MARK, FN_SD0_CLK),
-       PINMUX_DATA(SD0_CMD_MARK, FN_SD0_CMD),
-       PINMUX_DATA(SD0_DATA0_MARK, FN_SD0_DATA0),
-       PINMUX_DATA(SD0_DATA1_MARK, FN_SD0_DATA1),
-       PINMUX_DATA(SD0_DATA2_MARK, FN_SD0_DATA2),
-       PINMUX_DATA(SD0_DATA3_MARK, FN_SD0_DATA3),
-       PINMUX_DATA(SD0_CD_MARK, FN_SD0_CD),
-       PINMUX_DATA(SD0_WP_MARK, FN_SD0_WP),
-       PINMUX_DATA(SD1_CLK_MARK, FN_SD1_CLK),
-       PINMUX_DATA(SD1_CMD_MARK, FN_SD1_CMD),
-       PINMUX_DATA(SD1_DATA0_MARK, FN_SD1_DATA0),
-       PINMUX_DATA(SD1_DATA1_MARK, FN_SD1_DATA1),
-       PINMUX_DATA(SD1_DATA2_MARK, FN_SD1_DATA2),
-       PINMUX_DATA(SD1_DATA3_MARK, FN_SD1_DATA3),
+       PINMUX_SINGLE(A2),
+       PINMUX_SINGLE(WE0_N),
+       PINMUX_SINGLE(WE1_N),
+       PINMUX_SINGLE(DACK0),
+       PINMUX_SINGLE(USB0_PWEN),
+       PINMUX_SINGLE(USB0_OVC),
+       PINMUX_SINGLE(USB1_PWEN),
+       PINMUX_SINGLE(USB1_OVC),
+       PINMUX_SINGLE(SD0_CLK),
+       PINMUX_SINGLE(SD0_CMD),
+       PINMUX_SINGLE(SD0_DATA0),
+       PINMUX_SINGLE(SD0_DATA1),
+       PINMUX_SINGLE(SD0_DATA2),
+       PINMUX_SINGLE(SD0_DATA3),
+       PINMUX_SINGLE(SD0_CD),
+       PINMUX_SINGLE(SD0_WP),
+       PINMUX_SINGLE(SD1_CLK),
+       PINMUX_SINGLE(SD1_CMD),
+       PINMUX_SINGLE(SD1_DATA0),
+       PINMUX_SINGLE(SD1_DATA1),
+       PINMUX_SINGLE(SD1_DATA2),
+       PINMUX_SINGLE(SD1_DATA3),
 
        /* IPSR0 */
        PINMUX_IPSR_DATA(IP0_0, SD1_CD),
@@ -2644,6 +2625,21 @@ static const unsigned int scifb2_ctrl_pins[] = {
 static const unsigned int scifb2_ctrl_mux[] = {
        SCIFB2_RTS_N_MARK, SCIFB2_CTS_N_MARK,
 };
+/* - SCIF Clock ------------------------------------------------------------- */
+static const unsigned int scif_clk_pins[] = {
+       /* SCIF_CLK */
+       RCAR_GP_PIN(1, 23),
+};
+static const unsigned int scif_clk_mux[] = {
+       SCIF_CLK_MARK,
+};
+static const unsigned int scif_clk_b_pins[] = {
+       /* SCIF_CLK */
+       RCAR_GP_PIN(3, 29),
+};
+static const unsigned int scif_clk_b_mux[] = {
+       SCIF_CLK_B_MARK,
+};
 /* - SDHI0 ------------------------------------------------------------------ */
 static const unsigned int sdhi0_data1_pins[] = {
        /* D0 */
@@ -3071,6 +3067,8 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(scifb2_data),
        SH_PFC_PIN_GROUP(scifb2_clk),
        SH_PFC_PIN_GROUP(scifb2_ctrl),
+       SH_PFC_PIN_GROUP(scif_clk),
+       SH_PFC_PIN_GROUP(scif_clk_b),
        SH_PFC_PIN_GROUP(sdhi0_data1),
        SH_PFC_PIN_GROUP(sdhi0_data4),
        SH_PFC_PIN_GROUP(sdhi0_ctrl),
@@ -3354,6 +3352,11 @@ static const char * const scifb2_groups[] = {
        "scifb2_ctrl",
 };
 
+static const char * const scif_clk_groups[] = {
+       "scif_clk",
+       "scif_clk_b",
+};
+
 static const char * const sdhi0_groups[] = {
        "sdhi0_data1",
        "sdhi0_data4",
@@ -3441,6 +3444,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
        SH_PFC_FUNCTION(scifb0),
        SH_PFC_FUNCTION(scifb1),
        SH_PFC_FUNCTION(scifb2),
+       SH_PFC_FUNCTION(scif_clk),
        SH_PFC_FUNCTION(sdhi0),
        SH_PFC_FUNCTION(sdhi1),
        SH_PFC_FUNCTION(sdhi2),
index 7ddb2adfc5a53d7b6c35fee2182bc05ce009cb31..ce4f5cdb05798fe324a50d79e194f218464bd150 100644 (file)
 #include "core.h"
 #include "sh_pfc.h"
 
-#define PORT_GP_3(bank, fn, sfx)                                       \
-       PORT_GP_1(bank, 0,  fn, sfx), PORT_GP_1(bank, 1,  fn, sfx),     \
-       PORT_GP_1(bank, 2,  fn, sfx), PORT_GP_1(bank, 3,  fn, sfx)
-
-#define PORT_GP_14(bank, fn, sfx)                                      \
-       PORT_GP_3(bank, fn, sfx),                                       \
-       PORT_GP_1(bank, 4,  fn, sfx), PORT_GP_1(bank, 5,  fn, sfx),     \
-       PORT_GP_1(bank, 6,  fn, sfx), PORT_GP_1(bank, 7,  fn, sfx),     \
-       PORT_GP_1(bank, 8,  fn, sfx), PORT_GP_1(bank, 9,  fn, sfx),     \
-       PORT_GP_1(bank, 10, fn, sfx), PORT_GP_1(bank, 11, fn, sfx),     \
-       PORT_GP_1(bank, 12, fn, sfx), PORT_GP_1(bank, 13, fn, sfx),     \
-       PORT_GP_1(bank, 14, fn, sfx)
-
-#define PORT_GP_15(bank, fn, sfx)                                      \
-       PORT_GP_14(bank, fn, sfx),   PORT_GP_1(bank, 15, fn, sfx)
-
-#define PORT_GP_17(bank, fn, sfx)                                      \
-       PORT_GP_15(bank, fn, sfx),                                      \
-       PORT_GP_1(bank, 16, fn, sfx), PORT_GP_1(bank, 17, fn, sfx)
-
-#define PORT_GP_25(bank, fn, sfx)                                      \
-       PORT_GP_17(bank, fn, sfx),                                      \
-       PORT_GP_1(bank, 18, fn, sfx), PORT_GP_1(bank, 19, fn, sfx),     \
-       PORT_GP_1(bank, 20, fn, sfx), PORT_GP_1(bank, 21, fn, sfx),     \
-       PORT_GP_1(bank, 22, fn, sfx), PORT_GP_1(bank, 23, fn, sfx),     \
-       PORT_GP_1(bank, 24, fn, sfx), PORT_GP_1(bank, 25, fn, sfx)
-
-#define PORT_GP_27(bank, fn, sfx)                                      \
-       PORT_GP_25(bank, fn, sfx),                                      \
-       PORT_GP_1(bank, 26, fn, sfx), PORT_GP_1(bank, 27, fn, sfx)
-
 #define CPU_ALL_PORT(fn, sfx)                                          \
-       PORT_GP_15(0, fn, sfx),                                         \
-       PORT_GP_27(1, fn, sfx),                                         \
-       PORT_GP_14(2, fn, sfx),                                         \
-       PORT_GP_15(3, fn, sfx),                                         \
-       PORT_GP_17(4, fn, sfx),                                         \
-       PORT_GP_25(5, fn, sfx),                                         \
+       PORT_GP_16(0, fn, sfx),                                         \
+       PORT_GP_28(1, fn, sfx),                                         \
+       PORT_GP_15(2, fn, sfx),                                         \
+       PORT_GP_16(3, fn, sfx),                                         \
+       PORT_GP_18(4, fn, sfx),                                         \
+       PORT_GP_26(5, fn, sfx),                                         \
        PORT_GP_32(6, fn, sfx),                                         \
-       PORT_GP_3(7, fn, sfx)
+       PORT_GP_4(7, fn, sfx)
 /*
  * F_() : just information
  * FM() : macro for FN_xxx / xxx_MARK
@@ -495,7 +464,7 @@ FM(IP16_31_28)      IP16_31_28
 #define MOD_SEL1_13            FM(SEL_SCIF3_0)         FM(SEL_SCIF3_1)
 #define MOD_SEL1_12            FM(SEL_SCIF2_0)         FM(SEL_SCIF2_1)
 #define MOD_SEL1_11            FM(SEL_SCIF1_0)         FM(SEL_SCIF1_1)
-#define MOD_SEL1_10            FM(SEL_SCIF_0)          FM(SEL_SCIF_1)
+#define MOD_SEL1_10            FM(SEL_SATA_0)          FM(SEL_SATA_1)
 #define MOD_SEL1_9             FM(SEL_REMOCON_0)       FM(SEL_REMOCON_1)
 #define MOD_SEL1_6             FM(SEL_RCAN0_0)         FM(SEL_RCAN0_1)
 #define MOD_SEL1_5             FM(SEL_PWM6_0)          FM(SEL_PWM6_1)
@@ -580,6 +549,25 @@ enum {
 static const u16 pinmux_data[] = {
        PINMUX_DATA_GP_ALL(),
 
+       PINMUX_SINGLE(AVS1),
+       PINMUX_SINGLE(AVS2),
+       PINMUX_SINGLE(HDMI0_CEC),
+       PINMUX_SINGLE(HDMI1_CEC),
+       PINMUX_SINGLE(MSIOF0_RXD),
+       PINMUX_SINGLE(MSIOF0_SCK),
+       PINMUX_SINGLE(MSIOF0_TXD),
+       PINMUX_SINGLE(SD2_CMD),
+       PINMUX_SINGLE(SD3_CLK),
+       PINMUX_SINGLE(SD3_CMD),
+       PINMUX_SINGLE(SD3_DAT0),
+       PINMUX_SINGLE(SD3_DAT1),
+       PINMUX_SINGLE(SD3_DAT2),
+       PINMUX_SINGLE(SD3_DAT3),
+       PINMUX_SINGLE(SD3_DS),
+       PINMUX_SINGLE(SSI_SCK5),
+       PINMUX_SINGLE(SSI_SDATA5),
+       PINMUX_SINGLE(SSI_WS5),
+
        /* IPSR0 */
        PINMUX_IPSR_DATA(IP0_3_0,       AVB_MDC),
        PINMUX_IPSR_MSEL(IP0_3_0,       MSIOF2_SS2_C,           SEL_MSIOF2_2),
@@ -1033,7 +1021,7 @@ static const u16 pinmux_data[] = {
        PINMUX_IPSR_DATA(IP9_19_16,     SD2_DAT3),
 
        PINMUX_IPSR_DATA(IP9_23_20,     SD2_DS),
-       PINMUX_IPSR_MSEL(IP9_23_20,     SATA_DEVSLP_B,          SEL_SCIF_1),
+       PINMUX_IPSR_MSEL(IP9_23_20,     SATA_DEVSLP_B,          SEL_SATA_1),
 
        PINMUX_IPSR_DATA(IP9_27_24,     SD3_DAT4),
        PINMUX_IPSR_MSEL(IP9_27_24,     SD2_CD_A,               SEL_SDHI2_0),
@@ -1293,7 +1281,7 @@ static const u16 pinmux_data[] = {
 
        PINMUX_IPSR_DATA(IP15_11_8,     SSI_SDATA6),
        PINMUX_IPSR_MSEL(IP15_11_8,     SIM0_CLK_D,             SEL_SIMCARD_3),
-       PINMUX_IPSR_MSEL(IP15_11_8,     SATA_DEVSLP_A,          SEL_SCIF_0),
+       PINMUX_IPSR_MSEL(IP15_11_8,     SATA_DEVSLP_A,          SEL_SATA_0),
 
        PINMUX_IPSR_DATA(IP15_15_12,    SSI_SCK78),
        PINMUX_IPSR_MSEL(IP15_15_12,    HRX2_B,                 SEL_HSCIF2_1),
@@ -1612,6 +1600,191 @@ static const unsigned int avb_avtp_capture_b_mux[] = {
        AVB_AVTP_CAPTURE_B_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[] = {
+       HSCK1_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,
+};
+/* - 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, HCTS3_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 */
@@ -1663,6 +1836,678 @@ 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,
+};
+
+/* - SATA --------------------------------------------------------------------*/
+static const unsigned int sata0_devslp_a_pins[] = {
+       /* DEVSLP */
+       RCAR_GP_PIN(6, 16),
+};
+static const unsigned int sata0_devslp_a_mux[] = {
+       SATA_DEVSLP_A_MARK,
+};
+static const unsigned int sata0_devslp_b_pins[] = {
+       /* DEVSLP */
+       RCAR_GP_PIN(4, 6),
+};
+static const unsigned int sata0_devslp_b_mux[] = {
+       SATA_DEVSLP_B_MARK,
+};
+
 /* - SCIF0 ------------------------------------------------------------------ */
 static const unsigned int scif0_data_pins[] = {
        /* RX, TX */
@@ -1845,6 +2690,228 @@ static const unsigned int scif5_clk_pins[] = {
 static const unsigned int scif5_clk_mux[] = {
        SCK5_MARK,
 };
+/* - SDHI0 ------------------------------------------------------------------ */
+static const unsigned int sdhi0_data1_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(3, 2),
+};
+static const unsigned int sdhi0_data1_mux[] = {
+       SD0_DAT0_MARK,
+};
+static const unsigned int sdhi0_data4_pins[] = {
+       /* D[0:3] */
+       RCAR_GP_PIN(3, 2), RCAR_GP_PIN(3, 3),
+       RCAR_GP_PIN(3, 4), RCAR_GP_PIN(3, 5),
+};
+static const unsigned int sdhi0_data4_mux[] = {
+       SD0_DAT0_MARK, SD0_DAT1_MARK,
+       SD0_DAT2_MARK, SD0_DAT3_MARK,
+};
+static const unsigned int sdhi0_ctrl_pins[] = {
+       /* CLK, CMD */
+       RCAR_GP_PIN(3, 0), RCAR_GP_PIN(3, 1),
+};
+static const unsigned int sdhi0_ctrl_mux[] = {
+       SD0_CLK_MARK, SD0_CMD_MARK,
+};
+static const unsigned int sdhi0_cd_pins[] = {
+       /* CD */
+       RCAR_GP_PIN(3, 12),
+};
+static const unsigned int sdhi0_cd_mux[] = {
+       SD0_CD_MARK,
+};
+static const unsigned int sdhi0_wp_pins[] = {
+       /* WP */
+       RCAR_GP_PIN(3, 13),
+};
+static const unsigned int sdhi0_wp_mux[] = {
+       SD0_WP_MARK,
+};
+/* - SDHI1 ------------------------------------------------------------------ */
+static const unsigned int sdhi1_data1_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(3, 8),
+};
+static const unsigned int sdhi1_data1_mux[] = {
+       SD1_DAT0_MARK,
+};
+static const unsigned int sdhi1_data4_pins[] = {
+       /* D[0:3] */
+       RCAR_GP_PIN(3, 8),  RCAR_GP_PIN(3, 9),
+       RCAR_GP_PIN(3, 10), RCAR_GP_PIN(3, 11),
+};
+static const unsigned int sdhi1_data4_mux[] = {
+       SD1_DAT0_MARK, SD1_DAT1_MARK,
+       SD1_DAT2_MARK, SD1_DAT3_MARK,
+};
+static const unsigned int sdhi1_ctrl_pins[] = {
+       /* CLK, CMD */
+       RCAR_GP_PIN(3, 6), RCAR_GP_PIN(3, 7),
+};
+static const unsigned int sdhi1_ctrl_mux[] = {
+       SD1_CLK_MARK, SD1_CMD_MARK,
+};
+static const unsigned int sdhi1_cd_pins[] = {
+       /* CD */
+       RCAR_GP_PIN(3, 14),
+};
+static const unsigned int sdhi1_cd_mux[] = {
+       SD1_CD_MARK,
+};
+static const unsigned int sdhi1_wp_pins[] = {
+       /* WP */
+       RCAR_GP_PIN(3, 15),
+};
+static const unsigned int sdhi1_wp_mux[] = {
+       SD1_WP_MARK,
+};
+/* - SDHI2 ------------------------------------------------------------------ */
+static const unsigned int sdhi2_data1_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(4, 2),
+};
+static const unsigned int sdhi2_data1_mux[] = {
+       SD2_DAT0_MARK,
+};
+static const unsigned int sdhi2_data4_pins[] = {
+       /* D[0:3] */
+       RCAR_GP_PIN(4, 2), RCAR_GP_PIN(4, 3),
+       RCAR_GP_PIN(4, 4), RCAR_GP_PIN(4, 5),
+};
+static const unsigned int sdhi2_data4_mux[] = {
+       SD2_DAT0_MARK, SD2_DAT1_MARK,
+       SD2_DAT2_MARK, SD2_DAT3_MARK,
+};
+static const unsigned int sdhi2_data8_pins[] = {
+       /* D[0:7] */
+       RCAR_GP_PIN(4, 2),  RCAR_GP_PIN(4, 3),
+       RCAR_GP_PIN(4, 4),  RCAR_GP_PIN(4, 5),
+       RCAR_GP_PIN(3, 8),  RCAR_GP_PIN(3, 9),
+       RCAR_GP_PIN(3, 10), RCAR_GP_PIN(3, 11),
+};
+static const unsigned int sdhi2_data8_mux[] = {
+       SD2_DAT0_MARK, SD2_DAT1_MARK,
+       SD2_DAT2_MARK, SD2_DAT3_MARK,
+       SD2_DAT4_MARK, SD2_DAT5_MARK,
+       SD2_DAT6_MARK, SD2_DAT7_MARK,
+};
+static const unsigned int sdhi2_ctrl_pins[] = {
+       /* CLK, CMD */
+       RCAR_GP_PIN(4, 0), RCAR_GP_PIN(4, 1),
+};
+static const unsigned int sdhi2_ctrl_mux[] = {
+       SD2_CLK_MARK, SD2_CMD_MARK,
+};
+static const unsigned int sdhi2_cd_a_pins[] = {
+       /* CD */
+       RCAR_GP_PIN(4, 13),
+};
+static const unsigned int sdhi2_cd_a_mux[] = {
+       SD2_CD_A_MARK,
+};
+static const unsigned int sdhi2_cd_b_pins[] = {
+       /* CD */
+       RCAR_GP_PIN(5, 10),
+};
+static const unsigned int sdhi2_cd_b_mux[] = {
+       SD2_CD_B_MARK,
+};
+static const unsigned int sdhi2_wp_a_pins[] = {
+       /* WP */
+       RCAR_GP_PIN(4, 14),
+};
+static const unsigned int sdhi2_wp_a_mux[] = {
+       SD2_WP_A_MARK,
+};
+static const unsigned int sdhi2_wp_b_pins[] = {
+       /* WP */
+       RCAR_GP_PIN(5, 11),
+};
+static const unsigned int sdhi2_wp_b_mux[] = {
+       SD2_WP_B_MARK,
+};
+static const unsigned int sdhi2_ds_pins[] = {
+       /* DS */
+       RCAR_GP_PIN(4, 6),
+};
+static const unsigned int sdhi2_ds_mux[] = {
+       SD2_DS_MARK,
+};
+/* - SDHI3 ------------------------------------------------------------------ */
+static const unsigned int sdhi3_data1_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(4, 9),
+};
+static const unsigned int sdhi3_data1_mux[] = {
+       SD3_DAT0_MARK,
+};
+static const unsigned int sdhi3_data4_pins[] = {
+       /* D[0:3] */
+       RCAR_GP_PIN(4, 9),  RCAR_GP_PIN(4, 10),
+       RCAR_GP_PIN(4, 11), RCAR_GP_PIN(4, 12),
+};
+static const unsigned int sdhi3_data4_mux[] = {
+       SD3_DAT0_MARK, SD3_DAT1_MARK,
+       SD3_DAT2_MARK, SD3_DAT3_MARK,
+};
+static const unsigned int sdhi3_data8_pins[] = {
+       /* D[0:7] */
+       RCAR_GP_PIN(4, 9),  RCAR_GP_PIN(4, 10),
+       RCAR_GP_PIN(4, 11), RCAR_GP_PIN(4, 12),
+       RCAR_GP_PIN(4, 13), RCAR_GP_PIN(4, 14),
+       RCAR_GP_PIN(4, 15), RCAR_GP_PIN(4, 16),
+};
+static const unsigned int sdhi3_data8_mux[] = {
+       SD3_DAT0_MARK, SD3_DAT1_MARK,
+       SD3_DAT2_MARK, SD3_DAT3_MARK,
+       SD3_DAT4_MARK, SD3_DAT5_MARK,
+       SD3_DAT6_MARK, SD3_DAT7_MARK,
+};
+static const unsigned int sdhi3_ctrl_pins[] = {
+       /* CLK, CMD */
+       RCAR_GP_PIN(4, 7), RCAR_GP_PIN(4, 8),
+};
+static const unsigned int sdhi3_ctrl_mux[] = {
+       SD3_CLK_MARK, SD3_CMD_MARK,
+};
+static const unsigned int sdhi3_cd_pins[] = {
+       /* CD */
+       RCAR_GP_PIN(4, 15),
+};
+static const unsigned int sdhi3_cd_mux[] = {
+       SD3_CD_MARK,
+};
+static const unsigned int sdhi3_wp_pins[] = {
+       /* WP */
+       RCAR_GP_PIN(4, 16),
+};
+static const unsigned int sdhi3_wp_mux[] = {
+       SD3_WP_MARK,
+};
+static const unsigned int sdhi3_ds_pins[] = {
+       /* DS */
+       RCAR_GP_PIN(4, 17),
+};
+static const unsigned int sdhi3_ds_mux[] = {
+       SD3_DS_MARK,
+};
+
+/* - SCIF Clock ------------------------------------------------------------- */
+static const unsigned int scif_clk_a_pins[] = {
+       /* SCIF_CLK */
+       RCAR_GP_PIN(6, 23),
+};
+static const unsigned int scif_clk_a_mux[] = {
+       SCIF_CLK_A_MARK,
+};
+static const unsigned int scif_clk_b_pins[] = {
+       /* SCIF_CLK */
+       RCAR_GP_PIN(5, 9),
+};
+static const unsigned int scif_clk_b_mux[] = {
+       SCIF_CLK_B_MARK,
+};
 
 /* - SSI -------------------------------------------------------------------- */
 static const unsigned int ssi0_data_pins[] = {
@@ -2050,6 +3117,31 @@ 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(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(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),
@@ -2057,6 +3149,101 @@ 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(sata0_devslp_a),
+       SH_PFC_PIN_GROUP(sata0_devslp_b),
        SH_PFC_PIN_GROUP(scif0_data),
        SH_PFC_PIN_GROUP(scif0_clk),
        SH_PFC_PIN_GROUP(scif0_ctrl),
@@ -2082,6 +3269,34 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(scif4_ctrl_c),
        SH_PFC_PIN_GROUP(scif5_data),
        SH_PFC_PIN_GROUP(scif5_clk),
+       SH_PFC_PIN_GROUP(scif_clk_a),
+       SH_PFC_PIN_GROUP(scif_clk_b),
+       SH_PFC_PIN_GROUP(sdhi0_data1),
+       SH_PFC_PIN_GROUP(sdhi0_data4),
+       SH_PFC_PIN_GROUP(sdhi0_ctrl),
+       SH_PFC_PIN_GROUP(sdhi0_cd),
+       SH_PFC_PIN_GROUP(sdhi0_wp),
+       SH_PFC_PIN_GROUP(sdhi1_data1),
+       SH_PFC_PIN_GROUP(sdhi1_data4),
+       SH_PFC_PIN_GROUP(sdhi1_ctrl),
+       SH_PFC_PIN_GROUP(sdhi1_cd),
+       SH_PFC_PIN_GROUP(sdhi1_wp),
+       SH_PFC_PIN_GROUP(sdhi2_data1),
+       SH_PFC_PIN_GROUP(sdhi2_data4),
+       SH_PFC_PIN_GROUP(sdhi2_data8),
+       SH_PFC_PIN_GROUP(sdhi2_ctrl),
+       SH_PFC_PIN_GROUP(sdhi2_cd_a),
+       SH_PFC_PIN_GROUP(sdhi2_wp_a),
+       SH_PFC_PIN_GROUP(sdhi2_cd_b),
+       SH_PFC_PIN_GROUP(sdhi2_wp_b),
+       SH_PFC_PIN_GROUP(sdhi2_ds),
+       SH_PFC_PIN_GROUP(sdhi3_data1),
+       SH_PFC_PIN_GROUP(sdhi3_data4),
+       SH_PFC_PIN_GROUP(sdhi3_data8),
+       SH_PFC_PIN_GROUP(sdhi3_ctrl),
+       SH_PFC_PIN_GROUP(sdhi3_cd),
+       SH_PFC_PIN_GROUP(sdhi3_wp),
+       SH_PFC_PIN_GROUP(sdhi3_ds),
        SH_PFC_PIN_GROUP(ssi0_data),
        SH_PFC_PIN_GROUP(ssi01239_ctrl),
        SH_PFC_PIN_GROUP(ssi1_data_a),
@@ -2141,6 +3356,46 @@ static const char * const avb_groups[] = {
        "avb_avtp_capture_b",
 };
 
+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",
+};
+
+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",
@@ -2157,6 +3412,116 @@ 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",
+};
+
+static const char * const sata0_groups[] = {
+       "sata0_devslp_a",
+       "sata0_devslp_b",
+};
+
 static const char * const scif0_groups[] = {
        "scif0_data",
        "scif0_clk",
@@ -2200,6 +3565,49 @@ static const char * const scif5_groups[] = {
        "scif5_clk",
 };
 
+static const char * const scif_clk_groups[] = {
+       "scif_clk_a",
+       "scif_clk_b",
+};
+
+static const char * const sdhi0_groups[] = {
+       "sdhi0_data1",
+       "sdhi0_data4",
+       "sdhi0_ctrl",
+       "sdhi0_cd",
+       "sdhi0_wp",
+};
+
+static const char * const sdhi1_groups[] = {
+       "sdhi1_data1",
+       "sdhi1_data4",
+       "sdhi1_ctrl",
+       "sdhi1_cd",
+       "sdhi1_wp",
+};
+
+static const char * const sdhi2_groups[] = {
+       "sdhi2_data1",
+       "sdhi2_data4",
+       "sdhi2_data8",
+       "sdhi2_ctrl",
+       "sdhi2_cd_a",
+       "sdhi2_wp_a",
+       "sdhi2_cd_b",
+       "sdhi2_wp_b",
+       "sdhi2_ds",
+};
+
+static const char * const sdhi3_groups[] = {
+       "sdhi3_data1",
+       "sdhi3_data4",
+       "sdhi3_data8",
+       "sdhi3_ctrl",
+       "sdhi3_cd",
+       "sdhi3_wp",
+       "sdhi3_ds",
+};
+
 static const char * const ssi_groups[] = {
        "ssi0_data",
        "ssi01239_ctrl",
@@ -2231,15 +3639,30 @@ static const char * const ssi_groups[] = {
 static const struct sh_pfc_function pinmux_functions[] = {
        SH_PFC_FUNCTION(audio_clk),
        SH_PFC_FUNCTION(avb),
+       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(sata0),
        SH_PFC_FUNCTION(scif0),
        SH_PFC_FUNCTION(scif1),
        SH_PFC_FUNCTION(scif2),
        SH_PFC_FUNCTION(scif3),
        SH_PFC_FUNCTION(scif4),
        SH_PFC_FUNCTION(scif5),
+       SH_PFC_FUNCTION(scif_clk),
+       SH_PFC_FUNCTION(sdhi0),
+       SH_PFC_FUNCTION(sdhi1),
+       SH_PFC_FUNCTION(sdhi2),
+       SH_PFC_FUNCTION(sdhi3),
        SH_PFC_FUNCTION(ssi),
 };
 
index 6a69c8c5d9433d7ed8af781e29c41b86a52c98ed..d25e6f674d0aba84cdb3ca7ba9b555eba0729f13 100644 (file)
@@ -2059,7 +2059,7 @@ static const unsigned int lcd2_data9_mux[] = {
        LCD2D8_MARK,
 };
 static const unsigned int lcd2_data12_pins[] = {
-       /* D[0:12] */
+       /* D[0:11] */
        128, 129, 142, 143, 144, 145, 138, 139,
        140, 141, 130, 131,
 };
@@ -2198,6 +2198,420 @@ static const unsigned int mmc0_ctrl_1_pins[] = {
 static const unsigned int mmc0_ctrl_1_mux[] = {
        MMCCMD1_MARK, MMCCLK1_MARK,
 };
+/* - MSIOF0 ----------------------------------------------------------------- */
+static const unsigned int msiof0_rsck_pins[] = {
+       /* RSCK */
+       66,
+};
+static const unsigned int msiof0_rsck_mux[] = {
+       MSIOF0_RSCK_MARK,
+};
+static const unsigned int msiof0_tsck_pins[] = {
+       /* TSCK */
+       64,
+};
+static const unsigned int msiof0_tsck_mux[] = {
+       MSIOF0_TSCK_MARK,
+};
+static const unsigned int msiof0_rsync_pins[] = {
+       /* RSYNC */
+       67,
+};
+static const unsigned int msiof0_rsync_mux[] = {
+       MSIOF0_RSYNC_MARK,
+};
+static const unsigned int msiof0_tsync_pins[] = {
+       /* TSYNC */
+       63,
+};
+static const unsigned int msiof0_tsync_mux[] = {
+       MSIOF0_TSYNC_MARK,
+};
+static const unsigned int msiof0_ss1_pins[] = {
+       /* SS1 */
+       62,
+};
+static const unsigned int msiof0_ss1_mux[] = {
+       MSIOF0_SS1_MARK,
+};
+static const unsigned int msiof0_ss2_pins[] = {
+       /* SS2 */
+       71,
+};
+static const unsigned int msiof0_ss2_mux[] = {
+       MSIOF0_SS2_MARK,
+};
+static const unsigned int msiof0_rxd_pins[] = {
+       /* RXD */
+       70,
+};
+static const unsigned int msiof0_rxd_mux[] = {
+       MSIOF0_RXD_MARK,
+};
+static const unsigned int msiof0_txd_pins[] = {
+       /* TXD */
+       65,
+};
+static const unsigned int msiof0_txd_mux[] = {
+       MSIOF0_TXD_MARK,
+};
+static const unsigned int msiof0_mck0_pins[] = {
+       /* MSCK0 */
+       68,
+};
+static const unsigned int msiof0_mck0_mux[] = {
+       MSIOF0_MCK0_MARK,
+};
+
+static const unsigned int msiof0_mck1_pins[] = {
+       /* MSCK1 */
+       69,
+};
+static const unsigned int msiof0_mck1_mux[] = {
+       MSIOF0_MCK1_MARK,
+};
+
+static const unsigned int msiof0l_rsck_pins[] = {
+       /* RSCK */
+       214,
+};
+static const unsigned int msiof0l_rsck_mux[] = {
+       MSIOF0L_RSCK_MARK,
+};
+static const unsigned int msiof0l_tsck_pins[] = {
+       /* TSCK */
+       219,
+};
+static const unsigned int msiof0l_tsck_mux[] = {
+       MSIOF0L_TSCK_MARK,
+};
+static const unsigned int msiof0l_rsync_pins[] = {
+       /* RSYNC */
+       215,
+};
+static const unsigned int msiof0l_rsync_mux[] = {
+       MSIOF0L_RSYNC_MARK,
+};
+static const unsigned int msiof0l_tsync_pins[] = {
+       /* TSYNC */
+       217,
+};
+static const unsigned int msiof0l_tsync_mux[] = {
+       MSIOF0L_TSYNC_MARK,
+};
+static const unsigned int msiof0l_ss1_a_pins[] = {
+       /* SS1 */
+       207,
+};
+static const unsigned int msiof0l_ss1_a_mux[] = {
+       PORT207_MSIOF0L_SS1_MARK,
+};
+static const unsigned int msiof0l_ss1_b_pins[] = {
+       /* SS1 */
+       210,
+};
+static const unsigned int msiof0l_ss1_b_mux[] = {
+       PORT210_MSIOF0L_SS1_MARK,
+};
+static const unsigned int msiof0l_ss2_a_pins[] = {
+       /* SS2 */
+       208,
+};
+static const unsigned int msiof0l_ss2_a_mux[] = {
+       PORT208_MSIOF0L_SS2_MARK,
+};
+static const unsigned int msiof0l_ss2_b_pins[] = {
+       /* SS2 */
+       211,
+};
+static const unsigned int msiof0l_ss2_b_mux[] = {
+       PORT211_MSIOF0L_SS2_MARK,
+};
+static const unsigned int msiof0l_rxd_pins[] = {
+       /* RXD */
+       221,
+};
+static const unsigned int msiof0l_rxd_mux[] = {
+       MSIOF0L_RXD_MARK,
+};
+static const unsigned int msiof0l_txd_pins[] = {
+       /* TXD */
+       222,
+};
+static const unsigned int msiof0l_txd_mux[] = {
+       MSIOF0L_TXD_MARK,
+};
+static const unsigned int msiof0l_mck0_pins[] = {
+       /* MSCK0 */
+       212,
+};
+static const unsigned int msiof0l_mck0_mux[] = {
+       MSIOF0L_MCK0_MARK,
+};
+static const unsigned int msiof0l_mck1_pins[] = {
+       /* MSCK1 */
+       213,
+};
+static const unsigned int msiof0l_mck1_mux[] = {
+       MSIOF0L_MCK1_MARK,
+};
+/* - MSIOF1 ----------------------------------------------------------------- */
+static const unsigned int msiof1_rsck_pins[] = {
+       /* RSCK */
+       234,
+};
+static const unsigned int msiof1_rsck_mux[] = {
+       MSIOF1_RSCK_MARK,
+};
+static const unsigned int msiof1_tsck_pins[] = {
+       /* TSCK */
+       232,
+};
+static const unsigned int msiof1_tsck_mux[] = {
+       MSIOF1_TSCK_MARK,
+};
+static const unsigned int msiof1_rsync_pins[] = {
+       /* RSYNC */
+       235,
+};
+static const unsigned int msiof1_rsync_mux[] = {
+       MSIOF1_RSYNC_MARK,
+};
+static const unsigned int msiof1_tsync_pins[] = {
+       /* TSYNC */
+       231,
+};
+static const unsigned int msiof1_tsync_mux[] = {
+       MSIOF1_TSYNC_MARK,
+};
+static const unsigned int msiof1_ss1_pins[] = {
+       /* SS1 */
+       238,
+};
+static const unsigned int msiof1_ss1_mux[] = {
+       MSIOF1_SS1_MARK,
+};
+static const unsigned int msiof1_ss2_pins[] = {
+       /* SS2 */
+       239,
+};
+static const unsigned int msiof1_ss2_mux[] = {
+       MSIOF1_SS2_MARK,
+};
+static const unsigned int msiof1_rxd_pins[] = {
+       /* RXD */
+       233,
+};
+static const unsigned int msiof1_rxd_mux[] = {
+       MSIOF1_RXD_MARK,
+};
+static const unsigned int msiof1_txd_pins[] = {
+       /* TXD */
+       230,
+};
+static const unsigned int msiof1_txd_mux[] = {
+       MSIOF1_TXD_MARK,
+};
+static const unsigned int msiof1_mck0_pins[] = {
+       /* MSCK0 */
+       236,
+};
+static const unsigned int msiof1_mck0_mux[] = {
+       MSIOF1_MCK0_MARK,
+};
+static const unsigned int msiof1_mck1_pins[] = {
+       /* MSCK1 */
+       237,
+};
+static const unsigned int msiof1_mck1_mux[] = {
+       MSIOF1_MCK1_MARK,
+};
+/* - MSIOF2 ----------------------------------------------------------------- */
+static const unsigned int msiof2_rsck_pins[] = {
+       /* RSCK */
+       151,
+};
+static const unsigned int msiof2_rsck_mux[] = {
+       MSIOF2_RSCK_MARK,
+};
+static const unsigned int msiof2_tsck_pins[] = {
+       /* TSCK */
+       135,
+};
+static const unsigned int msiof2_tsck_mux[] = {
+       MSIOF2_TSCK_MARK,
+};
+static const unsigned int msiof2_rsync_pins[] = {
+       /* RSYNC */
+       152,
+};
+static const unsigned int msiof2_rsync_mux[] = {
+       MSIOF2_RSYNC_MARK,
+};
+static const unsigned int msiof2_tsync_pins[] = {
+       /* TSYNC */
+       133,
+};
+static const unsigned int msiof2_tsync_mux[] = {
+       MSIOF2_TSYNC_MARK,
+};
+static const unsigned int msiof2_ss1_a_pins[] = {
+       /* SS1 */
+       131,
+};
+static const unsigned int msiof2_ss1_a_mux[] = {
+       PORT131_MSIOF2_SS1_MARK,
+};
+static const unsigned int msiof2_ss1_b_pins[] = {
+       /* SS1 */
+       153,
+};
+static const unsigned int msiof2_ss1_b_mux[] = {
+       PORT153_MSIOF2_SS1_MARK,
+};
+static const unsigned int msiof2_ss2_a_pins[] = {
+       /* SS2 */
+       132,
+};
+static const unsigned int msiof2_ss2_a_mux[] = {
+       PORT132_MSIOF2_SS2_MARK,
+};
+static const unsigned int msiof2_ss2_b_pins[] = {
+       /* SS2 */
+       156,
+};
+static const unsigned int msiof2_ss2_b_mux[] = {
+       PORT156_MSIOF2_SS2_MARK,
+};
+static const unsigned int msiof2_rxd_a_pins[] = {
+       /* RXD */
+       130,
+};
+static const unsigned int msiof2_rxd_a_mux[] = {
+       PORT130_MSIOF2_RXD_MARK,
+};
+static const unsigned int msiof2_rxd_b_pins[] = {
+       /* RXD */
+       157,
+};
+static const unsigned int msiof2_rxd_b_mux[] = {
+       PORT157_MSIOF2_RXD_MARK,
+};
+static const unsigned int msiof2_txd_pins[] = {
+       /* TXD */
+       134,
+};
+static const unsigned int msiof2_txd_mux[] = {
+       MSIOF2_TXD_MARK,
+};
+static const unsigned int msiof2_mck0_pins[] = {
+       /* MSCK0 */
+       154,
+};
+static const unsigned int msiof2_mck0_mux[] = {
+       MSIOF2_MCK0_MARK,
+};
+static const unsigned int msiof2_mck1_pins[] = {
+       /* MSCK1 */
+       155,
+};
+static const unsigned int msiof2_mck1_mux[] = {
+       MSIOF2_MCK1_MARK,
+};
+
+static const unsigned int msiof2r_tsck_pins[] = {
+       /* TSCK */
+       248,
+};
+static const unsigned int msiof2r_tsck_mux[] = {
+       MSIOF2R_TSCK_MARK,
+};
+static const unsigned int msiof2r_tsync_pins[] = {
+       /* TSYNC */
+       249,
+};
+static const unsigned int msiof2r_tsync_mux[] = {
+       MSIOF2R_TSYNC_MARK,
+};
+static const unsigned int msiof2r_rxd_pins[] = {
+       /* RXD */
+       244,
+};
+static const unsigned int msiof2r_rxd_mux[] = {
+       MSIOF2R_RXD_MARK,
+};
+static const unsigned int msiof2r_txd_pins[] = {
+       /* TXD */
+       245,
+};
+static const unsigned int msiof2r_txd_mux[] = {
+       MSIOF2R_TXD_MARK,
+};
+/* - MSIOF3 (Pin function name of MSIOF3 is named BBIF1) -------------------- */
+static const unsigned int msiof3_rsck_pins[] = {
+       /* RSCK */
+       115,
+};
+static const unsigned int msiof3_rsck_mux[] = {
+       BBIF1_RSCK_MARK,
+};
+static const unsigned int msiof3_tsck_pins[] = {
+       /* TSCK */
+       112,
+};
+static const unsigned int msiof3_tsck_mux[] = {
+       BBIF1_TSCK_MARK,
+};
+static const unsigned int msiof3_rsync_pins[] = {
+       /* RSYNC */
+       116,
+};
+static const unsigned int msiof3_rsync_mux[] = {
+       BBIF1_RSYNC_MARK,
+};
+static const unsigned int msiof3_tsync_pins[] = {
+       /* TSYNC */
+       113,
+};
+static const unsigned int msiof3_tsync_mux[] = {
+       BBIF1_TSYNC_MARK,
+};
+static const unsigned int msiof3_ss1_pins[] = {
+       /* SS1 */
+       117,
+};
+static const unsigned int msiof3_ss1_mux[] = {
+       BBIF1_SS1_MARK,
+};
+static const unsigned int msiof3_ss2_pins[] = {
+       /* SS2 */
+       109,
+};
+static const unsigned int msiof3_ss2_mux[] = {
+       BBIF1_SS2_MARK,
+};
+static const unsigned int msiof3_rxd_pins[] = {
+       /* RXD */
+       111,
+};
+static const unsigned int msiof3_rxd_mux[] = {
+       BBIF1_RXD_MARK,
+};
+static const unsigned int msiof3_txd_pins[] = {
+       /* TXD */
+       114,
+};
+static const unsigned int msiof3_txd_mux[] = {
+       BBIF1_TXD_MARK,
+};
+static const unsigned int msiof3_flow_pins[] = {
+       /* FLOW */
+       117,
+};
+static const unsigned int msiof3_flow_mux[] = {
+       BBIF1_FLOW_MARK,
+};
+
 /* - SCIFA0 ----------------------------------------------------------------- */
 static const unsigned int scifa0_data_pins[] = {
        /* RXD, TXD */
@@ -2782,6 +3196,64 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(mmc0_data4_1),
        SH_PFC_PIN_GROUP(mmc0_data8_1),
        SH_PFC_PIN_GROUP(mmc0_ctrl_1),
+       SH_PFC_PIN_GROUP(msiof0_rsck),
+       SH_PFC_PIN_GROUP(msiof0_tsck),
+       SH_PFC_PIN_GROUP(msiof0_rsync),
+       SH_PFC_PIN_GROUP(msiof0_tsync),
+       SH_PFC_PIN_GROUP(msiof0_ss1),
+       SH_PFC_PIN_GROUP(msiof0_ss2),
+       SH_PFC_PIN_GROUP(msiof0_rxd),
+       SH_PFC_PIN_GROUP(msiof0_txd),
+       SH_PFC_PIN_GROUP(msiof0_mck0),
+       SH_PFC_PIN_GROUP(msiof0_mck1),
+       SH_PFC_PIN_GROUP(msiof0l_rsck),
+       SH_PFC_PIN_GROUP(msiof0l_tsck),
+       SH_PFC_PIN_GROUP(msiof0l_rsync),
+       SH_PFC_PIN_GROUP(msiof0l_tsync),
+       SH_PFC_PIN_GROUP(msiof0l_ss1_a),
+       SH_PFC_PIN_GROUP(msiof0l_ss1_b),
+       SH_PFC_PIN_GROUP(msiof0l_ss2_a),
+       SH_PFC_PIN_GROUP(msiof0l_ss2_b),
+       SH_PFC_PIN_GROUP(msiof0l_rxd),
+       SH_PFC_PIN_GROUP(msiof0l_txd),
+       SH_PFC_PIN_GROUP(msiof0l_mck0),
+       SH_PFC_PIN_GROUP(msiof0l_mck1),
+       SH_PFC_PIN_GROUP(msiof1_rsck),
+       SH_PFC_PIN_GROUP(msiof1_tsck),
+       SH_PFC_PIN_GROUP(msiof1_rsync),
+       SH_PFC_PIN_GROUP(msiof1_tsync),
+       SH_PFC_PIN_GROUP(msiof1_ss1),
+       SH_PFC_PIN_GROUP(msiof1_ss2),
+       SH_PFC_PIN_GROUP(msiof1_rxd),
+       SH_PFC_PIN_GROUP(msiof1_txd),
+       SH_PFC_PIN_GROUP(msiof1_mck0),
+       SH_PFC_PIN_GROUP(msiof1_mck1),
+       SH_PFC_PIN_GROUP(msiof2_rsck),
+       SH_PFC_PIN_GROUP(msiof2_tsck),
+       SH_PFC_PIN_GROUP(msiof2_rsync),
+       SH_PFC_PIN_GROUP(msiof2_tsync),
+       SH_PFC_PIN_GROUP(msiof2_ss1_a),
+       SH_PFC_PIN_GROUP(msiof2_ss1_b),
+       SH_PFC_PIN_GROUP(msiof2_ss2_a),
+       SH_PFC_PIN_GROUP(msiof2_ss2_b),
+       SH_PFC_PIN_GROUP(msiof2_rxd_a),
+       SH_PFC_PIN_GROUP(msiof2_rxd_b),
+       SH_PFC_PIN_GROUP(msiof2_txd),
+       SH_PFC_PIN_GROUP(msiof2_mck0),
+       SH_PFC_PIN_GROUP(msiof2_mck1),
+       SH_PFC_PIN_GROUP(msiof2r_tsck),
+       SH_PFC_PIN_GROUP(msiof2r_tsync),
+       SH_PFC_PIN_GROUP(msiof2r_rxd),
+       SH_PFC_PIN_GROUP(msiof2r_txd),
+       SH_PFC_PIN_GROUP(msiof3_rsck),
+       SH_PFC_PIN_GROUP(msiof3_tsck),
+       SH_PFC_PIN_GROUP(msiof3_rsync),
+       SH_PFC_PIN_GROUP(msiof3_tsync),
+       SH_PFC_PIN_GROUP(msiof3_ss1),
+       SH_PFC_PIN_GROUP(msiof3_ss2),
+       SH_PFC_PIN_GROUP(msiof3_rxd),
+       SH_PFC_PIN_GROUP(msiof3_txd),
+       SH_PFC_PIN_GROUP(msiof3_flow),
        SH_PFC_PIN_GROUP(scifa0_data),
        SH_PFC_PIN_GROUP(scifa0_clk),
        SH_PFC_PIN_GROUP(scifa0_ctrl),
@@ -2982,6 +3454,76 @@ static const char * const mmc0_groups[] = {
        "mmc0_ctrl_1",
 };
 
+static const char * const msiof0_groups[] = {
+       "msiof0_rsck",
+       "msiof0_tsck",
+       "msiof0_rsync",
+       "msiof0_tsync",
+       "msiof0_ss1",
+       "msiof0_ss2",
+       "msiof0_rxd",
+       "msiof0_txd",
+       "msiof0_mck0",
+       "msiof0_mck1",
+       "msiof0l_rsck",
+       "msiof0l_tsck",
+       "msiof0l_rsync",
+       "msiof0l_tsync",
+       "msiof0l_ss1_a",
+       "msiof0l_ss1_b",
+       "msiof0l_ss2_a",
+       "msiof0l_ss2_b",
+       "msiof0l_rxd",
+       "msiof0l_txd",
+       "msiof0l_mck0",
+       "msiof0l_mck1",
+};
+
+static const char * const msiof1_groups[] = {
+       "msiof1_rsck",
+       "msiof1_tsck",
+       "msiof1_rsync",
+       "msiof1_tsync",
+       "msiof1_ss1",
+       "msiof1_ss2",
+       "msiof1_rxd",
+       "msiof1_txd",
+       "msiof1_mck0",
+       "msiof1_mck1",
+};
+
+static const char * const msiof2_groups[] = {
+       "msiof2_rsck",
+       "msiof2_tsck",
+       "msiof2_rsync",
+       "msiof2_tsync",
+       "msiof2_ss1_a",
+       "msiof2_ss1_b",
+       "msiof2_ss2_a",
+       "msiof2_ss2_b",
+       "msiof2_rxd_a",
+       "msiof2_rxd_b",
+       "msiof2_txd",
+       "msiof2_mck0",
+       "msiof2_mck1",
+       "msiof2r_tsck",
+       "msiof2r_tsync",
+       "msiof2r_rxd",
+       "msiof2r_txd",
+};
+
+static const char * const msiof3_groups[] = {
+       "msiof3_rsck",
+       "msiof3_tsck",
+       "msiof3_rsync",
+       "msiof3_tsync",
+       "msiof3_ss1",
+       "msiof3_ss2",
+       "msiof3_rxd",
+       "msiof3_txd",
+       "msiof3_flow",
+};
+
 static const char * const scifa0_groups[] = {
        "scifa0_data",
        "scifa0_clk",
@@ -3116,6 +3658,10 @@ static const struct sh_pfc_function pinmux_functions[] = {
        SH_PFC_FUNCTION(lcd),
        SH_PFC_FUNCTION(lcd2),
        SH_PFC_FUNCTION(mmc0),
+       SH_PFC_FUNCTION(msiof0),
+       SH_PFC_FUNCTION(msiof1),
+       SH_PFC_FUNCTION(msiof2),
+       SH_PFC_FUNCTION(msiof3),
        SH_PFC_FUNCTION(scifa0),
        SH_PFC_FUNCTION(scifa1),
        SH_PFC_FUNCTION(scifa2),
index 9842bb1067969701a8879b3de481f3da6d2349a7..b0b328b3130b13247672cf5bbca3d6be10f8b504 100644 (file)
 
 #include "sh_pfc.h"
 
-#define PORT_GP_12(bank, fn, sfx)                                      \
-       PORT_GP_1(bank, 0, fn, sfx),  PORT_GP_1(bank, 1, fn, sfx),      \
-       PORT_GP_1(bank, 2, fn, sfx),  PORT_GP_1(bank, 3, fn, sfx),      \
-       PORT_GP_1(bank, 4, fn, sfx),  PORT_GP_1(bank, 5, fn, sfx),      \
-       PORT_GP_1(bank, 6, fn, sfx),  PORT_GP_1(bank, 7, fn, sfx),      \
-       PORT_GP_1(bank, 8, fn, sfx),  PORT_GP_1(bank, 9, fn, sfx),      \
-       PORT_GP_1(bank, 10, fn, sfx), PORT_GP_1(bank, 11, fn, sfx)
-
 #define CPU_ALL_PORT(fn, sfx)                                          \
        PORT_GP_32(0, fn, sfx),                                         \
        PORT_GP_32(1, fn, sfx),                                         \
@@ -585,15 +577,18 @@ enum {
 static const u16 pinmux_data[] = {
        PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
 
-       PINMUX_DATA(CLKOUT_MARK, FN_CLKOUT),
-       PINMUX_DATA(BS_MARK, FN_BS), PINMUX_DATA(CS0_MARK, FN_CS0),
-       PINMUX_DATA(EX_CS0_MARK, FN_EX_CS0),
-       PINMUX_DATA(RD_MARK, FN_RD), PINMUX_DATA(WE0_MARK, FN_WE0),
-       PINMUX_DATA(WE1_MARK, FN_WE1),
-       PINMUX_DATA(SCL0_MARK, FN_SCL0), PINMUX_DATA(PENC0_MARK, FN_PENC0),
-       PINMUX_DATA(USB_OVC0_MARK, FN_USB_OVC0),
-       PINMUX_DATA(IRQ2_B_MARK, FN_IRQ2_B),
-               PINMUX_DATA(IRQ3_B_MARK, FN_IRQ3_B),
+       PINMUX_SINGLE(CLKOUT),
+       PINMUX_SINGLE(BS),
+       PINMUX_SINGLE(CS0),
+       PINMUX_SINGLE(EX_CS0),
+       PINMUX_SINGLE(RD),
+       PINMUX_SINGLE(WE0),
+       PINMUX_SINGLE(WE1),
+       PINMUX_SINGLE(SCL0),
+       PINMUX_SINGLE(PENC0),
+       PINMUX_SINGLE(USB_OVC0),
+       PINMUX_SINGLE(IRQ2_B),
+       PINMUX_SINGLE(IRQ3_B),
 
        /* IPSR0 */
        PINMUX_IPSR_DATA(IP0_1_0, A0),
index 863c3e30ce05f9ce6b99fd328d53a6aa4bbb3dcc..87b0a599afafb62498142bda6f8ae3057e3ce03f 100644 (file)
@@ -273,8 +273,10 @@ static int sh_pfc_dt_node_to_map(struct pinctrl_dev *pctldev,
        for_each_child_of_node(np, child) {
                ret = sh_pfc_dt_subnode_to_map(pctldev, child, map, num_maps,
                                               &index);
-               if (ret < 0)
+               if (ret < 0) {
+                       of_node_put(child);
                        goto done;
+               }
        }
 
        /* If no mapping has been found in child nodes try the config node. */
index 7b373d43d981899f1d85e5eab6846025235f1d89..2123ab49d6a50151c51da3f90b65e5938c5c86f9 100644 (file)
@@ -198,6 +198,14 @@ struct sh_pfc_soc_info {
 #define PINMUX_IPSR_MSEL(ipsr, fn, ms)                                 \
        PINMUX_DATA(fn##_MARK, FN_##ms, FN_##ipsr, FN_##fn)
 
+/*
+ * Describe a pinmux configuration for a single-function pin with GPIO
+ * capability.
+ *   - fn: Function name
+ */
+#define PINMUX_SINGLE(fn)                                              \
+       PINMUX_DATA(fn##_MARK, FN_##fn)
+
 /*
  * GP port style (32 ports banks)
  */
@@ -205,22 +213,68 @@ struct sh_pfc_soc_info {
 #define PORT_GP_CFG_1(bank, pin, fn, sfx, cfg) fn(bank, pin, GP_##bank##_##pin, sfx, cfg)
 #define PORT_GP_1(bank, pin, fn, sfx)  PORT_GP_CFG_1(bank, pin, fn, sfx, 0)
 
-#define PORT_GP_CFG_32(bank, fn, sfx, cfg)                             \
+#define PORT_GP_CFG_4(bank, fn, sfx, cfg)                                              \
        PORT_GP_CFG_1(bank, 0,  fn, sfx, cfg), PORT_GP_CFG_1(bank, 1,  fn, sfx, cfg),   \
-       PORT_GP_CFG_1(bank, 2,  fn, sfx, cfg), PORT_GP_CFG_1(bank, 3,  fn, sfx, cfg),   \
+       PORT_GP_CFG_1(bank, 2,  fn, sfx, cfg), PORT_GP_CFG_1(bank, 3,  fn, sfx, cfg)
+#define PORT_GP_4(bank, fn, sfx)       PORT_GP_CFG_4(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_8(bank, fn, sfx, cfg)                                              \
+       PORT_GP_CFG_4(bank, fn, sfx, cfg),                                              \
        PORT_GP_CFG_1(bank, 4,  fn, sfx, cfg), PORT_GP_CFG_1(bank, 5,  fn, sfx, cfg),   \
-       PORT_GP_CFG_1(bank, 6,  fn, sfx, cfg), PORT_GP_CFG_1(bank, 7,  fn, sfx, cfg),   \
+       PORT_GP_CFG_1(bank, 6,  fn, sfx, cfg), PORT_GP_CFG_1(bank, 7,  fn, sfx, cfg)
+#define PORT_GP_8(bank, fn, sfx)       PORT_GP_CFG_8(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_9(bank, fn, sfx, cfg)                                              \
+       PORT_GP_CFG_8(bank, fn, sfx, cfg),                                              \
+       PORT_GP_CFG_1(bank, 8,  fn, sfx, cfg)
+#define PORT_GP_9(bank, fn, sfx)       PORT_GP_CFG_9(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_12(bank, fn, sfx, cfg)                                             \
+       PORT_GP_CFG_8(bank, fn, sfx, cfg),                                              \
        PORT_GP_CFG_1(bank, 8,  fn, sfx, cfg), PORT_GP_CFG_1(bank, 9,  fn, sfx, cfg),   \
-       PORT_GP_CFG_1(bank, 10, fn, sfx, cfg), PORT_GP_CFG_1(bank, 11, fn, sfx, cfg),   \
-       PORT_GP_CFG_1(bank, 12, fn, sfx, cfg), PORT_GP_CFG_1(bank, 13, fn, sfx, cfg),   \
-       PORT_GP_CFG_1(bank, 14, fn, sfx, cfg), PORT_GP_CFG_1(bank, 15, fn, sfx, cfg),   \
-       PORT_GP_CFG_1(bank, 16, fn, sfx, cfg), PORT_GP_CFG_1(bank, 17, fn, sfx, cfg),   \
+       PORT_GP_CFG_1(bank, 10, fn, sfx, cfg), PORT_GP_CFG_1(bank, 11, fn, sfx, cfg)
+#define PORT_GP_12(bank, fn, sfx)      PORT_GP_CFG_12(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_14(bank, fn, sfx, cfg)                                             \
+       PORT_GP_CFG_12(bank, fn, sfx, cfg),                                             \
+       PORT_GP_CFG_1(bank, 12, fn, sfx, cfg), PORT_GP_CFG_1(bank, 13, fn, sfx, cfg)
+#define PORT_GP_14(bank, fn, sfx)      PORT_GP_CFG_14(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_15(bank, fn, sfx, cfg)                                             \
+       PORT_GP_CFG_14(bank, fn, sfx, cfg),                                             \
+       PORT_GP_CFG_1(bank, 14, fn, sfx, cfg)
+#define PORT_GP_15(bank, fn, sfx)      PORT_GP_CFG_15(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_16(bank, fn, sfx, cfg)                                             \
+       PORT_GP_CFG_14(bank, fn, sfx, cfg),                                             \
+       PORT_GP_CFG_1(bank, 14, fn, sfx, cfg), PORT_GP_CFG_1(bank, 15, fn, sfx, cfg)
+#define PORT_GP_16(bank, fn, sfx)      PORT_GP_CFG_16(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_18(bank, fn, sfx, cfg)                                             \
+       PORT_GP_CFG_16(bank, fn, sfx, cfg),                                             \
+       PORT_GP_CFG_1(bank, 16, fn, sfx, cfg), PORT_GP_CFG_1(bank, 17, fn, sfx, cfg)
+#define PORT_GP_18(bank, fn, sfx)      PORT_GP_CFG_18(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_26(bank, fn, sfx, cfg)                                             \
+       PORT_GP_CFG_18(bank, fn, sfx, cfg),                                             \
        PORT_GP_CFG_1(bank, 18, fn, sfx, cfg), PORT_GP_CFG_1(bank, 19, fn, sfx, cfg),   \
        PORT_GP_CFG_1(bank, 20, fn, sfx, cfg), PORT_GP_CFG_1(bank, 21, fn, sfx, cfg),   \
        PORT_GP_CFG_1(bank, 22, fn, sfx, cfg), PORT_GP_CFG_1(bank, 23, fn, sfx, cfg),   \
-       PORT_GP_CFG_1(bank, 24, fn, sfx, cfg), PORT_GP_CFG_1(bank, 25, fn, sfx, cfg),   \
-       PORT_GP_CFG_1(bank, 26, fn, sfx, cfg), PORT_GP_CFG_1(bank, 27, fn, sfx, cfg),   \
-       PORT_GP_CFG_1(bank, 28, fn, sfx, cfg), PORT_GP_CFG_1(bank, 29, fn, sfx, cfg),   \
+       PORT_GP_CFG_1(bank, 24, fn, sfx, cfg), PORT_GP_CFG_1(bank, 25, fn, sfx, cfg)
+#define PORT_GP_26(bank, fn, sfx)      PORT_GP_CFG_26(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_28(bank, fn, sfx, cfg)                                             \
+       PORT_GP_CFG_26(bank, fn, sfx, cfg),                                             \
+       PORT_GP_CFG_1(bank, 26, fn, sfx, cfg), PORT_GP_CFG_1(bank, 27, fn, sfx, cfg)
+#define PORT_GP_28(bank, fn, sfx)      PORT_GP_CFG_28(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_30(bank, fn, sfx, cfg)                                             \
+       PORT_GP_CFG_28(bank, fn, sfx, cfg),                                             \
+       PORT_GP_CFG_1(bank, 28, fn, sfx, cfg), PORT_GP_CFG_1(bank, 29, fn, sfx, cfg)
+#define PORT_GP_30(bank, fn, sfx)      PORT_GP_CFG_30(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_32(bank, fn, sfx, cfg)                                             \
+       PORT_GP_CFG_30(bank, fn, sfx, cfg),                                             \
        PORT_GP_CFG_1(bank, 30, fn, sfx, cfg), PORT_GP_CFG_1(bank, 31, fn, sfx, cfg)
 #define PORT_GP_32(bank, fn, sfx)      PORT_GP_CFG_32(bank, fn, sfx, 0)
 
index 829018c812bdda3690f7449626cecccb2de8874b..053d98e33944a8df7fa71dcc8a575501aafac066 100644 (file)
@@ -161,6 +161,9 @@ enum altas7_pad_type {
 #define IN_DISABLE_VAL_1_REG_SET       0x0A88
 #define IN_DISABLE_VAL_1_REG_CLR       0x0A8C
 
+/* Offset of the SDIO9SEL*/
+#define SYS2PCI_SDIO9SEL 0x14
+
 struct dt_params {
        const char *property;
        int value;
@@ -370,6 +373,7 @@ struct atlas7_pmx {
        struct pinctrl_desc pctl_desc;
        struct atlas7_pinctrl_data *pctl_data;
        void __iomem *regs[ATLAS7_PINCTRL_REG_BANKS];
+       void __iomem *sys2pci_base;
        u32 status_ds[NUM_OF_IN_DISABLE_REG];
        u32 status_dsv[NUM_OF_IN_DISABLE_REG];
        struct atlas7_pad_status sleep_data[ATLAS7_PINCTRL_TOTAL_PINS];
@@ -885,11 +889,12 @@ static const unsigned int lr_lcdrom_pins[] = { 73, 54, 57, 58, 59, 60, 61,
                62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 56, 53, 55, };
 static const unsigned int lvds_analog_pins[] = { 149, 150, 151, 152, 153, 154,
                155, 156, 157, 158, };
-static const unsigned int nd_df_pins[] = { 44, 43, 42, 41, 40, 39, 38, 37,
-               47, 46, 52, 51, 45, 49, 50, 48, 124, };
-static const unsigned int nd_df_nowp_pins[] = { 44, 43, 42, 41, 40, 39, 38,
-               37, 47, 46, 52, 51, 45, 49, 50, 48, };
+static const unsigned int nd_df_basic_pins[] = { 44, 43, 42, 41, 40, 39, 38,
+               37, 47, 46, 52, 45, 49, 50, 48, };
+static const unsigned int nd_df_wp_pins[] = { 124, };
+static const unsigned int nd_df_cs_pins[] = { 51, };
 static const unsigned int ps_pins[] = { 120, 119, 121, };
+static const unsigned int ps_no_dir_pins[] = { 119, };
 static const unsigned int pwc_core_on_pins[] = { 8, };
 static const unsigned int pwc_ext_on_pins[] = { 6, };
 static const unsigned int pwc_gpio3_clk_pins[] = { 3, };
@@ -944,7 +949,7 @@ static const unsigned int sd2_cdb_pins0[] = { 124, };
 static const unsigned int sd2_cdb_pins1[] = { 161, };
 static const unsigned int sd2_wpb_pins0[] = { 123, };
 static const unsigned int sd2_wpb_pins1[] = { 163, };
-static const unsigned int sd3_pins[] = { 85, 86, 87, 88, 89, 90, };
+static const unsigned int sd3_9_pins[] = { 85, 86, 87, 88, 89, 90, };
 static const unsigned int sd5_pins[] = { 91, 92, 93, 94, 95, 96, };
 static const unsigned int sd6_pins0[] = { 79, 78, 74, 75, 76, 77, };
 static const unsigned int sd6_pins1[] = { 101, 99, 100, 110, 109, 111, };
@@ -998,9 +1003,9 @@ static const unsigned int vi_vip1_ext_pins[] = { 74, 75, 76, 77, 78, 79, 80,
                81, 82, 83, 84, 108, 103, 104, 105, 106, 107, 102, 97, 98,
                99, 100, };
 static const unsigned int vi_vip1_low8bit_pins[] = { 74, 75, 76, 77, 78, 79,
-               80, 81, };
-static const unsigned int vi_vip1_high8bit_pins[] = { 82, 83, 84, 108, 103,
-               104, 105, 106, };
+               80, 81, 82, 83, 84, };
+static const unsigned int vi_vip1_high8bit_pins[] = { 82, 83, 84, 103, 104,
+               105, 106, 107, 102, 97, 98, };
 
 /* definition of pin group table */
 struct atlas7_pin_group altas7_pin_groups[] = {
@@ -1142,9 +1147,11 @@ struct atlas7_pin_group altas7_pin_groups[] = {
        GROUP("ld_ldd_lck_grp", ld_ldd_lck_pins),
        GROUP("lr_lcdrom_grp", lr_lcdrom_pins),
        GROUP("lvds_analog_grp", lvds_analog_pins),
-       GROUP("nd_df_grp", nd_df_pins),
-       GROUP("nd_df_nowp_grp", nd_df_nowp_pins),
+       GROUP("nd_df_basic_grp", nd_df_basic_pins),
+       GROUP("nd_df_wp_grp", nd_df_wp_pins),
+       GROUP("nd_df_cs_grp", nd_df_cs_pins),
        GROUP("ps_grp", ps_pins),
+       GROUP("ps_no_dir_grp", ps_no_dir_pins),
        GROUP("pwc_core_on_grp", pwc_core_on_pins),
        GROUP("pwc_ext_on_grp", pwc_ext_on_pins),
        GROUP("pwc_gpio3_clk_grp", pwc_gpio3_clk_pins),
@@ -1196,7 +1203,7 @@ struct atlas7_pin_group altas7_pin_groups[] = {
        GROUP("sd2_cdb_grp1", sd2_cdb_pins1),
        GROUP("sd2_wpb_grp0", sd2_wpb_pins0),
        GROUP("sd2_wpb_grp1", sd2_wpb_pins1),
-       GROUP("sd3_grp", sd3_pins),
+       GROUP("sd3_9_grp", sd3_9_pins),
        GROUP("sd5_grp", sd5_pins),
        GROUP("sd6_grp0", sd6_pins0),
        GROUP("sd6_grp1", sd6_pins1),
@@ -1421,9 +1428,11 @@ static const char * const ld_ldd_fck_grp[] = { "ld_ldd_fck_grp", };
 static const char * const ld_ldd_lck_grp[] = { "ld_ldd_lck_grp", };
 static const char * const lr_lcdrom_grp[] = { "lr_lcdrom_grp", };
 static const char * const lvds_analog_grp[] = { "lvds_analog_grp", };
-static const char * const nd_df_grp[] = { "nd_df_grp", };
-static const char * const nd_df_nowp_grp[] = { "nd_df_nowp_grp", };
+static const char * const nd_df_basic_grp[] = { "nd_df_basic_grp", };
+static const char * const nd_df_wp_grp[] = { "nd_df_wp_grp", };
+static const char * const nd_df_cs_grp[] = { "nd_df_cs_grp", };
 static const char * const ps_grp[] = { "ps_grp", };
+static const char * const ps_no_dir_grp[] = { "ps_no_dir_grp", };
 static const char * const pwc_core_on_grp[] = { "pwc_core_on_grp", };
 static const char * const pwc_ext_on_grp[] = { "pwc_ext_on_grp", };
 static const char * const pwc_gpio3_clk_grp[] = { "pwc_gpio3_clk_grp", };
@@ -1478,7 +1487,7 @@ static const char * const sd2_cdb_grp0[] = { "sd2_cdb_grp0", };
 static const char * const sd2_cdb_grp1[] = { "sd2_cdb_grp1", };
 static const char * const sd2_wpb_grp0[] = { "sd2_wpb_grp0", };
 static const char * const sd2_wpb_grp1[] = { "sd2_wpb_grp1", };
-static const char * const sd3_grp[] = { "sd3_grp", };
+static const char * const sd3_9_grp[] = { "sd3_9_grp", };
 static const char * const sd5_grp[] = { "sd5_grp", };
 static const char * const sd6_grp0[] = { "sd6_grp0", };
 static const char * const sd6_grp1[] = { "sd6_grp1", };
@@ -3174,7 +3183,7 @@ static struct atlas7_grp_mux lvds_analog_grp_mux = {
        .pad_mux_list = lvds_analog_grp_pad_mux,
 };
 
-static struct atlas7_pad_mux nd_df_grp_pad_mux[] = {
+static struct atlas7_pad_mux nd_df_basic_grp_pad_mux[] = {
        MUX(1, 44, 1, N, N, N, N),
        MUX(1, 43, 1, N, N, N, N),
        MUX(1, 42, 1, N, N, N, N),
@@ -3186,41 +3195,33 @@ static struct atlas7_pad_mux nd_df_grp_pad_mux[] = {
        MUX(1, 47, 1, N, N, N, N),
        MUX(1, 46, 1, N, N, N, N),
        MUX(1, 52, 1, N, N, N, N),
-       MUX(1, 51, 1, N, N, N, N),
        MUX(1, 45, 1, N, N, N, N),
        MUX(1, 49, 1, N, N, N, N),
        MUX(1, 50, 1, N, N, N, N),
        MUX(1, 48, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux nd_df_basic_grp_mux = {
+       .pad_mux_count = ARRAY_SIZE(nd_df_basic_grp_pad_mux),
+       .pad_mux_list = nd_df_basic_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux nd_df_wp_grp_pad_mux[] = {
        MUX(1, 124, 4, N, N, N, N),
 };
 
-static struct atlas7_grp_mux nd_df_grp_mux = {
-       .pad_mux_count = ARRAY_SIZE(nd_df_grp_pad_mux),
-       .pad_mux_list = nd_df_grp_pad_mux,
+static struct atlas7_grp_mux nd_df_wp_grp_mux = {
+       .pad_mux_count = ARRAY_SIZE(nd_df_wp_grp_pad_mux),
+       .pad_mux_list = nd_df_wp_grp_pad_mux,
 };
 
-static struct atlas7_pad_mux nd_df_nowp_grp_pad_mux[] = {
-       MUX(1, 44, 1, N, N, N, N),
-       MUX(1, 43, 1, N, N, N, N),
-       MUX(1, 42, 1, N, N, N, N),
-       MUX(1, 41, 1, N, N, N, N),
-       MUX(1, 40, 1, N, N, N, N),
-       MUX(1, 39, 1, N, N, N, N),
-       MUX(1, 38, 1, N, N, N, N),
-       MUX(1, 37, 1, N, N, N, N),
-       MUX(1, 47, 1, N, N, N, N),
-       MUX(1, 46, 1, N, N, N, N),
-       MUX(1, 52, 1, N, N, N, N),
+static struct atlas7_pad_mux nd_df_cs_grp_pad_mux[] = {
        MUX(1, 51, 1, N, N, N, N),
-       MUX(1, 45, 1, N, N, N, N),
-       MUX(1, 49, 1, N, N, N, N),
-       MUX(1, 50, 1, N, N, N, N),
-       MUX(1, 48, 1, N, N, N, N),
 };
 
-static struct atlas7_grp_mux nd_df_nowp_grp_mux = {
-       .pad_mux_count = ARRAY_SIZE(nd_df_nowp_grp_pad_mux),
-       .pad_mux_list = nd_df_nowp_grp_pad_mux,
+static struct atlas7_grp_mux nd_df_cs_grp_mux = {
+       .pad_mux_count = ARRAY_SIZE(nd_df_cs_grp_pad_mux),
+       .pad_mux_list = nd_df_cs_grp_pad_mux,
 };
 
 static struct atlas7_pad_mux ps_grp_pad_mux[] = {
@@ -3234,6 +3235,15 @@ static struct atlas7_grp_mux ps_grp_mux = {
        .pad_mux_list = ps_grp_pad_mux,
 };
 
+static struct atlas7_pad_mux ps_no_dir_grp_pad_mux[] = {
+       MUX(1, 119, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux ps_no_dir_grp_mux = {
+       .pad_mux_count = ARRAY_SIZE(ps_no_dir_grp_pad_mux),
+       .pad_mux_list = ps_no_dir_grp_pad_mux,
+};
+
 static struct atlas7_pad_mux pwc_core_on_grp_pad_mux[] = {
        MUX(0, 8, 1, N, N, N, N),
 };
@@ -3743,7 +3753,7 @@ static struct atlas7_grp_mux sd2_wpb_grp1_mux = {
        .pad_mux_list = sd2_wpb_grp1_pad_mux,
 };
 
-static struct atlas7_pad_mux sd3_grp_pad_mux[] = {
+static struct atlas7_pad_mux sd3_9_grp_pad_mux[] = {
        MUX(1, 85, 1, N, N, N, N),
        MUX(1, 86, 1, N, N, N, N),
        MUX(1, 87, 1, N, N, N, N),
@@ -3752,9 +3762,9 @@ static struct atlas7_pad_mux sd3_grp_pad_mux[] = {
        MUX(1, 90, 1, N, N, N, N),
 };
 
-static struct atlas7_grp_mux sd3_grp_mux = {
-       .pad_mux_count = ARRAY_SIZE(sd3_grp_pad_mux),
-       .pad_mux_list = sd3_grp_pad_mux,
+static struct atlas7_grp_mux sd3_9_grp_mux = {
+       .pad_mux_count = ARRAY_SIZE(sd3_9_grp_pad_mux),
+       .pad_mux_list = sd3_9_grp_pad_mux,
 };
 
 static struct atlas7_pad_mux sd5_grp_pad_mux[] = {
@@ -4296,6 +4306,9 @@ static struct atlas7_pad_mux vi_vip1_low8bit_grp_pad_mux[] = {
        MUX(1, 79, 1, N, N, N, N),
        MUX(1, 80, 1, N, N, N, N),
        MUX(1, 81, 1, N, N, N, N),
+       MUX(1, 82, 1, N, N, N, N),
+       MUX(1, 83, 1, N, N, N, N),
+       MUX(1, 84, 1, N, N, N, N),
 };
 
 static struct atlas7_grp_mux vi_vip1_low8bit_grp_mux = {
@@ -4307,11 +4320,14 @@ static struct atlas7_pad_mux vi_vip1_high8bit_grp_pad_mux[] = {
        MUX(1, 82, 1, N, N, N, N),
        MUX(1, 83, 1, N, N, N, N),
        MUX(1, 84, 1, N, N, N, N),
-       MUX(1, 108, 2, N, N, N, N),
        MUX(1, 103, 2, N, N, N, N),
        MUX(1, 104, 2, N, N, N, N),
        MUX(1, 105, 2, N, N, N, N),
        MUX(1, 106, 2, N, N, N, N),
+       MUX(1, 107, 2, N, N, N, N),
+       MUX(1, 102, 2, N, N, N, N),
+       MUX(1, 97, 2, N, N, N, N),
+       MUX(1, 98, 2, N, N, N, N),
 };
 
 static struct atlas7_grp_mux vi_vip1_high8bit_grp_mux = {
@@ -4598,9 +4614,11 @@ static struct atlas7_pmx_func atlas7_pmx_functions[] = {
        FUNCTION("ld_ldd_lck", ld_ldd_lck_grp, &ld_ldd_lck_grp_mux),
        FUNCTION("lr_lcdrom", lr_lcdrom_grp, &lr_lcdrom_grp_mux),
        FUNCTION("lvds_analog", lvds_analog_grp, &lvds_analog_grp_mux),
-       FUNCTION("nd_df", nd_df_grp, &nd_df_grp_mux),
-       FUNCTION("nd_df_nowp", nd_df_nowp_grp, &nd_df_nowp_grp_mux),
+       FUNCTION("nd_df_basic", nd_df_basic_grp, &nd_df_basic_grp_mux),
+       FUNCTION("nd_df_wp", nd_df_wp_grp, &nd_df_wp_grp_mux),
+       FUNCTION("nd_df_cs", nd_df_cs_grp, &nd_df_cs_grp_mux),
        FUNCTION("ps", ps_grp, &ps_grp_mux),
+       FUNCTION("ps_no_dir", ps_no_dir_grp, &ps_no_dir_grp_mux),
        FUNCTION("pwc_core_on", pwc_core_on_grp, &pwc_core_on_grp_mux),
        FUNCTION("pwc_ext_on", pwc_ext_on_grp, &pwc_ext_on_grp_mux),
        FUNCTION("pwc_gpio3_clk", pwc_gpio3_clk_grp, &pwc_gpio3_clk_grp_mux),
@@ -4686,10 +4704,11 @@ static struct atlas7_pmx_func atlas7_pmx_functions[] = {
        FUNCTION("sd2_cdb_m1", sd2_cdb_grp1, &sd2_cdb_grp1_mux),
        FUNCTION("sd2_wpb_m0", sd2_wpb_grp0, &sd2_wpb_grp0_mux),
        FUNCTION("sd2_wpb_m1", sd2_wpb_grp1, &sd2_wpb_grp1_mux),
-       FUNCTION("sd3", sd3_grp, &sd3_grp_mux),
+       FUNCTION("sd3", sd3_9_grp, &sd3_9_grp_mux),
        FUNCTION("sd5", sd5_grp, &sd5_grp_mux),
        FUNCTION("sd6_m0", sd6_grp0, &sd6_grp0_mux),
        FUNCTION("sd6_m1", sd6_grp1, &sd6_grp1_mux),
+       FUNCTION("sd9", sd3_9_grp, &sd3_9_grp_mux),
        FUNCTION("sp0_ext_ldo_on",
                        sp0_ext_ldo_on_grp,
                        &sp0_ext_ldo_on_grp_mux),
@@ -5097,6 +5116,14 @@ static int atlas7_pmx_set_mux(struct pinctrl_dev *pctldev,
        pr_debug("PMX DUMP ### Function:[%s] Group:[%s] #### START >>>\n",
                        pmx_func->name, pin_grp->name);
 
+       /* the sd3 and sd9 pin select by SYS2PCI_SDIO9SEL register */
+       if (pin_grp->pins == (unsigned int *)&sd3_9_pins) {
+               if (!strcmp(pmx_func->name, "sd9"))
+                       writel(1, pmx->sys2pci_base + SYS2PCI_SDIO9SEL);
+               else
+                       writel(0, pmx->sys2pci_base + SYS2PCI_SDIO9SEL);
+       }
+
        grp_mux = pmx_func->grpmux;
 
        for (idx = 0; idx < grp_mux->pad_mux_count; idx++) {
@@ -5385,12 +5412,27 @@ static int atlas7_pinmux_probe(struct platform_device *pdev)
        struct atlas7_pmx *pmx;
        struct device_node *np = pdev->dev.of_node;
        u32 banks = ATLAS7_PINCTRL_REG_BANKS;
+       struct device_node *sys2pci_np;
+       struct resource res;
 
        /* Create state holders etc for this driver */
        pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
        if (!pmx)
                return -ENOMEM;
 
+       /* The sd3 and sd9 shared all pins, and the function select by
+        * SYS2PCI_SDIO9SEL register
+        */
+       sys2pci_np = of_find_node_by_name(NULL, "sys2pci");
+       if (!sys2pci_np)
+               return -EINVAL;
+       ret = of_address_to_resource(sys2pci_np, 0, &res);
+       if (ret)
+               return ret;
+       pmx->sys2pci_base = devm_ioremap_resource(&pdev->dev, &res);
+       if (IS_ERR(pmx->sys2pci_base))
+               return -ENOMEM;
+
        pmx->dev = &pdev->dev;
 
        pmx->pctl_data = &atlas7_ioc_data;
index 2a8d69725de81aab6a469faa02558d065f22f7d9..edf40df05ec05b59b73a52c616d4b05472b4becf 100644 (file)
@@ -85,12 +85,16 @@ static int sirfsoc_dt_node_to_map(struct pinctrl_dev *pctldev,
        /* calculate number of maps required */
        for_each_child_of_node(np_config, np) {
                ret = of_property_read_string(np, "sirf,function", &function);
-               if (ret < 0)
+               if (ret < 0) {
+                       of_node_put(np);
                        return ret;
+               }
 
                ret = of_property_count_strings(np, "sirf,pins");
-               if (ret < 0)
+               if (ret < 0) {
+                       of_node_put(np);
                        return ret;
+               }
 
                count += ret;
        }
index 0e400ebeb8ff6d440a9219fae0efa8644bcc6cb6..37b8412ac8a3ce9eb4d0c5ea9b6f8f20fa059f55 100644 (file)
@@ -1,7 +1,7 @@
 # SPEAr pinmux support
 
 obj-$(CONFIG_PINCTRL_SPEAR_PLGPIO)     += pinctrl-plgpio.o
-obj-$(CONFIG_PINCTRL_SPEAR)    += pinctrl-spear.o
+obj-y                          += pinctrl-spear.o
 obj-$(CONFIG_PINCTRL_SPEAR3XX) += pinctrl-spear3xx.o
 obj-$(CONFIG_PINCTRL_SPEAR300) += pinctrl-spear300.o
 obj-$(CONFIG_PINCTRL_SPEAR310) += pinctrl-spear310.o
index e68fd951129a4df5557c4007776fb5aa5891bf2c..f8dbc8bec0e1e5363520abc12263182fe68b6c00 100644 (file)
@@ -51,8 +51,17 @@ config PINCTRL_SUN8I_A23_R
        depends on RESET_CONTROLLER
        select PINCTRL_SUNXI_COMMON
 
+config PINCTRL_SUN8I_H3
+       def_bool MACH_SUN8I
+       select PINCTRL_SUNXI_COMMON
+
 config PINCTRL_SUN9I_A80
        def_bool MACH_SUN9I
        select PINCTRL_SUNXI_COMMON
 
+config PINCTRL_SUN9I_A80_R
+       def_bool MACH_SUN9I
+       depends on RESET_CONTROLLER
+       select PINCTRL_SUNXI_COMMON
+
 endif
index e080290345107d60a52dea9ec054949879f2a5f2..ef82f22bb9ef594ef19e783f2cece3a9962a6de0 100644 (file)
@@ -13,4 +13,6 @@ obj-$(CONFIG_PINCTRL_SUN8I_A23)               += pinctrl-sun8i-a23.o
 obj-$(CONFIG_PINCTRL_SUN8I_A23_R)      += pinctrl-sun8i-a23-r.o
 obj-$(CONFIG_PINCTRL_SUN8I_A33)                += pinctrl-sun8i-a33.o
 obj-$(CONFIG_PINCTRL_SUN8I_A83T)       += pinctrl-sun8i-a83t.o
+obj-$(CONFIG_PINCTRL_SUN8I_H3)         += pinctrl-sun8i-h3.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-sun8i-h3.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-h3.c
new file mode 100644 (file)
index 0000000..77d4cf0
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+ * Allwinner H3 SoCs pinctrl driver.
+ *
+ * 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_h3_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(0x3, "pwm1"),
+                 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_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_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, "nand"),          /* 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, "nand"),          /* 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, "nand"),          /* 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_PIN(SUNXI_PINCTRL_PIN(D, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac")),         /* RXD2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac")),         /* RXD1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac")),         /* RXD0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac")),         /* RXCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac")),         /* RXCTL/RXDV */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac")),         /* RXERR */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac")),         /* TXD3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 8),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac")),         /* TXD2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 9),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac")),         /* TXD1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac")),         /* TXD0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac")),         /* CRS */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac")),         /* TXCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac")),         /* TXCTL/TXEN */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac")),         /* TXERR */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac")),         /* CLKIN/COL */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac")),         /* MDC */
+       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, "ts")),           /* 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, "ts")),           /* 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, "ts")),           /* 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, "ts")),           /* 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, "ts")),           /* 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, "ts")),           /* 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, "ts")),           /* 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, "ts")),           /* D3 */
+       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")),           /* D4 */
+       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")),           /* D5 */
+       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")),           /* D6 */
+       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_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_PIN(SUNXI_PINCTRL_PIN(E, 15),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out")),
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D1 */
+                 SUNXI_FUNCTION(0x3, "jtag")),         /* 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 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart1"),         /* TX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 6)),  /* 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 13)), /* PG_EINT13 */
+};
+
+static const struct sunxi_pinctrl_desc sun8i_h3_pinctrl_data = {
+       .pins = sun8i_h3_pins,
+       .npins = ARRAY_SIZE(sun8i_h3_pins),
+       .irq_banks = 2,
+};
+
+static int sun8i_h3_pinctrl_probe(struct platform_device *pdev)
+{
+       return sunxi_pinctrl_init(pdev,
+                                 &sun8i_h3_pinctrl_data);
+}
+
+static const struct of_device_id sun8i_h3_pinctrl_match[] = {
+       { .compatible = "allwinner,sun8i-h3-pinctrl", },
+       {}
+};
+
+static struct platform_driver sun8i_h3_pinctrl_driver = {
+       .probe  = sun8i_h3_pinctrl_probe,
+       .driver = {
+               .name           = "sun8i-h3-pinctrl",
+               .of_match_table = sun8i_h3_pinctrl_match,
+       },
+};
+builtin_platform_driver(sun8i_h3_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun9i-a80-r.c b/drivers/pinctrl/sunxi/pinctrl-sun9i-a80-r.c
new file mode 100644 (file)
index 0000000..42547ff
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Allwinner A80 SoCs special pins 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/reset.h>
+
+#include "pinctrl-sunxi.h"
+
+static const struct sunxi_desc_pin sun9i_a80_r_pins[] = {
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "s_uart"),        /* TX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)),  /* PL_EINT0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "s_uart"),        /* RX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)),  /* PL_EINT1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "s_jtag"),        /* TMS */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)),  /* PL_EINT2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "s_jtag"),        /* TCK */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)),  /* PL_EINT3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "s_jtag"),        /* TDO */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)),  /* PL_EINT4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "s_jtag"),        /* TDI */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)),  /* PL_EINT5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "s_cir_rx"),
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)),  /* PL_EINT6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 7),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "1wire"),
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)),  /* PL_EINT7 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 8),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "s_ps2"),         /* SCK1 */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)),  /* PL_EINT8 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 9),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "s_ps2"),         /* SDA1 */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)),  /* PL_EINT9 */
+
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 0)),  /* PM_EINT0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 1)),  /* PM_EINT1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 2)),  /* PM_EINT2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 3)),  /* PM_EINT3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "s_i2s1"),        /* LRCKR */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 4)),  /* PM_EINT4 */
+
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 8),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "s_i2c1"),        /* SCK */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 8)),  /* PM_EINT8 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 9),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "s_i2c1"),        /* SDA */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 9)),  /* PM_EINT9 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 10),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "s_i2s0"),        /* MCLK */
+                 SUNXI_FUNCTION(0x3, "s_i2s1")),       /* MCLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 11),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "s_i2s0"),        /* BCLK */
+                 SUNXI_FUNCTION(0x3, "s_i2s1")),       /* BCLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 12),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "s_i2s0"),        /* LRCK */
+                 SUNXI_FUNCTION(0x3, "s_i2s1")),       /* LRCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 13),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "s_i2s0"),        /* DIN */
+                 SUNXI_FUNCTION(0x3, "s_i2s1")),       /* DIN */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 14),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "s_i2s0"),        /* DOUT */
+                 SUNXI_FUNCTION(0x3, "s_i2s1")),       /* DOUT */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 15),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 15)), /* PM_EINT15 */
+
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(N, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "s_i2c0"),        /* SCK */
+                 SUNXI_FUNCTION(0x3, "s_rsb")),        /* SCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(N, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "s_i2c0"),        /* SDA */
+                 SUNXI_FUNCTION(0x3, "s_rsb")),        /* SDA */
+};
+
+static const struct sunxi_pinctrl_desc sun9i_a80_r_pinctrl_data = {
+       .pins = sun9i_a80_r_pins,
+       .npins = ARRAY_SIZE(sun9i_a80_r_pins),
+       .pin_base = PL_BASE,
+       .irq_banks = 2,
+};
+
+static int sun9i_a80_r_pinctrl_probe(struct platform_device *pdev)
+{
+       return sunxi_pinctrl_init(pdev,
+                                 &sun9i_a80_r_pinctrl_data);
+}
+
+static const struct of_device_id sun9i_a80_r_pinctrl_match[] = {
+       { .compatible = "allwinner,sun9i-a80-r-pinctrl", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, sun9i_a80_r_pinctrl_match);
+
+static struct platform_driver sun9i_a80_r_pinctrl_driver = {
+       .probe  = sun9i_a80_r_pinctrl_probe,
+       .driver = {
+               .name           = "sun9i-a80-r-pinctrl",
+               .owner          = THIS_MODULE,
+               .of_match_table = sun9i_a80_r_pinctrl_match,
+       },
+};
+module_platform_driver(sun9i_a80_r_pinctrl_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
+MODULE_DESCRIPTION("Allwinner A80 R_PIO pinctrl driver");
+MODULE_LICENSE("GPL");
index ad907072e09fe191e92096e6fd3de6e88f0993e2..7abd614dc38361a1dbbd081c12121f4558493f99 100644 (file)
@@ -1,32 +1,35 @@
-if ARCH_UNIPHIER
-
-config PINCTRL_UNIPHIER
-       bool
+menuconfig PINCTRL_UNIPHIER
+       bool "UniPhier SoC pinctrl drivers"
+       depends on ARCH_UNIPHIER
+       depends on OF && MFD_SYSCON
+       default y
        select PINMUX
        select GENERIC_PINCONF
 
+if PINCTRL_UNIPHIER
+
 config PINCTRL_UNIPHIER_PH1_LD4
        tristate "UniPhier PH1-LD4 SoC pinctrl driver"
-       select PINCTRL_UNIPHIER
+       default y
 
 config PINCTRL_UNIPHIER_PH1_PRO4
        tristate "UniPhier PH1-Pro4 SoC pinctrl driver"
-       select PINCTRL_UNIPHIER
+       default y
 
 config PINCTRL_UNIPHIER_PH1_SLD8
        tristate "UniPhier PH1-sLD8 SoC pinctrl driver"
-       select PINCTRL_UNIPHIER
+       default y
 
 config PINCTRL_UNIPHIER_PH1_PRO5
        tristate "UniPhier PH1-Pro5 SoC pinctrl driver"
-       select PINCTRL_UNIPHIER
+       default y
 
 config PINCTRL_UNIPHIER_PROXSTREAM2
        tristate "UniPhier ProXstream2 SoC pinctrl driver"
-       select PINCTRL_UNIPHIER
+       default y
 
 config PINCTRL_UNIPHIER_PH1_LD6B
        tristate "UniPhier PH1-LD6b SoC pinctrl driver"
-       select PINCTRL_UNIPHIER
+       default y
 
 endif
index 7bc6df3100efa8e507641172491b9d0039b9d6dd..6804354c42bd29214463fc62d87fe13c3f92e775 100644 (file)
@@ -40,10 +40,14 @@ struct read_info_sccb {
        u8      fac85;                  /* 85 */
        u8      _pad_86[91 - 86];       /* 86-90 */
        u8      flags;                  /* 91 */
-       u8      _pad_92[100 - 92];      /* 92-99 */
+       u8      _pad_92[99 - 92];       /* 92-98 */
+       u8      hamaxpow;               /* 99 */
        u32     rnsize2;                /* 100-103 */
        u64     rnmax2;                 /* 104-111 */
-       u8      _pad_112[120 - 112];    /* 112-119 */
+       u8      _pad_112[116 - 112];    /* 112-115 */
+       u8      fac116;                 /* 116 */
+       u8      _pad_117[119 - 117];    /* 117-118 */
+       u8      fac119;                 /* 119 */
        u16     hcpua;                  /* 120-121 */
        u8      _pad_122[4096 - 122];   /* 122-4095 */
 } __packed __aligned(PAGE_SIZE);
@@ -108,6 +112,8 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
        sclp.facilities = sccb->facilities;
        sclp.has_sprp = !!(sccb->fac84 & 0x02);
        sclp.has_core_type = !!(sccb->fac84 & 0x01);
+       sclp.has_esca = !!(sccb->fac116 & 0x08);
+       sclp.has_hvs = !!(sccb->fac119 & 0x80);
        if (sccb->fac85 & 0x02)
                S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP;
        sclp.rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
@@ -115,6 +121,11 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
        sclp.rzm <<= 20;
        sclp.ibc = sccb->ibc;
 
+       if (sccb->hamaxpow && sccb->hamaxpow < 64)
+               sclp.hamax = (1UL << sccb->hamaxpow) - 1;
+       else
+               sclp.hamax = U64_MAX;
+
        if (!sccb->hcpua) {
                if (MACHINE_IS_VM)
                        sclp.max_cores = 64;
@@ -131,6 +142,7 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
                        continue;
                sclp.has_siif = cpue->siif;
                sclp.has_sigpif = cpue->sigpif;
+               sclp.has_sief2 = cpue->sief2;
                break;
        }
 
index 3d22fc3e3c1a7ba6df90665f59cf10e8d38ef715..4e08d1cd704d1c261c82a98067649154f433ecd1 100644 (file)
@@ -2885,10 +2885,13 @@ static int sd_revalidate_disk(struct gendisk *disk)
 
        /*
         * Use the device's preferred I/O size for reads and writes
-        * unless the reported value is unreasonably large (or garbage).
+        * unless the reported value is unreasonably small, large, or
+        * garbage.
         */
-       if (sdkp->opt_xfer_blocks && sdkp->opt_xfer_blocks <= dev_max &&
-           sdkp->opt_xfer_blocks <= SD_DEF_XFER_BLOCKS)
+       if (sdkp->opt_xfer_blocks &&
+           sdkp->opt_xfer_blocks <= dev_max &&
+           sdkp->opt_xfer_blocks <= SD_DEF_XFER_BLOCKS &&
+           sdkp->opt_xfer_blocks * sdp->sector_size >= PAGE_CACHE_SIZE)
                rw_max = q->limits.io_opt =
                        logical_to_sectors(sdp, sdkp->opt_xfer_blocks);
        else
index b04b05a0904eec086c49250c3dc4e27cb84a3927..0ad66fa9bb1aa47c97a7a5c1cae80f7bbc945473 100644 (file)
@@ -116,7 +116,7 @@ static const struct spm_reg_data spm_reg_8064_cpu = {
 
 static DEFINE_PER_CPU(struct spm_driver_data *, cpu_spm_drv);
 
-typedef int (*idle_fn)(int);
+typedef int (*idle_fn)(void);
 static DEFINE_PER_CPU(idle_fn*, qcom_idle_ops);
 
 static inline void spm_register_write(struct spm_driver_data *drv,
@@ -179,10 +179,10 @@ static int qcom_pm_collapse(unsigned long int unused)
        return -1;
 }
 
-static int qcom_cpu_spc(int cpu)
+static int qcom_cpu_spc(void)
 {
        int ret;
-       struct spm_driver_data *drv = per_cpu(cpu_spm_drv, cpu);
+       struct spm_driver_data *drv = __this_cpu_read(cpu_spm_drv);
 
        spm_set_low_power_mode(drv, PM_SLEEP_MODE_SPC);
        ret = cpu_suspend(0, qcom_pm_collapse);
@@ -197,9 +197,9 @@ static int qcom_cpu_spc(int cpu)
        return ret;
 }
 
-static int qcom_idle_enter(int cpu, unsigned long index)
+static int qcom_idle_enter(unsigned long index)
 {
-       return per_cpu(qcom_idle_ops, cpu)[index](cpu);
+       return __this_cpu_read(qcom_idle_ops)[index]();
 }
 
 static const struct of_device_id qcom_idle_state_match[] __initconst = {
index 69b203651905e93f77149754a5b9d6a021b6bf32..e489a3271f0697fe8a9f35708434412072a3f2a1 100644 (file)
@@ -118,12 +118,20 @@ failed:
        return rc;
 }
 
-static const char *ll_follow_link(struct dentry *dentry, void **cookie)
+static void ll_put_link(void *p)
+{
+       ptlrpc_req_finished(p);
+}
+
+static const char *ll_get_link(struct dentry *dentry,
+                              struct inode *inode,
+                              struct delayed_call *done)
 {
-       struct inode *inode = d_inode(dentry);
        struct ptlrpc_request *request = NULL;
        int rc;
        char *symname = NULL;
+       if (!dentry)
+               return ERR_PTR(-ECHILD);
 
        CDEBUG(D_VFSTRACE, "VFS Op\n");
        ll_inode_size_lock(inode);
@@ -135,22 +143,16 @@ static const char *ll_follow_link(struct dentry *dentry, void **cookie)
        }
 
        /* symname may contain a pointer to the request message buffer,
-        * we delay request releasing until ll_put_link then.
+        * we delay request releasing then.
         */
-       *cookie = request;
+       set_delayed_call(done, ll_put_link, request);
        return symname;
 }
 
-static void ll_put_link(struct inode *unused, void *cookie)
-{
-       ptlrpc_req_finished(cookie);
-}
-
 struct inode_operations ll_fast_symlink_inode_operations = {
        .readlink       = generic_readlink,
        .setattr        = ll_setattr,
-       .follow_link    = ll_follow_link,
-       .put_link       = ll_put_link,
+       .get_link       = ll_get_link,
        .getattr        = ll_getattr,
        .permission     = ll_inode_permission,
        .setxattr       = ll_setxattr,
index 4b7eb33f7d0172d8f8c716c309e98b7fdce19b1a..660b8ac37ae0c62fa2f66a38f2c0733774382144 100644 (file)
 static
 int get_xattr_type(const char *name)
 {
-       if (!strcmp(name, POSIX_ACL_XATTR_ACCESS))
+       if (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS))
                return XATTR_ACL_ACCESS_T;
 
-       if (!strcmp(name, POSIX_ACL_XATTR_DEFAULT))
+       if (!strcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT))
                return XATTR_ACL_DEFAULT_T;
 
        if (!strncmp(name, XATTR_USER_PREFIX,
index b10d6016b9939b6b0779dc385adaabb25a598bbc..93bffbac8fc7ef22d4eee7227e270c040143cb07 100644 (file)
@@ -1000,8 +1000,8 @@ static int bcm2048_set_fm_search_tune_mode(struct bcm2048_device *bdev,
                timeout = BCM2048_AUTO_SEARCH_TIMEOUT;
 
        if (!wait_for_completion_timeout(&bdev->compl,
-                       msecs_to_jiffies(timeout)))
-                       dev_err(&bdev->client->dev, "IRQ timeout.\n");
+               msecs_to_jiffies(timeout)))
+               dev_err(&bdev->client->dev, "IRQ timeout.\n");
 
        if (value)
                if (!bdev->scan_state)
index 4de2f082491d8a007cac94b17f2fb55096b9c371..f40a06954a92eaecbadf27014ba35d6e81c185b4 100644 (file)
@@ -2,6 +2,8 @@ config VIDEO_DM365_VPFE
        tristate "DM365 VPFE Media Controller Capture Driver"
        depends on VIDEO_V4L2 && ARCH_DAVINCI_DM365 && !VIDEO_DM365_ISIF
        depends on HAS_DMA
+       depends on VIDEO_V4L2_SUBDEV_API
+       depends on VIDEO_DAVINCI_VPBE_DISPLAY
        select VIDEOBUF2_DMA_CONTIG
        help
          Support for DM365 VPFE based Media Controller Capture driver.
index b1dfa2ccc4ef3ad61a68139ceaa1e1e4db826027..c492914768eaa5acb186cab362d48fa2dd872ae9 100644 (file)
@@ -1536,8 +1536,9 @@ ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
  * @fse: pointer to v4l2_subdev_frame_size_enum structure.
  */
 static int
-ipipe_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
-                         struct v4l2_subdev_frame_size_enum *fse)
+ipipe_enum_frame_size(struct v4l2_subdev *sd,
+                      struct v4l2_subdev_pad_config *cfg,
+                      struct v4l2_subdev_frame_size_enum *fse)
 {
        struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt format;
index 2a3a56b88de19e866f9db6035c28d53427f4004a..b1d5e23ae6e086cc1cab1e81991d19bf42b15e23 100644 (file)
@@ -254,7 +254,7 @@ int config_ipipe_hw(struct vpfe_ipipe_device *ipipe)
        void __iomem *ipipe_base = ipipe->base_addr;
        struct v4l2_mbus_framefmt *outformat;
        u32 color_pat;
-       u32 ipipe_mode;
+       int ipipe_mode;
        u32 data_path;
 
        /* enable clock to IPIPE */
index acb293ed9c91c74ae1ebadd56a7f5a059dacabe6..d892fee3f52fd12137b0547245bf3f6e0117193e 100644 (file)
@@ -63,16 +63,11 @@ resizer_calculate_line_length(u32 pix, int width, int height,
        if (pix == MEDIA_BUS_FMT_UYVY8_2X8 ||
            pix == MEDIA_BUS_FMT_SGRBG12_1X12) {
                *line_len = width << 1;
-       } else if (pix == MEDIA_BUS_FMT_Y8_1X8 ||
-                  pix == MEDIA_BUS_FMT_UV8_1X8) {
-               *line_len = width;
-               *line_len_c = width;
        } else {
-               /* YUV 420 */
-               /* round width to upper 32 byte boundary */
                *line_len = width;
                *line_len_c = width;
        }
+
        /* adjust the line len to be a multiple of 32 */
        *line_len += 31;
        *line_len &= ~0x1f;
index 01df0683e950734ca66fbc1b3fb7289acfea1a58..69b678ca40c06a3a13c435aba2876b714ae642de 100644 (file)
@@ -227,7 +227,7 @@ static int vpfe_enable_clock(struct vpfe_device *vpfe_dev)
                return 0;
 
        vpfe_dev->clks = kcalloc(vpfe_cfg->num_clocks,
-                                sizeof(struct clock *), GFP_KERNEL);
+                                sizeof(*vpfe_dev->clks), GFP_KERNEL);
        if (vpfe_dev->clks == NULL)
                return -ENOMEM;
 
index 0fdff91624fd6d649857f1b71e4fb70ad7382d48..adb2bc8811aba9ae96280db18e560db0a9eec759 100644 (file)
@@ -470,7 +470,7 @@ void vpfe_video_process_buffer_complete(struct vpfe_video_device *video)
 {
        struct vpfe_pipeline *pipe = &video->pipe;
 
-       v4l2_get_timestamp(&video->cur_frm->vb.timestamp);
+       video->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns();
        vb2_buffer_done(&video->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE);
        if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS)
                video->cur_frm = video->next_frm;
@@ -1078,7 +1078,7 @@ vpfe_g_dv_timings(struct file *file, void *fh,
  * the buffer nbuffers and buffer size
  */
 static int
-vpfe_buffer_queue_setup(struct vb2_queue *vq, const void *parg,
+vpfe_buffer_queue_setup(struct vb2_queue *vq,
                        unsigned int *nbuffers, unsigned int *nplanes,
                        unsigned int sizes[], void *alloc_ctxs[])
 {
index 534b8103ae808eafd98eca40612b871e6dd832d7..ff1926ca1f96f538219478a1a17ba215e81f9ef7 100644 (file)
@@ -885,12 +885,14 @@ static int imon_probe(struct usb_interface *interface,
                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:
index c1408342b1d0ebe35e35d5996a49ddec9f3c2828..d009bcb439f0677c977d0af1bc3315797c2bf9fa 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
-#include <linux/time.h>
+#include <linux/ktime.h>
 #include <linux/mm.h>
 #include <linux/delay.h>
 
@@ -144,25 +144,22 @@ static void lirc_off(void)
 
 static unsigned int init_lirc_timer(void)
 {
-       struct timeval tv, now;
+       ktime_t kt, now, timeout;
        unsigned int level, newlevel, timeelapsed, newtimer;
        int count = 0;
 
-       do_gettimeofday(&tv);
-       tv.tv_sec++;                     /* wait max. 1 sec. */
+       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;
-               do_gettimeofday(&now);
-       } while (count < 1000 && (now.tv_sec < tv.tv_sec
-                            || (now.tv_sec == tv.tv_sec
-                                && now.tv_usec < tv.tv_usec)));
-
-       timeelapsed = (now.tv_sec + 1 - tv.tv_sec)*1000000
-                    + (now.tv_usec - tv.tv_usec);
+               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 */
@@ -220,8 +217,8 @@ static void rbuf_write(int signal)
 
 static void lirc_lirc_irq_handler(void *blah)
 {
-       struct timeval tv;
-       static struct timeval lasttv;
+       ktime_t kt, delkt;
+       static ktime_t lastkt;
        static int init;
        long signal;
        int data;
@@ -244,16 +241,14 @@ static void lirc_lirc_irq_handler(void *blah)
 
 #ifdef LIRC_TIMER
        if (init) {
-               do_gettimeofday(&tv);
+               kt = ktime_get();
 
-               signal = tv.tv_sec - lasttv.tv_sec;
-               if (signal > 15)
+               delkt = ktime_sub(kt, lastkt);
+               if (ktime_compare(delkt, ktime_set(15, 0)) > 0)
                        /* really long time */
                        data = PULSE_MASK;
                else
-                       data = (int) (signal*1000000 +
-                                        tv.tv_usec - lasttv.tv_usec +
-                                        LIRC_SFH506_DELAY);
+                       data = (int)(ktime_to_us(delkt) + LIRC_SFH506_DELAY);
 
                rbuf_write(data); /* space */
        } else {
@@ -301,7 +296,7 @@ static void lirc_lirc_irq_handler(void *blah)
                        data = 1;
                rbuf_write(PULSE_BIT|data); /* pulse */
        }
-       do_gettimeofday(&lasttv);
+       lastkt = ktime_get();
 #else
        /* add your code here */
 #endif
index f2dca69c2bc0ed3ea8704e9d9df68ba4d04fc980..2218d0042030ed29ba95376c8d1dd310f1ce2437 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 #include <linux/usb.h>
+#include <linux/ktime.h>
 
 #include <media/lirc.h>
 #include <media/lirc_dev.h>
@@ -111,7 +112,7 @@ struct sasem_context {
        } tx;
 
        /* for dealing with repeat codes (wish there was a toggle bit!) */
-       struct timeval presstime;
+       ktime_t presstime;
        char lastcode[8];
        int codesaved;
 };
@@ -566,8 +567,8 @@ static void incoming_packet(struct sasem_context *context,
 {
        int len = urb->actual_length;
        unsigned char *buf = urb->transfer_buffer;
-       long ms;
-       struct timeval tv;
+       u64 ns;
+       ktime_t kt;
 
        if (len != 8) {
                dev_warn(&context->dev->dev,
@@ -584,9 +585,8 @@ static void incoming_packet(struct sasem_context *context,
         */
 
        /* get the time since the last button press */
-       do_gettimeofday(&tv);
-       ms = (tv.tv_sec - context->presstime.tv_sec) * 1000 +
-            (tv.tv_usec - context->presstime.tv_usec) / 1000;
+       kt = ktime_get();
+       ns = ktime_to_ns(ktime_sub(kt, context->presstime));
 
        if (memcmp(buf, "\x08\0\0\0\0\0\0\0", 8) == 0) {
                /*
@@ -600,10 +600,9 @@ static void incoming_packet(struct sasem_context *context,
                 *   in that time and then get a false repeat of the previous
                 *   press but it is long enough for a genuine repeat
                 */
-               if ((ms < 250) && (context->codesaved != 0)) {
+               if ((ns < 250 * NSEC_PER_MSEC) && (context->codesaved != 0)) {
                        memcpy(buf, &context->lastcode, 8);
-                       context->presstime.tv_sec = tv.tv_sec;
-                       context->presstime.tv_usec = tv.tv_usec;
+                       context->presstime = kt;
                }
        } else {
                /* save the current valid code for repeats */
@@ -613,8 +612,7 @@ static void incoming_packet(struct sasem_context *context,
                 * just for safety reasons
                 */
                context->codesaved = 1;
-               context->presstime.tv_sec = tv.tv_sec;
-               context->presstime.tv_usec = tv.tv_usec;
+               context->presstime = kt;
        }
 
        lirc_buffer_write(context->driver->rbuf, buf);
index 64a7b2fc5289b6c1c0c0cabfa865756fb92208ed..b798b311d32ccbe47129e0b6626aa23ae73dade4 100644 (file)
@@ -59,7 +59,7 @@
 #include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/serial_reg.h>
-#include <linux/time.h>
+#include <linux/ktime.h>
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/wait.h>
@@ -204,7 +204,7 @@ static struct lirc_serial hardware[] = {
 
 #define RBUF_LEN 256
 
-static struct timeval lasttv = {0, 0};
+static ktime_t lastkt;
 
 static struct lirc_buffer rbuf;
 
@@ -542,10 +542,10 @@ static void frbwrite(int l)
 
 static irqreturn_t lirc_irq_handler(int i, void *blah)
 {
-       struct timeval tv;
+       ktime_t kt;
        int counter, dcd;
        u8 status;
-       long deltv;
+       ktime_t delkt;
        int data;
        static int last_dcd = -1;
 
@@ -565,7 +565,7 @@ static irqreturn_t lirc_irq_handler(int i, void *blah)
                if ((status & hardware[type].signal_pin_change)
                    && sense != -1) {
                        /* get current time */
-                       do_gettimeofday(&tv);
+                       kt = ktime_get();
 
                        /* New mode, written by Trent Piepho
                           <xyzzy@u.washington.edu>. */
@@ -594,34 +594,20 @@ static irqreturn_t lirc_irq_handler(int i, void *blah)
                        dcd = (status & hardware[type].signal_pin) ? 1 : 0;
 
                        if (dcd == last_dcd) {
-                               pr_warn("ignoring spike: %d %d %lx %lx %lx %lx\n",
-                                       dcd, sense,
-                                       tv.tv_sec, lasttv.tv_sec,
-                                       (unsigned long)tv.tv_usec,
-                                       (unsigned long)lasttv.tv_usec);
+                               pr_warn("ignoring spike: %d %d %llx %llx\n",
+                                       dcd, sense, ktime_to_us(kt),
+                                       ktime_to_us(lastkt));
                                continue;
                        }
 
-                       deltv = tv.tv_sec-lasttv.tv_sec;
-                       if (tv.tv_sec < lasttv.tv_sec ||
-                           (tv.tv_sec == lasttv.tv_sec &&
-                            tv.tv_usec < lasttv.tv_usec)) {
-                               pr_warn("AIEEEE: your clock just jumped backwards\n");
-                               pr_warn("%d %d %lx %lx %lx %lx\n",
-                                       dcd, sense,
-                                       tv.tv_sec, lasttv.tv_sec,
-                                       (unsigned long)tv.tv_usec,
-                                       (unsigned long)lasttv.tv_usec);
-                               data = PULSE_MASK;
-                       } else if (deltv > 15) {
+                       delkt = ktime_sub(kt, lastkt);
+                       if (ktime_compare(delkt, ktime_set(15, 0)) > 0) {
                                data = PULSE_MASK; /* really long time */
                                if (!(dcd^sense)) {
                                        /* sanity check */
-                                       pr_warn("AIEEEE: %d %d %lx %lx %lx %lx\n",
-                                               dcd, sense,
-                                               tv.tv_sec, lasttv.tv_sec,
-                                               (unsigned long)tv.tv_usec,
-                                               (unsigned long)lasttv.tv_usec);
+                                       pr_warn("AIEEEE: %d %d %llx %llx\n",
+                                               dcd, sense, ktime_to_us(kt),
+                                               ktime_to_us(lastkt));
                                        /*
                                         * detecting pulse while this
                                         * MUST be a space!
@@ -629,11 +615,9 @@ static irqreturn_t lirc_irq_handler(int i, void *blah)
                                        sense = sense ? 0 : 1;
                                }
                        } else
-                               data = (int) (deltv*1000000 +
-                                              tv.tv_usec -
-                                              lasttv.tv_usec);
+                               data = (int) ktime_to_us(delkt);
                        frbwrite(dcd^sense ? data : (data|PULSE_BIT));
-                       lasttv = tv;
+                       lastkt = kt;
                        last_dcd = dcd;
                        wake_up_interruptible(&rbuf.wait_poll);
                }
@@ -790,7 +774,7 @@ static int set_use_inc(void *data)
        unsigned long flags;
 
        /* initialize timestamp */
-       do_gettimeofday(&lasttv);
+       lastkt = ktime_get();
 
        spin_lock_irqsave(&hardware[type].lock, flags);
 
@@ -979,7 +963,7 @@ static int lirc_serial_resume(struct platform_device *dev)
 
        spin_lock_irqsave(&hardware[type].lock, flags);
        /* Enable Interrupt */
-       do_gettimeofday(&lasttv);
+       lastkt = ktime_get();
        soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI);
        off();
 
index 8d4e3bd1bfe1feaab40d92741062bf4a99ed5626..46183464ee79f8965323b73b525f9c9f58613310 100644 (file)
@@ -1,6 +1,6 @@
 config VIDEO_OMAP4
        tristate "OMAP 4 Camera support"
-       depends on VIDEO_V4L2=y && VIDEO_V4L2_SUBDEV_API && I2C=y && ARCH_OMAP4
+       depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && I2C && ARCH_OMAP4
        depends on HAS_DMA
        select MFD_SYSCON
        select VIDEOBUF2_DMA_CONTIG
index aa76ccda5b424f73f64776a010afcb9040ecd39f..e27a988540a6b73bb188ec52f8662f71523747c0 100644 (file)
@@ -601,8 +601,8 @@ static int iss_pipeline_disable(struct iss_pipeline *pipe,
                subdev = media_entity_to_v4l2_subdev(entity);
                ret = v4l2_subdev_call(subdev, video, s_stream, 0);
                if (ret < 0) {
-                       dev_dbg(iss->dev, "%s: module stop timeout.\n",
-                               subdev->name);
+                       dev_warn(iss->dev, "%s: module stop timeout.\n",
+                                subdev->name);
                        /* If the entity failed to stopped, assume it has
                         * crashed. Mark it as such, the ISS will be reset when
                         * applications will release it.
index 35df8b4709e6089d44f15d81fa989e9a4a6840cc..5929357fe68794b765dd64800bc650969168dfe6 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/platform_device.h>
 #include <linux/wait.h>
 
-#include <media/omap4iss.h>
+#include <linux/platform_data/media/omap4iss.h>
 
 #include "iss_regs.h"
 #include "iss_csiphy.h"
index c6e6d47ac57f371695d7b02cac96ee9e42cce9ad..b941035139ae8b1ff02385fc26b43fa63f3f0580 100644 (file)
@@ -674,6 +674,9 @@ static void csi2_isr_ctx(struct iss_csi2_device *csi2,
        status = iss_reg_read(csi2->iss, csi2->regs1, CSI2_CTX_IRQSTATUS(n));
        iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_IRQSTATUS(n), status);
 
+       if (omap4iss_module_sync_is_stopping(&csi2->wait, &csi2->stopping))
+               return;
+
        /* Propagate frame number */
        if (status & CSI2_CTX_IRQ_FS) {
                struct iss_pipeline *pipe =
@@ -776,9 +779,6 @@ void omap4iss_csi2_isr(struct iss_csi2_device *csi2)
                pipe->error = true;
        }
 
-       if (omap4iss_module_sync_is_stopping(&csi2->wait, &csi2->stopping))
-               return;
-
        /* Successful cases */
        if (csi2_irqstatus & CSI2_IRQ_CONTEXT0)
                csi2_isr_ctx(csi2, &csi2->contexts[0]);
index e9ca43955654f9e89b0ae8e953f06273cae66bb6..a0f2d974daeb64e5f94989cae8df4764b81c7013 100644 (file)
@@ -14,7 +14,7 @@
 #ifndef OMAP4_ISS_CSI_PHY_H
 #define OMAP4_ISS_CSI_PHY_H
 
-#include <media/omap4iss.h>
+#include <linux/platform_data/media/omap4iss.h>
 
 struct iss_csi2_device;
 
index 9c8180bba77ed142af008c846bc26866ab27497f..108961e05f539dc9cddca92ef2577acad721d44d 100644 (file)
@@ -158,8 +158,8 @@ static void resizer_set_outaddr(struct iss_resizer_device *resizer, u32 addr)
        /* Program UV buffer address... Hardcoded to be contiguous! */
        if ((informat->code == MEDIA_BUS_FMT_UYVY8_1X16) &&
            (outformat->code == MEDIA_BUS_FMT_YUYV8_1_5X8)) {
-               u32 c_addr = addr + (resizer->video_out.bpl_value *
-                                    (outformat->height - 1));
+               u32 c_addr = addr + resizer->video_out.bpl_value
+                          * outformat->height;
 
                /* Ensure Y_BAD_L[6:0] = C_BAD_L[6:0]*/
                if ((c_addr ^ addr) & 0x7f) {
index 2a0158bb497420b63f527a45b9bbada740136e37..e9aeca08986f905ffd8cb32e5a65574592440be2 100644 (file)
@@ -287,7 +287,6 @@ iss_video_check_format(struct iss_video *video, struct iss_video_fh *vfh)
  */
 
 static int iss_video_queue_setup(struct vb2_queue *vq,
-                                const void *parg,
                                 unsigned int *count, unsigned int *num_planes,
                                 unsigned int sizes[], void *alloc_ctxs[])
 {
@@ -434,7 +433,7 @@ struct iss_buffer *omap4iss_video_buffer_next(struct iss_video *video)
        list_del(&buf->list);
        spin_unlock_irqrestore(&video->qlock, flags);
 
-       v4l2_get_timestamp(&buf->vb.timestamp);
+       buf->vb.vb2_buf.timestamp = ktime_get_ns();
 
        /* Do frame number propagation only if this is the output video node.
         * Frame number either comes from the CSI receivers or it gets
index 5381a728d23e773af0e1ebe2869e01bf98757244..e5139402e7f8f8356457c62316f393d6a1e826b8 100644 (file)
@@ -133,6 +133,12 @@ static void sysrq_handle_crash(int key)
 {
        char *killer = NULL;
 
+       /* we need to release the RCU read lock here,
+        * otherwise we get an annoying
+        * 'BUG: sleeping function called from invalid context'
+        * complaint from the kernel before the panic.
+        */
+       rcu_read_unlock();
        panic_on_oops = 1;      /* force panic */
        wmb();
        *killer = 1;
index 51d4a1703af2721ef4c8079c413fe70d911b7291..912694f3d54ec807c6090336007067241b7649a4 100644 (file)
@@ -41,7 +41,7 @@
  * videobuf2 queue operations
  */
 
-static int uvc_queue_setup(struct vb2_queue *vq, const void *parg,
+static int uvc_queue_setup(struct vb2_queue *vq,
                           unsigned int *nbuffers, unsigned int *nplanes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
@@ -329,7 +329,7 @@ struct uvc_buffer *uvcg_queue_next_buffer(struct uvc_video_queue *queue,
 
        buf->buf.field = V4L2_FIELD_NONE;
        buf->buf.sequence = queue->sequence++;
-       v4l2_get_timestamp(&buf->buf.timestamp);
+       buf->buf.vb2_buf.timestamp = ktime_get_ns();
 
        vb2_set_plane_payload(&buf->buf.vb2_buf, 0, buf->bytesused);
        vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE);
index aa8a7f71f3106569b25b9959fcdedf9a8e057527..9b7a35c9e51ddd5a9d3bdb3319cfb9f1a35ff627 100644 (file)
@@ -1,6 +1,6 @@
 obj-$(CONFIG_HOTPLUG_CPU)              += cpu_hotplug.o
 obj-$(CONFIG_X86)                      += fallback.o
-obj-y  += grant-table.o features.o balloon.o manage.o preempt.o
+obj-y  += grant-table.o features.o balloon.o manage.o preempt.o time.o
 obj-y  += events/
 obj-y  += xenbus/
 
index 90307c0b630c14b10faf01eb1b764e6578cbc72e..6893c79fd2a1ae1aa3d248adb3c860085e35f7f5 100644 (file)
@@ -58,7 +58,7 @@ static int xen_acpi_notify_hypervisor_state(u8 sleep_state,
                 bits, val_a, val_b))
                return -1;
 
-       HYPERVISOR_dom0_op(&op);
+       HYPERVISOR_platform_op(&op);
        return 1;
 }
 
index f745db2701719fad20d88cf2db2a935513a73465..be7e56a338e84dba95b9e42cddc7db3d15f224a8 100644 (file)
@@ -42,7 +42,7 @@ static efi_status_t xen_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
 {
        struct xen_platform_op op = INIT_EFI_OP(get_time);
 
-       if (HYPERVISOR_dom0_op(&op) < 0)
+       if (HYPERVISOR_platform_op(&op) < 0)
                return EFI_UNSUPPORTED;
 
        if (tm) {
@@ -67,7 +67,7 @@ static efi_status_t xen_efi_set_time(efi_time_t *tm)
        BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.set_time));
        memcpy(&efi_data(op).u.set_time, tm, sizeof(*tm));
 
-       if (HYPERVISOR_dom0_op(&op) < 0)
+       if (HYPERVISOR_platform_op(&op) < 0)
                return EFI_UNSUPPORTED;
 
        return efi_data(op).status;
@@ -79,7 +79,7 @@ static efi_status_t xen_efi_get_wakeup_time(efi_bool_t *enabled,
 {
        struct xen_platform_op op = INIT_EFI_OP(get_wakeup_time);
 
-       if (HYPERVISOR_dom0_op(&op) < 0)
+       if (HYPERVISOR_platform_op(&op) < 0)
                return EFI_UNSUPPORTED;
 
        if (tm) {
@@ -108,7 +108,7 @@ static efi_status_t xen_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
        else
                efi_data(op).misc |= XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY;
 
-       if (HYPERVISOR_dom0_op(&op) < 0)
+       if (HYPERVISOR_platform_op(&op) < 0)
                return EFI_UNSUPPORTED;
 
        return efi_data(op).status;
@@ -129,7 +129,7 @@ static efi_status_t xen_efi_get_variable(efi_char16_t *name,
        efi_data(op).u.get_variable.size = *data_size;
        set_xen_guest_handle(efi_data(op).u.get_variable.data, data);
 
-       if (HYPERVISOR_dom0_op(&op) < 0)
+       if (HYPERVISOR_platform_op(&op) < 0)
                return EFI_UNSUPPORTED;
 
        *data_size = efi_data(op).u.get_variable.size;
@@ -152,7 +152,7 @@ static efi_status_t xen_efi_get_next_variable(unsigned long *name_size,
        memcpy(&efi_data(op).u.get_next_variable_name.vendor_guid, vendor,
               sizeof(*vendor));
 
-       if (HYPERVISOR_dom0_op(&op) < 0)
+       if (HYPERVISOR_platform_op(&op) < 0)
                return EFI_UNSUPPORTED;
 
        *name_size = efi_data(op).u.get_next_variable_name.size;
@@ -178,7 +178,7 @@ static efi_status_t xen_efi_set_variable(efi_char16_t *name,
        efi_data(op).u.set_variable.size = data_size;
        set_xen_guest_handle(efi_data(op).u.set_variable.data, data);
 
-       if (HYPERVISOR_dom0_op(&op) < 0)
+       if (HYPERVISOR_platform_op(&op) < 0)
                return EFI_UNSUPPORTED;
 
        return efi_data(op).status;
@@ -196,7 +196,7 @@ static efi_status_t xen_efi_query_variable_info(u32 attr,
 
        efi_data(op).u.query_variable_info.attr = attr;
 
-       if (HYPERVISOR_dom0_op(&op) < 0)
+       if (HYPERVISOR_platform_op(&op) < 0)
                return EFI_UNSUPPORTED;
 
        *storage_space = efi_data(op).u.query_variable_info.max_store_size;
@@ -210,7 +210,7 @@ static efi_status_t xen_efi_get_next_high_mono_count(u32 *count)
 {
        struct xen_platform_op op = INIT_EFI_OP(get_next_high_monotonic_count);
 
-       if (HYPERVISOR_dom0_op(&op) < 0)
+       if (HYPERVISOR_platform_op(&op) < 0)
                return EFI_UNSUPPORTED;
 
        *count = efi_data(op).misc;
@@ -232,7 +232,7 @@ static efi_status_t xen_efi_update_capsule(efi_capsule_header_t **capsules,
        efi_data(op).u.update_capsule.capsule_count = count;
        efi_data(op).u.update_capsule.sg_list = sg_list;
 
-       if (HYPERVISOR_dom0_op(&op) < 0)
+       if (HYPERVISOR_platform_op(&op) < 0)
                return EFI_UNSUPPORTED;
 
        return efi_data(op).status;
@@ -252,7 +252,7 @@ static efi_status_t xen_efi_query_capsule_caps(efi_capsule_header_t **capsules,
                                        capsules);
        efi_data(op).u.query_capsule_capabilities.capsule_count = count;
 
-       if (HYPERVISOR_dom0_op(&op) < 0)
+       if (HYPERVISOR_platform_op(&op) < 0)
                return EFI_UNSUPPORTED;
 
        *max_size = efi_data(op).u.query_capsule_capabilities.max_capsule_size;
@@ -331,7 +331,7 @@ efi_system_table_t __init *xen_efi_probe(void)
        };
        union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info;
 
-       if (!xen_initial_domain() || HYPERVISOR_dom0_op(&op) < 0)
+       if (!xen_initial_domain() || HYPERVISOR_platform_op(&op) < 0)
                return NULL;
 
        /* Here we know that Xen runs on EFI platform. */
@@ -347,7 +347,7 @@ efi_system_table_t __init *xen_efi_probe(void)
        info->vendor.bufsz = sizeof(vendor);
        set_xen_guest_handle(info->vendor.name, vendor);
 
-       if (HYPERVISOR_dom0_op(&op) == 0) {
+       if (HYPERVISOR_platform_op(&op) == 0) {
                efi_systab_xen.fw_vendor = __pa_symbol(vendor);
                efi_systab_xen.fw_revision = info->vendor.revision;
        } else
@@ -357,14 +357,14 @@ efi_system_table_t __init *xen_efi_probe(void)
        op.u.firmware_info.type = XEN_FW_EFI_INFO;
        op.u.firmware_info.index = XEN_FW_EFI_VERSION;
 
-       if (HYPERVISOR_dom0_op(&op) == 0)
+       if (HYPERVISOR_platform_op(&op) == 0)
                efi_systab_xen.hdr.revision = info->version;
 
        op.cmd = XENPF_firmware_info;
        op.u.firmware_info.type = XEN_FW_EFI_INFO;
        op.u.firmware_info.index = XEN_FW_EFI_RT_VERSION;
 
-       if (HYPERVISOR_dom0_op(&op) == 0)
+       if (HYPERVISOR_platform_op(&op) == 0)
                efi.runtime_version = info->version;
 
        return &efi_systab_xen;
index 1be5dd048622f6c8c4f9aa805514b9fd5b5c5d7b..dc495383ad7335b2022f65df051700ca180de7d3 100644 (file)
@@ -518,7 +518,7 @@ static void mn_release(struct mmu_notifier *mn,
        mutex_unlock(&priv->lock);
 }
 
-static struct mmu_notifier_ops gntdev_mmu_ops = {
+static const struct mmu_notifier_ops gntdev_mmu_ops = {
        .release                = mn_release,
        .invalidate_page        = mn_invl_page,
        .invalidate_range_start = mn_invl_range_start,
@@ -748,6 +748,206 @@ static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u)
        return rc;
 }
 
+#define GNTDEV_COPY_BATCH 24
+
+struct gntdev_copy_batch {
+       struct gnttab_copy ops[GNTDEV_COPY_BATCH];
+       struct page *pages[GNTDEV_COPY_BATCH];
+       s16 __user *status[GNTDEV_COPY_BATCH];
+       unsigned int nr_ops;
+       unsigned int nr_pages;
+};
+
+static int gntdev_get_page(struct gntdev_copy_batch *batch, void __user *virt,
+                          bool writeable, unsigned long *gfn)
+{
+       unsigned long addr = (unsigned long)virt;
+       struct page *page;
+       unsigned long xen_pfn;
+       int ret;
+
+       ret = get_user_pages_fast(addr, 1, writeable, &page);
+       if (ret < 0)
+               return ret;
+
+       batch->pages[batch->nr_pages++] = page;
+
+       xen_pfn = page_to_xen_pfn(page) + XEN_PFN_DOWN(addr & ~PAGE_MASK);
+       *gfn = pfn_to_gfn(xen_pfn);
+
+       return 0;
+}
+
+static void gntdev_put_pages(struct gntdev_copy_batch *batch)
+{
+       unsigned int i;
+
+       for (i = 0; i < batch->nr_pages; i++)
+               put_page(batch->pages[i]);
+       batch->nr_pages = 0;
+}
+
+static int gntdev_copy(struct gntdev_copy_batch *batch)
+{
+       unsigned int i;
+
+       gnttab_batch_copy(batch->ops, batch->nr_ops);
+       gntdev_put_pages(batch);
+
+       /*
+        * For each completed op, update the status if the op failed
+        * and all previous ops for the segment were successful.
+        */
+       for (i = 0; i < batch->nr_ops; i++) {
+               s16 status = batch->ops[i].status;
+               s16 old_status;
+
+               if (status == GNTST_okay)
+                       continue;
+
+               if (__get_user(old_status, batch->status[i]))
+                       return -EFAULT;
+
+               if (old_status != GNTST_okay)
+                       continue;
+
+               if (__put_user(status, batch->status[i]))
+                       return -EFAULT;
+       }
+
+       batch->nr_ops = 0;
+       return 0;
+}
+
+static int gntdev_grant_copy_seg(struct gntdev_copy_batch *batch,
+                                struct gntdev_grant_copy_segment *seg,
+                                s16 __user *status)
+{
+       uint16_t copied = 0;
+
+       /*
+        * Disallow local -> local copies since there is only space in
+        * batch->pages for one page per-op and this would be a very
+        * expensive memcpy().
+        */
+       if (!(seg->flags & (GNTCOPY_source_gref | GNTCOPY_dest_gref)))
+               return -EINVAL;
+
+       /* Can't cross page if source/dest is a grant ref. */
+       if (seg->flags & GNTCOPY_source_gref) {
+               if (seg->source.foreign.offset + seg->len > XEN_PAGE_SIZE)
+                       return -EINVAL;
+       }
+       if (seg->flags & GNTCOPY_dest_gref) {
+               if (seg->dest.foreign.offset + seg->len > XEN_PAGE_SIZE)
+                       return -EINVAL;
+       }
+
+       if (put_user(GNTST_okay, status))
+               return -EFAULT;
+
+       while (copied < seg->len) {
+               struct gnttab_copy *op;
+               void __user *virt;
+               size_t len, off;
+               unsigned long gfn;
+               int ret;
+
+               if (batch->nr_ops >= GNTDEV_COPY_BATCH) {
+                       ret = gntdev_copy(batch);
+                       if (ret < 0)
+                               return ret;
+               }
+
+               len = seg->len - copied;
+
+               op = &batch->ops[batch->nr_ops];
+               op->flags = 0;
+
+               if (seg->flags & GNTCOPY_source_gref) {
+                       op->source.u.ref = seg->source.foreign.ref;
+                       op->source.domid = seg->source.foreign.domid;
+                       op->source.offset = seg->source.foreign.offset + copied;
+                       op->flags |= GNTCOPY_source_gref;
+               } else {
+                       virt = seg->source.virt + copied;
+                       off = (unsigned long)virt & ~XEN_PAGE_MASK;
+                       len = min(len, (size_t)XEN_PAGE_SIZE - off);
+
+                       ret = gntdev_get_page(batch, virt, false, &gfn);
+                       if (ret < 0)
+                               return ret;
+
+                       op->source.u.gmfn = gfn;
+                       op->source.domid = DOMID_SELF;
+                       op->source.offset = off;
+               }
+
+               if (seg->flags & GNTCOPY_dest_gref) {
+                       op->dest.u.ref = seg->dest.foreign.ref;
+                       op->dest.domid = seg->dest.foreign.domid;
+                       op->dest.offset = seg->dest.foreign.offset + copied;
+                       op->flags |= GNTCOPY_dest_gref;
+               } else {
+                       virt = seg->dest.virt + copied;
+                       off = (unsigned long)virt & ~XEN_PAGE_MASK;
+                       len = min(len, (size_t)XEN_PAGE_SIZE - off);
+
+                       ret = gntdev_get_page(batch, virt, true, &gfn);
+                       if (ret < 0)
+                               return ret;
+
+                       op->dest.u.gmfn = gfn;
+                       op->dest.domid = DOMID_SELF;
+                       op->dest.offset = off;
+               }
+
+               op->len = len;
+               copied += len;
+
+               batch->status[batch->nr_ops] = status;
+               batch->nr_ops++;
+       }
+
+       return 0;
+}
+
+static long gntdev_ioctl_grant_copy(struct gntdev_priv *priv, void __user *u)
+{
+       struct ioctl_gntdev_grant_copy copy;
+       struct gntdev_copy_batch batch;
+       unsigned int i;
+       int ret = 0;
+
+       if (copy_from_user(&copy, u, sizeof(copy)))
+               return -EFAULT;
+
+       batch.nr_ops = 0;
+       batch.nr_pages = 0;
+
+       for (i = 0; i < copy.count; i++) {
+               struct gntdev_grant_copy_segment seg;
+
+               if (copy_from_user(&seg, &copy.segments[i], sizeof(seg))) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+
+               ret = gntdev_grant_copy_seg(&batch, &seg, &copy.segments[i].status);
+               if (ret < 0)
+                       goto out;
+
+               cond_resched();
+       }
+       if (batch.nr_ops)
+               ret = gntdev_copy(&batch);
+       return ret;
+
+  out:
+       gntdev_put_pages(&batch);
+       return ret;
+}
+
 static long gntdev_ioctl(struct file *flip,
                         unsigned int cmd, unsigned long arg)
 {
@@ -767,6 +967,9 @@ static long gntdev_ioctl(struct file *flip,
        case IOCTL_GNTDEV_SET_UNMAP_NOTIFY:
                return gntdev_ioctl_notify(priv, ptr);
 
+       case IOCTL_GNTDEV_GRANT_COPY:
+               return gntdev_ioctl_grant_copy(priv, ptr);
+
        default:
                pr_debug("priv %p, unknown cmd %x\n", priv, cmd);
                return -ENOIOCTLCMD;
index c49f79ed58c53353cbbf4dc34fa7dd5902388ea9..effbaf91791f4d5ab7a8e0b9d195901f539a7c91 100644 (file)
@@ -128,7 +128,7 @@ struct unmap_refs_callback_data {
        int result;
 };
 
-static struct gnttab_ops *gnttab_interface;
+static const struct gnttab_ops *gnttab_interface;
 
 static int grant_table_version;
 static int grefs_per_grant_frame;
@@ -1013,7 +1013,7 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
        return rc;
 }
 
-static struct gnttab_ops gnttab_v1_ops = {
+static const struct gnttab_ops gnttab_v1_ops = {
        .map_frames                     = gnttab_map_frames_v1,
        .unmap_frames                   = gnttab_unmap_frames_v1,
        .update_entry                   = gnttab_update_entry_v1,
index 49e88f2ce7a1889e43f4bf9767f4502b4909f3ed..cdc6daa7a9f66f9a534e619af244bc8843bcccef 100644 (file)
@@ -78,7 +78,7 @@ static int xen_pcpu_down(uint32_t cpu_id)
                .u.cpu_ol.cpuid         = cpu_id,
        };
 
-       return HYPERVISOR_dom0_op(&op);
+       return HYPERVISOR_platform_op(&op);
 }
 
 static int xen_pcpu_up(uint32_t cpu_id)
@@ -89,7 +89,7 @@ static int xen_pcpu_up(uint32_t cpu_id)
                .u.cpu_ol.cpuid         = cpu_id,
        };
 
-       return HYPERVISOR_dom0_op(&op);
+       return HYPERVISOR_platform_op(&op);
 }
 
 static ssize_t show_online(struct device *dev,
@@ -277,7 +277,7 @@ static int sync_pcpu(uint32_t cpu, uint32_t *max_cpu)
                .u.pcpu_info.xen_cpuid = cpu,
        };
 
-       ret = HYPERVISOR_dom0_op(&op);
+       ret = HYPERVISOR_platform_op(&op);
        if (ret)
                return ret;
 
@@ -364,7 +364,7 @@ int xen_pcpu_id(uint32_t acpi_id)
        op.cmd = XENPF_get_cpuinfo;
        while (cpu_id <= max_id) {
                op.u.pcpu_info.xen_cpuid = cpu_id;
-               if (HYPERVISOR_dom0_op(&op)) {
+               if (HYPERVISOR_platform_op(&op)) {
                        cpu_id++;
                        continue;
                }
diff --git a/drivers/xen/time.c b/drivers/xen/time.c
new file mode 100644 (file)
index 0000000..7107842
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Xen stolen ticks accounting.
+ */
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/math64.h>
+#include <linux/gfp.h>
+
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/events.h>
+#include <xen/features.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/vcpu.h>
+#include <xen/xen-ops.h>
+
+/* runstate info updated by Xen */
+static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate);
+
+/* return an consistent snapshot of 64-bit time/counter value */
+static u64 get64(const u64 *p)
+{
+       u64 ret;
+
+       if (BITS_PER_LONG < 64) {
+               u32 *p32 = (u32 *)p;
+               u32 h, l, h2;
+
+               /*
+                * Read high then low, and then make sure high is
+                * still the same; this will only loop if low wraps
+                * and carries into high.
+                * XXX some clean way to make this endian-proof?
+                */
+               do {
+                       h = READ_ONCE(p32[1]);
+                       l = READ_ONCE(p32[0]);
+                       h2 = READ_ONCE(p32[1]);
+               } while(h2 != h);
+
+               ret = (((u64)h) << 32) | l;
+       } else
+               ret = READ_ONCE(*p);
+
+       return ret;
+}
+
+/*
+ * Runstate accounting
+ */
+void xen_get_runstate_snapshot(struct vcpu_runstate_info *res)
+{
+       u64 state_time;
+       struct vcpu_runstate_info *state;
+
+       BUG_ON(preemptible());
+
+       state = this_cpu_ptr(&xen_runstate);
+
+       /*
+        * The runstate info is always updated by the hypervisor on
+        * the current CPU, so there's no need to use anything
+        * stronger than a compiler barrier when fetching it.
+        */
+       do {
+               state_time = get64(&state->state_entry_time);
+               *res = READ_ONCE(*state);
+       } while (get64(&state->state_entry_time) != state_time);
+}
+
+/* return true when a vcpu could run but has no real cpu to run on */
+bool xen_vcpu_stolen(int vcpu)
+{
+       return per_cpu(xen_runstate, vcpu).state == RUNSTATE_runnable;
+}
+
+void xen_setup_runstate_info(int cpu)
+{
+       struct vcpu_register_runstate_memory_area area;
+
+       area.addr.v = &per_cpu(xen_runstate, cpu);
+
+       if (HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area,
+                              cpu, &area))
+               BUG();
+}
+
index f4a3694295533d3111c74bd0223c5f64f2e7d327..fdc9e67b842dfd2cb54c57e70c1261494ba36528 100644 (file)
@@ -206,7 +206,7 @@ static int xen_hotadd_cpu(struct acpi_processor *pr)
        op.u.cpu_add.acpi_id = pr->acpi_id;
        op.u.cpu_add.pxm = pxm;
 
-       cpu_id = HYPERVISOR_dom0_op(&op);
+       cpu_id = HYPERVISOR_platform_op(&op);
        if (cpu_id < 0)
                pr_err(PREFIX "Failed to hotadd CPU for acpi_id %d\n",
                                pr->acpi_id);
index f83b754505f83e1f0906f7d0e4d628bf2ad16e83..23d1808fe027a45db7094bf5dd5477d776194fd1 100644 (file)
@@ -36,7 +36,7 @@ static int xen_acpi_pad_idle_cpus(unsigned int idle_nums)
        op.u.core_parking.type = XEN_CORE_PARKING_SET;
        op.u.core_parking.idle_nums = idle_nums;
 
-       return HYPERVISOR_dom0_op(&op);
+       return HYPERVISOR_platform_op(&op);
 }
 
 static int xen_acpi_pad_idle_cpus_num(void)
@@ -46,7 +46,7 @@ static int xen_acpi_pad_idle_cpus_num(void)
        op.cmd = XENPF_core_parking;
        op.u.core_parking.type = XEN_CORE_PARKING_GET;
 
-       return HYPERVISOR_dom0_op(&op)
+       return HYPERVISOR_platform_op(&op)
               ?: op.u.core_parking.idle_nums;
 }
 
index 70fa438000afa66f79b09407dd2c032446151650..076970a54f894b80366da951f220a97203466bb7 100644 (file)
@@ -116,7 +116,7 @@ static int push_cxx_to_hypervisor(struct acpi_processor *_pr)
        set_xen_guest_handle(op.u.set_pminfo.power.states, dst_cx_states);
 
        if (!no_hypercall)
-               ret = HYPERVISOR_dom0_op(&op);
+               ret = HYPERVISOR_platform_op(&op);
 
        if (!ret) {
                pr_debug("ACPI CPU%u - C-states uploaded.\n", _pr->acpi_id);
@@ -244,7 +244,7 @@ static int push_pxx_to_hypervisor(struct acpi_processor *_pr)
        }
 
        if (!no_hypercall)
-               ret = HYPERVISOR_dom0_op(&op);
+               ret = HYPERVISOR_platform_op(&op);
 
        if (!ret) {
                struct acpi_processor_performance *perf;
@@ -302,7 +302,7 @@ static unsigned int __init get_max_acpi_id(void)
        info = &op.u.pcpu_info;
        info->xen_cpuid = 0;
 
-       ret = HYPERVISOR_dom0_op(&op);
+       ret = HYPERVISOR_platform_op(&op);
        if (ret)
                return NR_CPUS;
 
@@ -310,7 +310,7 @@ static unsigned int __init get_max_acpi_id(void)
        last_cpu = op.u.pcpu_info.max_present;
        for (i = 0; i <= last_cpu; i++) {
                info->xen_cpuid = i;
-               ret = HYPERVISOR_dom0_op(&op);
+               ret = HYPERVISOR_platform_op(&op);
                if (ret)
                        continue;
                max_acpi_id = max(info->acpi_id, max_acpi_id);
index f8b12856753f0c0b0358571e55082986913733dd..a03f261b12d8956ecf83ac1dad19c9a957fe0c54 100644 (file)
@@ -31,7 +31,7 @@ static int xensyms_next_sym(struct xensyms *xs)
 
        symnum = symdata->symnum;
 
-       ret = HYPERVISOR_dom0_op(&xs->op);
+       ret = HYPERVISOR_platform_op(&xs->op);
        if (ret < 0)
                return ret;
 
@@ -50,7 +50,7 @@ static int xensyms_next_sym(struct xensyms *xs)
                set_xen_guest_handle(symdata->name, xs->name);
                symdata->symnum--; /* Rewind */
 
-               ret = HYPERVISOR_dom0_op(&xs->op);
+               ret = HYPERVISOR_platform_op(&xs->op);
                if (ret < 0)
                        return ret;
        }
index 0c4d96dee9b632a3833b0a83787b83954001e6e2..de6f22e008f1fbe428282e4e157378d9a6132fd3 100644 (file)
@@ -677,7 +677,7 @@ File: av7110/bootcode.bin
 
 Licence: GPLv2 or later
 
-ARM assembly source code available at http://www.linuxtv.org/downloads/firmware/Boot.S
+ARM assembly source code available at https://linuxtv.org/downloads/firmware/Boot.S
 
 --------------------------------------------------------------------------
 
index a7e28890f5efb4ec8729fc9de4f09e16d4fb91bd..9da967f383872dab4bc08ed149a230f5f8304f1a 100644 (file)
@@ -67,8 +67,8 @@ int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
                return 0;
        }
        /* get the default/access acl values and cache them */
-       dacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_DEFAULT);
-       pacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_ACCESS);
+       dacl = __v9fs_get_acl(fid, XATTR_NAME_POSIX_ACL_DEFAULT);
+       pacl = __v9fs_get_acl(fid, XATTR_NAME_POSIX_ACL_ACCESS);
 
        if (!IS_ERR(dacl) && !IS_ERR(pacl)) {
                set_cached_acl(inode, ACL_TYPE_DEFAULT, dacl);
@@ -133,10 +133,10 @@ static int v9fs_set_acl(struct p9_fid *fid, int type, struct posix_acl *acl)
                goto err_free_out;
        switch (type) {
        case ACL_TYPE_ACCESS:
-               name = POSIX_ACL_XATTR_ACCESS;
+               name = XATTR_NAME_POSIX_ACL_ACCESS;
                break;
        case ACL_TYPE_DEFAULT:
-               name = POSIX_ACL_XATTR_DEFAULT;
+               name = XATTR_NAME_POSIX_ACL_DEFAULT;
                break;
        default:
                BUG();
@@ -220,15 +220,12 @@ static int v9fs_xattr_get_acl(const struct xattr_handler *handler,
        struct posix_acl *acl;
        int error;
 
-       if (strcmp(name, "") != 0)
-               return -EINVAL;
-
        v9ses = v9fs_dentry2v9ses(dentry);
        /*
         * We allow set/get/list of acl when access=client is not specified
         */
        if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
-               return v9fs_xattr_get(dentry, handler->prefix, buffer, size);
+               return v9fs_xattr_get(dentry, handler->name, buffer, size);
 
        acl = v9fs_get_cached_acl(d_inode(dentry), handler->flags);
        if (IS_ERR(acl))
@@ -250,16 +247,13 @@ static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
        struct v9fs_session_info *v9ses;
        struct inode *inode = d_inode(dentry);
 
-       if (strcmp(name, "") != 0)
-               return -EINVAL;
-
        v9ses = v9fs_dentry2v9ses(dentry);
        /*
         * set the attribute on the remote. Without even looking at the
         * xattr value. We leave it to the server to validate
         */
        if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
-               return v9fs_xattr_set(dentry, handler->prefix, value, size,
+               return v9fs_xattr_set(dentry, handler->name, value, size,
                                      flags);
 
        if (S_ISLNK(inode->i_mode))
@@ -319,7 +313,7 @@ static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
        default:
                BUG();
        }
-       retval = v9fs_xattr_set(dentry, handler->prefix, value, size, flags);
+       retval = v9fs_xattr_set(dentry, handler->name, value, size, flags);
        if (!retval)
                set_cached_acl(inode, handler->flags, acl);
 err_out:
@@ -328,14 +322,14 @@ err_out:
 }
 
 const struct xattr_handler v9fs_xattr_acl_access_handler = {
-       .prefix = POSIX_ACL_XATTR_ACCESS,
+       .name   = XATTR_NAME_POSIX_ACL_ACCESS,
        .flags  = ACL_TYPE_ACCESS,
        .get    = v9fs_xattr_get_acl,
        .set    = v9fs_xattr_set_acl,
 };
 
 const struct xattr_handler v9fs_xattr_acl_default_handler = {
-       .prefix = POSIX_ACL_XATTR_DEFAULT,
+       .name   = XATTR_NAME_POSIX_ACL_DEFAULT,
        .flags  = ACL_TYPE_DEFAULT,
        .get    = v9fs_xattr_get_acl,
        .set    = v9fs_xattr_set_acl,
index 511078586fa13543c30ac887dbb4e825888efee0..c7cc7c30f0c8b9aab15816584763f9d32fec37f0 100644 (file)
@@ -1223,18 +1223,26 @@ ino_t v9fs_qid2ino(struct p9_qid *qid)
 }
 
 /**
- * v9fs_vfs_follow_link - follow a symlink path
+ * v9fs_vfs_get_link - follow a symlink path
  * @dentry: dentry for symlink
- * @cookie: place to pass the data to put_link()
+ * @inode: inode for symlink
+ * @done: delayed call for when we are done with the return value
  */
 
-static const char *v9fs_vfs_follow_link(struct dentry *dentry, void **cookie)
+static const char *v9fs_vfs_get_link(struct dentry *dentry,
+                                    struct inode *inode,
+                                    struct delayed_call *done)
 {
-       struct v9fs_session_info *v9ses = v9fs_dentry2v9ses(dentry);
-       struct p9_fid *fid = v9fs_fid_lookup(dentry);
+       struct v9fs_session_info *v9ses;
+       struct p9_fid *fid;
        struct p9_wstat *st;
        char *res;
 
+       if (!dentry)
+               return ERR_PTR(-ECHILD);
+
+       v9ses = v9fs_dentry2v9ses(dentry);
+       fid = v9fs_fid_lookup(dentry);
        p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);
 
        if (IS_ERR(fid))
@@ -1259,7 +1267,8 @@ static const char *v9fs_vfs_follow_link(struct dentry *dentry, void **cookie)
 
        p9stat_free(st);
        kfree(st);
-       return *cookie = res;
+       set_delayed_call(done, kfree_link, res);
+       return res;
 }
 
 /**
@@ -1452,8 +1461,7 @@ static const struct inode_operations v9fs_file_inode_operations = {
 
 static const struct inode_operations v9fs_symlink_inode_operations = {
        .readlink = generic_readlink,
-       .follow_link = v9fs_vfs_follow_link,
-       .put_link = kfree_put_link,
+       .get_link = v9fs_vfs_get_link,
        .getattr = v9fs_vfs_getattr,
        .setattr = v9fs_vfs_setattr,
 };
index cb899af1babc3bf42b48a6064d7f9345ae0bb4a8..a34702c998f593f60515d72fcf093cd556f5d951 100644 (file)
@@ -899,26 +899,34 @@ error:
 }
 
 /**
- * v9fs_vfs_follow_link_dotl - follow a symlink path
+ * v9fs_vfs_get_link_dotl - follow a symlink path
  * @dentry: dentry for symlink
- * @cookie: place to pass the data to put_link()
+ * @inode: inode for symlink
+ * @done: destructor for return value
  */
 
 static const char *
-v9fs_vfs_follow_link_dotl(struct dentry *dentry, void **cookie)
+v9fs_vfs_get_link_dotl(struct dentry *dentry,
+                      struct inode *inode,
+                      struct delayed_call *done)
 {
-       struct p9_fid *fid = v9fs_fid_lookup(dentry);
+       struct p9_fid *fid;
        char *target;
        int retval;
 
+       if (!dentry)
+               return ERR_PTR(-ECHILD);
+
        p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);
 
+       fid = v9fs_fid_lookup(dentry);
        if (IS_ERR(fid))
                return ERR_CAST(fid);
        retval = p9_client_readlink(fid, &target);
        if (retval)
                return ERR_PTR(retval);
-       return *cookie = target;
+       set_delayed_call(done, kfree_link, target);
+       return target;
 }
 
 int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
@@ -984,8 +992,7 @@ const struct inode_operations v9fs_file_inode_operations_dotl = {
 
 const struct inode_operations v9fs_symlink_inode_operations_dotl = {
        .readlink = generic_readlink,
-       .follow_link = v9fs_vfs_follow_link_dotl,
-       .put_link = kfree_put_link,
+       .get_link = v9fs_vfs_get_link_dotl,
        .getattr = v9fs_vfs_getattr_dotl,
        .setattr = v9fs_vfs_setattr_dotl,
        .setxattr = generic_setxattr,
index e3d026ac382eb482c9840140466b946aa554dd78..9dd9b47a6c1a1f095f15aeeff96e41638cd85a5e 100644 (file)
@@ -143,8 +143,6 @@ static int v9fs_xattr_handler_get(const struct xattr_handler *handler,
 {
        const char *full_name = xattr_full_name(handler, name);
 
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
        return v9fs_xattr_get(dentry, full_name, buffer, size);
 }
 
@@ -154,8 +152,6 @@ static int v9fs_xattr_handler_set(const struct xattr_handler *handler,
 {
        const char *full_name = xattr_full_name(handler, name);
 
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
        return v9fs_xattr_set(dentry, full_name, value, size, flags);
 }
 
index 17349500592d55b8b0a9a087809301c05995c696..0fdb0f5b2239df24b69363a7449a7a7ff360003c 100644 (file)
@@ -140,6 +140,7 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino)
                break;
        case ST_SOFTLINK:
                inode->i_mode |= S_IFLNK;
+               inode_nohighmem(inode);
                inode->i_op = &affs_symlink_inode_operations;
                inode->i_data.a_ops = &affs_symlink_aops;
                break;
index 181e05b46e7261d32ab9390daf7007b017af1e84..00d3002a6780b339cf456417b742bf5c9f991ec8 100644 (file)
@@ -344,6 +344,7 @@ affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
                return -ENOSPC;
 
        inode->i_op = &affs_symlink_inode_operations;
+       inode_nohighmem(inode);
        inode->i_data.a_ops = &affs_symlink_aops;
        inode->i_mode = S_IFLNK | 0777;
        mode_to_prot(inode);
index ea5b69a18ba9ce9165d8ea083bfffbb40e13a600..69b03dbb792f7a080abc70f5d45ff4bf50d458b9 100644 (file)
@@ -14,13 +14,13 @@ static int affs_symlink_readpage(struct file *file, struct page *page)
 {
        struct buffer_head *bh;
        struct inode *inode = page->mapping->host;
-       char *link = kmap(page);
+       char *link = page_address(page);
        struct slink_front *lf;
        int                      i, j;
        char                     c;
        char                     lc;
 
-       pr_debug("follow_link(ino=%lu)\n", inode->i_ino);
+       pr_debug("get_link(ino=%lu)\n", inode->i_ino);
 
        bh = affs_bread(inode->i_sb, inode->i_ino);
        if (!bh)
@@ -57,12 +57,10 @@ static int affs_symlink_readpage(struct file *file, struct page *page)
        link[i] = '\0';
        affs_brelse(bh);
        SetPageUptodate(page);
-       kunmap(page);
        unlock_page(page);
        return 0;
 fail:
        SetPageError(page);
-       kunmap(page);
        unlock_page(page);
        return -EIO;
 }
@@ -73,7 +71,6 @@ const struct address_space_operations affs_symlink_aops = {
 
 const struct inode_operations affs_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = page_follow_link_light,
-       .put_link       = page_put_link,
+       .get_link       = page_get_link,
        .setattr        = affs_notify_change,
 };
index e06f5a23352ac65415f8bcb54450af2620588e95..86cc7264c21cda727a3bb71e73af9a7ddc35eec5 100644 (file)
@@ -56,6 +56,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
        case AFS_FTYPE_SYMLINK:
                inode->i_mode   = S_IFLNK | vnode->status.mode;
                inode->i_op     = &page_symlink_inode_operations;
+               inode_nohighmem(inode);
                break;
        default:
                printk("kAFS: AFS vnode with undefined type\n");
index da0c33481bc0387788bcf4ce1792b38e141804e4..84e037d1d129336a7d052ad2881db238785bd350 100644 (file)
 
 #include "autofs_i.h"
 
-static const char *autofs4_follow_link(struct dentry *dentry, void **cookie)
+static const char *autofs4_get_link(struct dentry *dentry,
+                                   struct inode *inode,
+                                   struct delayed_call *done)
 {
-       struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
-       struct autofs_info *ino = autofs4_dentry_ino(dentry);
+       struct autofs_sb_info *sbi;
+       struct autofs_info *ino;
+       if (!dentry)
+               return ERR_PTR(-ECHILD);
+       sbi = autofs4_sbi(dentry->d_sb);
+       ino = autofs4_dentry_ino(dentry);
        if (ino && !autofs4_oz_mode(sbi))
                ino->last_used = jiffies;
        return d_inode(dentry)->i_private;
@@ -23,5 +29,5 @@ static const char *autofs4_follow_link(struct dentry *dentry, void **cookie)
 
 const struct inode_operations autofs4_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = autofs4_follow_link
+       .get_link       = autofs4_get_link
 };
index 46aedacfa6a8d4131563a83a8402daf89d590ddb..25250fa87086316a95d8877935d810cd8d305196 100644 (file)
@@ -42,7 +42,7 @@ static struct inode *befs_iget(struct super_block *, unsigned long);
 static struct inode *befs_alloc_inode(struct super_block *sb);
 static void befs_destroy_inode(struct inode *inode);
 static void befs_destroy_inodecache(void);
-static const char *befs_follow_link(struct dentry *, void **);
+static int befs_symlink_readpage(struct file *, struct page *);
 static int befs_utf2nls(struct super_block *sb, const char *in, int in_len,
                        char **out, int *out_len);
 static int befs_nls2utf(struct super_block *sb, const char *in, int in_len,
@@ -79,10 +79,8 @@ static const struct address_space_operations befs_aops = {
        .bmap           = befs_bmap,
 };
 
-static const struct inode_operations befs_symlink_inode_operations = {
-       .readlink       = generic_readlink,
-       .follow_link    = befs_follow_link,
-       .put_link       = kfree_put_link,
+static const struct address_space_operations befs_symlink_aops = {
+       .readpage       = befs_symlink_readpage,
 };
 
 /* 
@@ -398,7 +396,9 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino)
                inode->i_fop = &befs_dir_operations;
        } else if (S_ISLNK(inode->i_mode)) {
                if (befs_ino->i_flags & BEFS_LONG_SYMLINK) {
-                       inode->i_op = &befs_symlink_inode_operations;
+                       inode->i_op = &page_symlink_inode_operations;
+                       inode_nohighmem(inode);
+                       inode->i_mapping->a_ops = &befs_symlink_aops;
                } else {
                        inode->i_link = befs_ino->i_data.symlink;
                        inode->i_op = &simple_symlink_inode_operations;
@@ -463,31 +463,33 @@ befs_destroy_inodecache(void)
  * The data stream become link name. Unless the LONG_SYMLINK
  * flag is set.
  */
-static const char *
-befs_follow_link(struct dentry *dentry, void **cookie)
+static int befs_symlink_readpage(struct file *unused, struct page *page)
 {
-       struct super_block *sb = dentry->d_sb;
-       struct befs_inode_info *befs_ino = BEFS_I(d_inode(dentry));
+       struct inode *inode = page->mapping->host;
+       struct super_block *sb = inode->i_sb;
+       struct befs_inode_info *befs_ino = BEFS_I(inode);
        befs_data_stream *data = &befs_ino->i_data.ds;
        befs_off_t len = data->size;
-       char *link;
+       char *link = page_address(page);
 
-       if (len == 0) {
+       if (len == 0 || len > PAGE_SIZE) {
                befs_error(sb, "Long symlink with illegal length");
-               return ERR_PTR(-EIO);
+               goto fail;
        }
        befs_debug(sb, "Follow long symlink");
 
-       link = kmalloc(len, GFP_NOFS);
-       if (!link)
-               return ERR_PTR(-ENOMEM);
        if (befs_read_lsymlink(sb, data, link, len) != len) {
-               kfree(link);
                befs_error(sb, "Failed to read entire long symlink");
-               return ERR_PTR(-EIO);
+               goto fail;
        }
        link[len - 1] = '\0';
-       return *cookie = link;
+       SetPageUptodate(page);
+       unlock_page(page);
+       return 0;
+fail:
+       SetPageError(page);
+       unlock_page(page);
+       return -EIO;
 }
 
 /*
index 9a0124a95851014c9000ed7822dc5fad0a2f6995..f89db0c21b51edaadda1d1544425010d89e92ae2 100644 (file)
@@ -37,10 +37,10 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
 
        switch (type) {
        case ACL_TYPE_ACCESS:
-               name = POSIX_ACL_XATTR_ACCESS;
+               name = XATTR_NAME_POSIX_ACL_ACCESS;
                break;
        case ACL_TYPE_DEFAULT:
-               name = POSIX_ACL_XATTR_DEFAULT;
+               name = XATTR_NAME_POSIX_ACL_DEFAULT;
                break;
        default:
                BUG();
@@ -81,7 +81,7 @@ static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
 
        switch (type) {
        case ACL_TYPE_ACCESS:
-               name = POSIX_ACL_XATTR_ACCESS;
+               name = XATTR_NAME_POSIX_ACL_ACCESS;
                if (acl) {
                        ret = posix_acl_equiv_mode(acl, &inode->i_mode);
                        if (ret < 0)
@@ -94,7 +94,7 @@ static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
        case ACL_TYPE_DEFAULT:
                if (!S_ISDIR(inode->i_mode))
                        return acl ? -EINVAL : 0;
-               name = POSIX_ACL_XATTR_DEFAULT;
+               name = XATTR_NAME_POSIX_ACL_DEFAULT;
                break;
        default:
                return -EINVAL;
index 974be09e7556ca3f342cac89357364f4ce3cc016..42a378a4eefb4cd198c0d328eecaec293735f3af 100644 (file)
@@ -923,7 +923,7 @@ static int check_async_write(struct inode *inode, unsigned long bio_flags)
        if (bio_flags & EXTENT_BIO_TREE_LOG)
                return 0;
 #ifdef CONFIG_X86
-       if (cpu_has_xmm4_2)
+       if (static_cpu_has_safe(X86_FEATURE_XMM4_2))
                return 0;
 #endif
        return 1;
index a70c5790f8f5908f08f606d097fe33e6966af36b..3b8856e182ae7b7ee0d6ee4c32454cfc9bffdc3a 100644 (file)
@@ -3550,10 +3550,10 @@ static noinline int acls_after_inode_item(struct extent_buffer *leaf,
        int scanned = 0;
 
        if (!xattr_access) {
-               xattr_access = btrfs_name_hash(POSIX_ACL_XATTR_ACCESS,
-                                       strlen(POSIX_ACL_XATTR_ACCESS));
-               xattr_default = btrfs_name_hash(POSIX_ACL_XATTR_DEFAULT,
-                                       strlen(POSIX_ACL_XATTR_DEFAULT));
+               xattr_access = btrfs_name_hash(XATTR_NAME_POSIX_ACL_ACCESS,
+                                       strlen(XATTR_NAME_POSIX_ACL_ACCESS));
+               xattr_default = btrfs_name_hash(XATTR_NAME_POSIX_ACL_DEFAULT,
+                                       strlen(XATTR_NAME_POSIX_ACL_DEFAULT));
        }
 
        slot++;
@@ -3774,6 +3774,7 @@ cache_acl:
                break;
        case S_IFLNK:
                inode->i_op = &btrfs_symlink_inode_operations;
+               inode_nohighmem(inode);
                inode->i_mapping->a_ops = &btrfs_symlink_aops;
                break;
        default:
@@ -9705,6 +9706,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
        btrfs_free_path(path);
 
        inode->i_op = &btrfs_symlink_inode_operations;
+       inode_nohighmem(inode);
        inode->i_mapping->a_ops = &btrfs_symlink_aops;
        inode_set_bytes(inode, name_len);
        btrfs_i_size_write(inode, name_len);
@@ -9994,7 +9996,7 @@ static const struct inode_operations btrfs_dir_inode_operations = {
        .setattr        = btrfs_setattr,
        .mknod          = btrfs_mknod,
        .setxattr       = btrfs_setxattr,
-       .getxattr       = btrfs_getxattr,
+       .getxattr       = generic_getxattr,
        .listxattr      = btrfs_listxattr,
        .removexattr    = btrfs_removexattr,
        .permission     = btrfs_permission,
@@ -10071,7 +10073,7 @@ static const struct inode_operations btrfs_file_inode_operations = {
        .getattr        = btrfs_getattr,
        .setattr        = btrfs_setattr,
        .setxattr       = btrfs_setxattr,
-       .getxattr       = btrfs_getxattr,
+       .getxattr       = generic_getxattr,
        .listxattr      = btrfs_listxattr,
        .removexattr    = btrfs_removexattr,
        .permission     = btrfs_permission,
@@ -10085,7 +10087,7 @@ static const struct inode_operations btrfs_special_inode_operations = {
        .setattr        = btrfs_setattr,
        .permission     = btrfs_permission,
        .setxattr       = btrfs_setxattr,
-       .getxattr       = btrfs_getxattr,
+       .getxattr       = generic_getxattr,
        .listxattr      = btrfs_listxattr,
        .removexattr    = btrfs_removexattr,
        .get_acl        = btrfs_get_acl,
@@ -10094,13 +10096,12 @@ static const struct inode_operations btrfs_special_inode_operations = {
 };
 static const struct inode_operations btrfs_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = page_follow_link_light,
-       .put_link       = page_put_link,
+       .get_link       = page_get_link,
        .getattr        = btrfs_getattr,
        .setattr        = btrfs_setattr,
        .permission     = btrfs_permission,
        .setxattr       = btrfs_setxattr,
-       .getxattr       = btrfs_getxattr,
+       .getxattr       = generic_getxattr,
        .listxattr      = btrfs_listxattr,
        .removexattr    = btrfs_removexattr,
        .update_time    = btrfs_update_time,
index 1fcd7b6e7564defa675b3abe12589473a58e937d..7cbef1a14fe1b13bc3af4c63f47efb3a6f83dbad 100644 (file)
@@ -351,137 +351,89 @@ err:
        return ret;
 }
 
-/*
- * List of handlers for synthetic system.* attributes.  All real ondisk
- * attributes are handled directly.
- */
-const struct xattr_handler *btrfs_xattr_handlers[] = {
-#ifdef CONFIG_BTRFS_FS_POSIX_ACL
-       &posix_acl_access_xattr_handler,
-       &posix_acl_default_xattr_handler,
-#endif
-       NULL,
-};
-
-/*
- * Check if the attribute is in a supported namespace.
- *
- * This is applied after the check for the synthetic attributes in the system
- * namespace.
- */
-static int btrfs_is_valid_xattr(const char *name)
+static int btrfs_xattr_handler_get(const struct xattr_handler *handler,
+                                  struct dentry *dentry, const char *name,
+                                  void *buffer, size_t size)
 {
-       int len = strlen(name);
-       int prefixlen = 0;
-
-       if (!strncmp(name, XATTR_SECURITY_PREFIX,
-                       XATTR_SECURITY_PREFIX_LEN))
-               prefixlen = XATTR_SECURITY_PREFIX_LEN;
-       else if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
-               prefixlen = XATTR_SYSTEM_PREFIX_LEN;
-       else if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
-               prefixlen = XATTR_TRUSTED_PREFIX_LEN;
-       else if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
-               prefixlen = XATTR_USER_PREFIX_LEN;
-       else if (!strncmp(name, XATTR_BTRFS_PREFIX, XATTR_BTRFS_PREFIX_LEN))
-               prefixlen = XATTR_BTRFS_PREFIX_LEN;
-       else
-               return -EOPNOTSUPP;
-
-       /*
-        * The name cannot consist of just prefix
-        */
-       if (len <= prefixlen)
-               return -EINVAL;
+       struct inode *inode = d_inode(dentry);
 
-       return 0;
+       name = xattr_full_name(handler, name);
+       return __btrfs_getxattr(inode, name, buffer, size);
 }
 
-ssize_t btrfs_getxattr(struct dentry *dentry, const char *name,
-                      void *buffer, size_t size)
+static int btrfs_xattr_handler_set(const struct xattr_handler *handler,
+                                  struct dentry *dentry, const char *name,
+                                  const void *buffer, size_t size,
+                                  int flags)
 {
-       int ret;
+       struct inode *inode = d_inode(dentry);
 
-       /*
-        * If this is a request for a synthetic attribute in the system.*
-        * namespace use the generic infrastructure to resolve a handler
-        * for it via sb->s_xattr.
-        */
-       if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
-               return generic_getxattr(dentry, name, buffer, size);
+       name = xattr_full_name(handler, name);
+       return __btrfs_setxattr(NULL, inode, name, buffer, size, flags);
+}
 
-       ret = btrfs_is_valid_xattr(name);
-       if (ret)
-               return ret;
-       return __btrfs_getxattr(d_inode(dentry), name, buffer, size);
+static int btrfs_xattr_handler_set_prop(const struct xattr_handler *handler,
+                                       struct dentry *dentry,
+                                       const char *name, const void *value,
+                                       size_t size, int flags)
+{
+       name = xattr_full_name(handler, name);
+       return btrfs_set_prop(d_inode(dentry), name, value, size, flags);
 }
 
+static const struct xattr_handler btrfs_security_xattr_handler = {
+       .prefix = XATTR_SECURITY_PREFIX,
+       .get = btrfs_xattr_handler_get,
+       .set = btrfs_xattr_handler_set,
+};
+
+static const struct xattr_handler btrfs_trusted_xattr_handler = {
+       .prefix = XATTR_TRUSTED_PREFIX,
+       .get = btrfs_xattr_handler_get,
+       .set = btrfs_xattr_handler_set,
+};
+
+static const struct xattr_handler btrfs_user_xattr_handler = {
+       .prefix = XATTR_USER_PREFIX,
+       .get = btrfs_xattr_handler_get,
+       .set = btrfs_xattr_handler_set,
+};
+
+static const struct xattr_handler btrfs_btrfs_xattr_handler = {
+       .prefix = XATTR_BTRFS_PREFIX,
+       .get = btrfs_xattr_handler_get,
+       .set = btrfs_xattr_handler_set_prop,
+};
+
+const struct xattr_handler *btrfs_xattr_handlers[] = {
+       &btrfs_security_xattr_handler,
+#ifdef CONFIG_BTRFS_FS_POSIX_ACL
+       &posix_acl_access_xattr_handler,
+       &posix_acl_default_xattr_handler,
+#endif
+       &btrfs_trusted_xattr_handler,
+       &btrfs_user_xattr_handler,
+       &btrfs_btrfs_xattr_handler,
+       NULL,
+};
+
 int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
                   size_t size, int flags)
 {
        struct btrfs_root *root = BTRFS_I(d_inode(dentry))->root;
-       int ret;
 
-       /*
-        * The permission on security.* and system.* is not checked
-        * in permission().
-        */
        if (btrfs_root_readonly(root))
                return -EROFS;
-
-       /*
-        * If this is a request for a synthetic attribute in the system.*
-        * namespace use the generic infrastructure to resolve a handler
-        * for it via sb->s_xattr.
-        */
-       if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
-               return generic_setxattr(dentry, name, value, size, flags);
-
-       ret = btrfs_is_valid_xattr(name);
-       if (ret)
-               return ret;
-
-       if (!strncmp(name, XATTR_BTRFS_PREFIX, XATTR_BTRFS_PREFIX_LEN))
-               return btrfs_set_prop(d_inode(dentry), name,
-                                     value, size, flags);
-
-       if (size == 0)
-               value = "";  /* empty EA, do not remove */
-
-       return __btrfs_setxattr(NULL, d_inode(dentry), name, value, size,
-                               flags);
+       return generic_setxattr(dentry, name, value, size, flags);
 }
 
 int btrfs_removexattr(struct dentry *dentry, const char *name)
 {
        struct btrfs_root *root = BTRFS_I(d_inode(dentry))->root;
-       int ret;
 
-       /*
-        * The permission on security.* and system.* is not checked
-        * in permission().
-        */
        if (btrfs_root_readonly(root))
                return -EROFS;
-
-       /*
-        * If this is a request for a synthetic attribute in the system.*
-        * namespace use the generic infrastructure to resolve a handler
-        * for it via sb->s_xattr.
-        */
-       if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
-               return generic_removexattr(dentry, name);
-
-       ret = btrfs_is_valid_xattr(name);
-       if (ret)
-               return ret;
-
-       if (!strncmp(name, XATTR_BTRFS_PREFIX, XATTR_BTRFS_PREFIX_LEN))
-               return btrfs_set_prop(d_inode(dentry), name,
-                                     NULL, 0, XATTR_REPLACE);
-
-       return __btrfs_setxattr(NULL, d_inode(dentry), name, NULL, 0,
-                               XATTR_REPLACE);
+       return generic_removexattr(dentry, name);
 }
 
 static int btrfs_initxattrs(struct inode *inode,
index 5049608d13889e1e647cdb447851a6b30319990d..96807b3d22f502d3cf5a683dab48ed7602845325 100644 (file)
@@ -28,8 +28,6 @@ extern ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
 extern int __btrfs_setxattr(struct btrfs_trans_handle *trans,
                            struct inode *inode, const char *name,
                            const void *value, size_t size, int flags);
-extern ssize_t btrfs_getxattr(struct dentry *dentry, const char *name,
-               void *buffer, size_t size);
 extern int btrfs_setxattr(struct dentry *dentry, const char *name,
                const void *value, size_t size, int flags);
 extern int btrfs_removexattr(struct dentry *dentry, const char *name);
index 8f84646f10e9560ade100c1dafa180768f1d76de..f19708487e2f74c80e55b14ecbadb07bf79b73a9 100644 (file)
@@ -49,10 +49,10 @@ struct posix_acl *ceph_get_acl(struct inode *inode, int type)
 
        switch (type) {
        case ACL_TYPE_ACCESS:
-               name = POSIX_ACL_XATTR_ACCESS;
+               name = XATTR_NAME_POSIX_ACL_ACCESS;
                break;
        case ACL_TYPE_DEFAULT:
-               name = POSIX_ACL_XATTR_DEFAULT;
+               name = XATTR_NAME_POSIX_ACL_DEFAULT;
                break;
        default:
                BUG();
@@ -92,7 +92,7 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 
        switch (type) {
        case ACL_TYPE_ACCESS:
-               name = POSIX_ACL_XATTR_ACCESS;
+               name = XATTR_NAME_POSIX_ACL_ACCESS;
                if (acl) {
                        ret = posix_acl_equiv_mode(acl, &new_mode);
                        if (ret < 0)
@@ -106,7 +106,7 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
                        ret = acl ? -EINVAL : 0;
                        goto out;
                }
-               name = POSIX_ACL_XATTR_DEFAULT;
+               name = XATTR_NAME_POSIX_ACL_DEFAULT;
                break;
        default:
                ret = -EINVAL;
@@ -202,11 +202,11 @@ int ceph_pre_init_acls(struct inode *dir, umode_t *mode,
        ceph_pagelist_encode_32(pagelist, acl && default_acl ? 2 : 1);
 
        if (acl) {
-               size_t len = strlen(POSIX_ACL_XATTR_ACCESS);
+               size_t len = strlen(XATTR_NAME_POSIX_ACL_ACCESS);
                err = ceph_pagelist_reserve(pagelist, len + val_size1 + 8);
                if (err)
                        goto out_err;
-               ceph_pagelist_encode_string(pagelist, POSIX_ACL_XATTR_ACCESS,
+               ceph_pagelist_encode_string(pagelist, XATTR_NAME_POSIX_ACL_ACCESS,
                                            len);
                err = posix_acl_to_xattr(&init_user_ns, acl,
                                         tmp_buf, val_size1);
@@ -216,12 +216,12 @@ int ceph_pre_init_acls(struct inode *dir, umode_t *mode,
                ceph_pagelist_append(pagelist, tmp_buf, val_size1);
        }
        if (default_acl) {
-               size_t len = strlen(POSIX_ACL_XATTR_DEFAULT);
+               size_t len = strlen(XATTR_NAME_POSIX_ACL_DEFAULT);
                err = ceph_pagelist_reserve(pagelist, len + val_size2 + 8);
                if (err)
                        goto out_err;
                err = ceph_pagelist_encode_string(pagelist,
-                                                 POSIX_ACL_XATTR_DEFAULT, len);
+                                                 XATTR_NAME_POSIX_ACL_DEFAULT, len);
                err = posix_acl_to_xattr(&init_user_ns, default_acl,
                                         tmp_buf, val_size2);
                if (err < 0)
index 498dcfa2dcdbedf393ae26fc9f7f68cf90bceb90..da55eb8bcffab89755baf5229b92ededf49dd484 100644 (file)
@@ -1756,7 +1756,7 @@ retry:
  */
 static const struct inode_operations ceph_symlink_iops = {
        .readlink = generic_readlink,
-       .follow_link = simple_follow_link,
+       .get_link = simple_get_link,
        .setattr = ceph_setattr,
        .getattr = ceph_getattr,
        .setxattr = ceph_setxattr,
index cbc0f4bca0c0dfa73b6a545fb6978a72b1a702ef..90e4e2b398b66b08c9a35ed3448f34c91fbcb1df 100644 (file)
@@ -900,8 +900,7 @@ const struct inode_operations cifs_file_inode_ops = {
 
 const struct inode_operations cifs_symlink_inode_ops = {
        .readlink = generic_readlink,
-       .follow_link = cifs_follow_link,
-       .put_link = kfree_put_link,
+       .get_link = cifs_get_link,
        .permission = cifs_permission,
        /* BB add the following two eventually */
        /* revalidate: cifs_revalidate,
index c3cc1609025fa3a966c2d5b10f32626214a9e4ef..26a1187d4323f227ca89072504d94619d8eb5df5 100644 (file)
@@ -120,9 +120,8 @@ extern struct vfsmount *cifs_dfs_d_automount(struct path *path);
 #endif
 
 /* Functions related to symlinks */
-extern const char *cifs_follow_link(struct dentry *direntry, void **cookie);
-extern int cifs_readlink(struct dentry *direntry, char __user *buffer,
-                        int buflen);
+extern const char *cifs_get_link(struct dentry *, struct inode *,
+                       struct delayed_call *);
 extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
                        const char *symname);
 extern int     cifs_removexattr(struct dentry *, const char *);
index e3548f73bdeaa980ef1c282246688e1e3f5f21e8..062c2375549a87acf716957593a58f213a972e06 100644 (file)
@@ -627,9 +627,9 @@ cifs_hl_exit:
 }
 
 const char *
-cifs_follow_link(struct dentry *direntry, void **cookie)
+cifs_get_link(struct dentry *direntry, struct inode *inode,
+             struct delayed_call *done)
 {
-       struct inode *inode = d_inode(direntry);
        int rc = -ENOMEM;
        unsigned int xid;
        char *full_path = NULL;
@@ -639,6 +639,9 @@ cifs_follow_link(struct dentry *direntry, void **cookie)
        struct cifs_tcon *tcon;
        struct TCP_Server_Info *server;
 
+       if (!direntry)
+               return ERR_PTR(-ECHILD);
+
        xid = get_xid();
 
        tlink = cifs_sb_tlink(cifs_sb);
@@ -678,7 +681,8 @@ cifs_follow_link(struct dentry *direntry, void **cookie)
                kfree(target_path);
                return ERR_PTR(rc);
        }
-       return *cookie = target_path;
+       set_delayed_call(done, kfree_link, target_path);
+       return target_path;
 }
 
 int
index ff9e1f8b16a4872158c05f688a9761a9a7a8781d..f5dc2f0df4ad6f13b52e26ac8bd0bf12c5370ed8 100644 (file)
@@ -190,8 +190,8 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
 #endif /* CONFIG_CIFS_ACL */
        } else {
                int temp;
-               temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
-                       strlen(POSIX_ACL_XATTR_ACCESS));
+               temp = strncmp(ea_name, XATTR_NAME_POSIX_ACL_ACCESS,
+                       strlen(XATTR_NAME_POSIX_ACL_ACCESS));
                if (temp == 0) {
 #ifdef CONFIG_CIFS_POSIX
                        if (sb->s_flags & MS_POSIXACL)
@@ -203,8 +203,8 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
 #else
                        cifs_dbg(FYI, "set POSIX ACL not supported\n");
 #endif
-               } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
-                                  strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
+               } else if (strncmp(ea_name, XATTR_NAME_POSIX_ACL_DEFAULT,
+                                  strlen(XATTR_NAME_POSIX_ACL_DEFAULT)) == 0) {
 #ifdef CONFIG_CIFS_POSIX
                        if (sb->s_flags & MS_POSIXACL)
                                rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
@@ -292,8 +292,8 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
                        rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
                                full_path, ea_name, ea_value, buf_size,
                                cifs_sb->local_nls, cifs_remap(cifs_sb));
-       } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
-                         strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
+       } else if (strncmp(ea_name, XATTR_NAME_POSIX_ACL_ACCESS,
+                         strlen(XATTR_NAME_POSIX_ACL_ACCESS)) == 0) {
 #ifdef CONFIG_CIFS_POSIX
                if (sb->s_flags & MS_POSIXACL)
                        rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
@@ -303,8 +303,8 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
 #else
                cifs_dbg(FYI, "Query POSIX ACL not supported yet\n");
 #endif /* CONFIG_CIFS_POSIX */
-       } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
-                         strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
+       } else if (strncmp(ea_name, XATTR_NAME_POSIX_ACL_DEFAULT,
+                         strlen(XATTR_NAME_POSIX_ACL_DEFAULT)) == 0) {
 #ifdef CONFIG_CIFS_POSIX
                if (sb->s_flags & MS_POSIXACL)
                        rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
index 7740b1c871c183ea55994e84812273effa58a476..1bfb7ba4e85e3ecc05000a3543a01917a7ed40a4 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/coda.h>
 #include <linux/coda_psdev.h>
+#include <linux/pagemap.h>
 #include "coda_linux.h"
 
 static inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2)
@@ -17,8 +18,7 @@ static inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2)
 
 static const struct inode_operations coda_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = page_follow_link_light,
-       .put_link       = page_put_link,
+       .get_link       = page_get_link,
        .setattr        = coda_setattr,
 };
 
@@ -35,6 +35,7 @@ static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
                 inode->i_fop = &coda_dir_operations;
         } else if (S_ISLNK(inode->i_mode)) {
                inode->i_op = &coda_symlink_inode_operations;
+               inode_nohighmem(inode);
                inode->i_data.a_ops = &coda_symlink_aops;
                inode->i_mapping = &inode->i_data;
        } else
index ab94ef63caefed0767e8f2cccf6364038ca94825..03736e20d72076cec96eb0c57aa0c9bf8f901e59 100644 (file)
@@ -26,7 +26,7 @@ static int coda_symlink_filler(struct file *file, struct page *page)
        int error;
        struct coda_inode_info *cii;
        unsigned int len = PAGE_SIZE;
-       char *p = kmap(page);
+       char *p = page_address(page);
 
        cii = ITOC(inode);
 
@@ -34,13 +34,11 @@ static int coda_symlink_filler(struct file *file, struct page *page)
        if (error)
                goto fail;
        SetPageUptodate(page);
-       kunmap(page);
        unlock_page(page);
        return 0;
 
 fail:
        SetPageError(page);
-       kunmap(page);
        unlock_page(page);
        return error;
 }
index dcf26537c935f25ed10a534a13e31492802c5369..9144b779d10ef454d0f42bb15f7560878265b5ba 100644 (file)
@@ -58,6 +58,8 @@
 #include <linux/atalk.h>
 #include <linux/gfp.h>
 
+#include "internal.h"
+
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_sock.h>
 #include <net/bluetooth/rfcomm.h>
 #include <asm/fbio.h>
 #endif
 
-static int w_long(unsigned int fd, unsigned int cmd,
-               compat_ulong_t __user *argp)
+#define convert_in_user(srcptr, dstptr)                        \
+({                                                     \
+       typeof(*srcptr) val;                            \
+                                                       \
+       get_user(val, srcptr) || put_user(val, dstptr); \
+})
+
+static int do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int err;
+
+       err = security_file_ioctl(file, cmd, arg);
+       if (err)
+               return err;
+
+       return vfs_ioctl(file, cmd, arg);
+}
+
+static int w_long(struct file *file,
+               unsigned int cmd, compat_ulong_t __user *argp)
 {
-       mm_segment_t old_fs = get_fs();
        int err;
-       unsigned long val;
+       unsigned long __user *valp = compat_alloc_user_space(sizeof(*valp));
 
-       set_fs (KERNEL_DS);
-       err = sys_ioctl(fd, cmd, (unsigned long)&val);
-       set_fs (old_fs);
-       if (!err && put_user(val, argp))
+       if (valp == NULL)
                return -EFAULT;
-       return err;
+       err = do_ioctl(file, cmd, (unsigned long)valp);
+       if (err)
+               return err;
+       if (convert_in_user(valp, argp))
+               return -EFAULT;
+       return 0;
 }
 
 struct compat_video_event {
@@ -139,23 +160,23 @@ struct compat_video_event {
        } u;
 };
 
-static int do_video_get_event(unsigned int fd, unsigned int cmd,
-               struct compat_video_event __user *up)
+static int do_video_get_event(struct file *file,
+               unsigned int cmd, struct compat_video_event __user *up)
 {
-       struct video_event kevent;
-       mm_segment_t old_fs = get_fs();
+       struct video_event __user *kevent =
+               compat_alloc_user_space(sizeof(*kevent));
        int err;
 
-       set_fs(KERNEL_DS);
-       err = sys_ioctl(fd, cmd, (unsigned long) &kevent);
-       set_fs(old_fs);
+       if (kevent == NULL)
+               return -EFAULT;
 
+       err = do_ioctl(file, cmd, (unsigned long)kevent);
        if (!err) {
-               err  = put_user(kevent.type, &up->type);
-               err |= put_user(kevent.timestamp, &up->timestamp);
-               err |= put_user(kevent.u.size.w, &up->u.size.w);
-               err |= put_user(kevent.u.size.h, &up->u.size.h);
-               err |= put_user(kevent.u.size.aspect_ratio,
+               err  = convert_in_user(&kevent->type, &up->type);
+               err |= convert_in_user(&kevent->timestamp, &up->timestamp);
+               err |= convert_in_user(&kevent->u.size.w, &up->u.size.w);
+               err |= convert_in_user(&kevent->u.size.h, &up->u.size.h);
+               err |= convert_in_user(&kevent->u.size.aspect_ratio,
                                &up->u.size.aspect_ratio);
                if (err)
                        err = -EFAULT;
@@ -169,8 +190,8 @@ struct compat_video_still_picture {
         int32_t size;
 };
 
-static int do_video_stillpicture(unsigned int fd, unsigned int cmd,
-       struct compat_video_still_picture __user *up)
+static int do_video_stillpicture(struct file *file,
+               unsigned int cmd, struct compat_video_still_picture __user *up)
 {
        struct video_still_picture __user *up_native;
        compat_uptr_t fp;
@@ -190,7 +211,7 @@ static int do_video_stillpicture(unsigned int fd, unsigned int cmd,
        if (err)
                return -EFAULT;
 
-       err = sys_ioctl(fd, cmd, (unsigned long) up_native);
+       err = do_ioctl(file, cmd, (unsigned long) up_native);
 
        return err;
 }
@@ -200,8 +221,8 @@ struct compat_video_spu_palette {
        compat_uptr_t palette;
 };
 
-static int do_video_set_spu_palette(unsigned int fd, unsigned int cmd,
-               struct compat_video_spu_palette __user *up)
+static int do_video_set_spu_palette(struct file *file,
+               unsigned int cmd, struct compat_video_spu_palette __user *up)
 {
        struct video_spu_palette __user *up_native;
        compat_uptr_t palp;
@@ -218,7 +239,7 @@ static int do_video_set_spu_palette(unsigned int fd, unsigned int cmd,
        if (err)
                return -EFAULT;
 
-       err = sys_ioctl(fd, cmd, (unsigned long) up_native);
+       err = do_ioctl(file, cmd, (unsigned long) up_native);
 
        return err;
 }
@@ -276,7 +297,7 @@ static int sg_build_iovec(sg_io_hdr_t __user *sgio, void __user *dxferp, u16 iov
        return 0;
 }
 
-static int sg_ioctl_trans(unsigned int fd, unsigned int cmd,
+static int sg_ioctl_trans(struct file *file, unsigned int cmd,
                        sg_io_hdr32_t __user *sgio32)
 {
        sg_io_hdr_t __user *sgio;
@@ -289,7 +310,7 @@ static int sg_ioctl_trans(unsigned int fd, unsigned int cmd,
        if (get_user(interface_id, &sgio32->interface_id))
                return -EFAULT;
        if (interface_id != 'S')
-               return sys_ioctl(fd, cmd, (unsigned long)sgio32);
+               return do_ioctl(file, cmd, (unsigned long)sgio32);
 
        if (get_user(iovec_count, &sgio32->iovec_count))
                return -EFAULT;
@@ -349,7 +370,7 @@ static int sg_ioctl_trans(unsigned int fd, unsigned int cmd,
        if (put_user(compat_ptr(data), &sgio->usr_ptr))
                return -EFAULT;
 
-       err = sys_ioctl(fd, cmd, (unsigned long) sgio);
+       err = do_ioctl(file, cmd, (unsigned long) sgio);
 
        if (err >= 0) {
                void __user *datap;
@@ -380,13 +401,13 @@ struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
        int unused;
 };
 
-static int sg_grt_trans(unsigned int fd, unsigned int cmd, struct
-                       compat_sg_req_info __user *o)
+static int sg_grt_trans(struct file *file,
+               unsigned int cmd, struct compat_sg_req_info __user *o)
 {
        int err, i;
        sg_req_info_t __user *r;
        r = compat_alloc_user_space(sizeof(sg_req_info_t)*SG_MAX_QUEUE);
-       err = sys_ioctl(fd,cmd,(unsigned long)r);
+       err = do_ioctl(file, cmd, (unsigned long)r);
        if (err < 0)
                return err;
        for (i = 0; i < SG_MAX_QUEUE; i++) {
@@ -412,8 +433,8 @@ struct sock_fprog32 {
 #define PPPIOCSPASS32  _IOW('t', 71, struct sock_fprog32)
 #define PPPIOCSACTIVE32        _IOW('t', 70, struct sock_fprog32)
 
-static int ppp_sock_fprog_ioctl_trans(unsigned int fd, unsigned int cmd,
-                       struct sock_fprog32 __user *u_fprog32)
+static int ppp_sock_fprog_ioctl_trans(struct file *file,
+               unsigned int cmd, struct sock_fprog32 __user *u_fprog32)
 {
        struct sock_fprog __user *u_fprog64 = compat_alloc_user_space(sizeof(struct sock_fprog));
        void __user *fptr64;
@@ -435,7 +456,7 @@ static int ppp_sock_fprog_ioctl_trans(unsigned int fd, unsigned int cmd,
        else
                cmd = PPPIOCSACTIVE;
 
-       return sys_ioctl(fd, cmd, (unsigned long) u_fprog64);
+       return do_ioctl(file, cmd, (unsigned long) u_fprog64);
 }
 
 struct ppp_option_data32 {
@@ -451,7 +472,7 @@ struct ppp_idle32 {
 };
 #define PPPIOCGIDLE32          _IOR('t', 63, struct ppp_idle32)
 
-static int ppp_gidle(unsigned int fd, unsigned int cmd,
+static int ppp_gidle(struct file *file, unsigned int cmd,
                struct ppp_idle32 __user *idle32)
 {
        struct ppp_idle __user *idle;
@@ -460,7 +481,7 @@ static int ppp_gidle(unsigned int fd, unsigned int cmd,
 
        idle = compat_alloc_user_space(sizeof(*idle));
 
-       err = sys_ioctl(fd, PPPIOCGIDLE, (unsigned long) idle);
+       err = do_ioctl(file, PPPIOCGIDLE, (unsigned long) idle);
 
        if (!err) {
                if (get_user(xmit, &idle->xmit_idle) ||
@@ -472,7 +493,7 @@ static int ppp_gidle(unsigned int fd, unsigned int cmd,
        return err;
 }
 
-static int ppp_scompress(unsigned int fd, unsigned int cmd,
+static int ppp_scompress(struct file *file, unsigned int cmd,
        struct ppp_option_data32 __user *odata32)
 {
        struct ppp_option_data __user *odata;
@@ -492,7 +513,7 @@ static int ppp_scompress(unsigned int fd, unsigned int cmd,
                         sizeof(__u32) + sizeof(int)))
                return -EFAULT;
 
-       return sys_ioctl(fd, PPPIOCSCOMPRESS, (unsigned long) odata);
+       return do_ioctl(file, PPPIOCSCOMPRESS, (unsigned long) odata);
 }
 
 #ifdef CONFIG_BLOCK
@@ -512,12 +533,13 @@ struct mtpos32 {
 };
 #define MTIOCPOS32     _IOR('m', 3, struct mtpos32)
 
-static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, void __user *argp)
+static int mt_ioctl_trans(struct file *file,
+               unsigned int cmd, void __user *argp)
 {
-       mm_segment_t old_fs = get_fs();
-       struct mtget get;
+       /* NULL initialization to make gcc shut up */
+       struct mtget __user *get = NULL;
        struct mtget32 __user *umget32;
-       struct mtpos pos;
+       struct mtpos __user *pos = NULL;
        struct mtpos32 __user *upos32;
        unsigned long kcmd;
        void *karg;
@@ -526,32 +548,34 @@ static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, void __user *argp)
        switch(cmd) {
        case MTIOCPOS32:
                kcmd = MTIOCPOS;
-               karg = &pos;
+               pos = compat_alloc_user_space(sizeof(*pos));
+               karg = pos;
                break;
        default:        /* MTIOCGET32 */
                kcmd = MTIOCGET;
-               karg = &get;
+               get = compat_alloc_user_space(sizeof(*get));
+               karg = get;
                break;
        }
-       set_fs (KERNEL_DS);
-       err = sys_ioctl (fd, kcmd, (unsigned long)karg);
-       set_fs (old_fs);
+       if (karg == NULL)
+               return -EFAULT;
+       err = do_ioctl(file, kcmd, (unsigned long)karg);
        if (err)
                return err;
        switch (cmd) {
        case MTIOCPOS32:
                upos32 = argp;
-               err = __put_user(pos.mt_blkno, &upos32->mt_blkno);
+               err = convert_in_user(&pos->mt_blkno, &upos32->mt_blkno);
                break;
        case MTIOCGET32:
                umget32 = argp;
-               err = __put_user(get.mt_type, &umget32->mt_type);
-               err |= __put_user(get.mt_resid, &umget32->mt_resid);
-               err |= __put_user(get.mt_dsreg, &umget32->mt_dsreg);
-               err |= __put_user(get.mt_gstat, &umget32->mt_gstat);
-               err |= __put_user(get.mt_erreg, &umget32->mt_erreg);
-               err |= __put_user(get.mt_fileno, &umget32->mt_fileno);
-               err |= __put_user(get.mt_blkno, &umget32->mt_blkno);
+               err = convert_in_user(&get->mt_type, &umget32->mt_type);
+               err |= convert_in_user(&get->mt_resid, &umget32->mt_resid);
+               err |= convert_in_user(&get->mt_dsreg, &umget32->mt_dsreg);
+               err |= convert_in_user(&get->mt_gstat, &umget32->mt_gstat);
+               err |= convert_in_user(&get->mt_erreg, &umget32->mt_erreg);
+               err |= convert_in_user(&get->mt_fileno, &umget32->mt_fileno);
+               err |= convert_in_user(&get->mt_blkno, &umget32->mt_blkno);
                break;
        }
        return err ? -EFAULT: 0;
@@ -605,42 +629,41 @@ struct serial_struct32 {
         compat_int_t    reserved[1];
 };
 
-static int serial_struct_ioctl(unsigned fd, unsigned cmd,
-                       struct serial_struct32 __user *ss32)
+static int serial_struct_ioctl(struct file *file,
+               unsigned cmd, struct serial_struct32 __user *ss32)
 {
         typedef struct serial_struct32 SS32;
         int err;
-        struct serial_struct ss;
-        mm_segment_t oldseg = get_fs();
+       struct serial_struct __user *ss = compat_alloc_user_space(sizeof(*ss));
         __u32 udata;
        unsigned int base;
+       unsigned char *iomem_base;
 
+       if (ss == NULL)
+               return -EFAULT;
         if (cmd == TIOCSSERIAL) {
-                if (!access_ok(VERIFY_READ, ss32, sizeof(SS32)))
-                        return -EFAULT;
-                if (__copy_from_user(&ss, ss32, offsetof(SS32, iomem_base)))
+               if (copy_in_user(ss, ss32, offsetof(SS32, iomem_base)) ||
+                   get_user(udata, &ss32->iomem_base))
                        return -EFAULT;
-                if (__get_user(udata, &ss32->iomem_base))
+               iomem_base = compat_ptr(udata);
+               if (put_user(iomem_base, &ss->iomem_base) ||
+                   convert_in_user(&ss32->iomem_reg_shift,
+                     &ss->iomem_reg_shift) ||
+                   convert_in_user(&ss32->port_high, &ss->port_high) ||
+                   put_user(0UL, &ss->iomap_base))
                        return -EFAULT;
-                ss.iomem_base = compat_ptr(udata);
-                if (__get_user(ss.iomem_reg_shift, &ss32->iomem_reg_shift) ||
-                   __get_user(ss.port_high, &ss32->port_high))
-                       return -EFAULT;
-                ss.iomap_base = 0UL;
         }
-        set_fs(KERNEL_DS);
-                err = sys_ioctl(fd,cmd,(unsigned long)(&ss));
-        set_fs(oldseg);
+       err = do_ioctl(file, cmd, (unsigned long)ss);
         if (cmd == TIOCGSERIAL && err >= 0) {
-                if (!access_ok(VERIFY_WRITE, ss32, sizeof(SS32)))
-                        return -EFAULT;
-                if (__copy_to_user(ss32,&ss,offsetof(SS32,iomem_base)))
+               if (copy_in_user(ss32, ss, offsetof(SS32, iomem_base)) ||
+                   get_user(iomem_base, &ss->iomem_base))
                        return -EFAULT;
-               base = (unsigned long)ss.iomem_base  >> 32 ?
-                       0xffffffff : (unsigned)(unsigned long)ss.iomem_base;
-               if (__put_user(base, &ss32->iomem_base) ||
-                   __put_user(ss.iomem_reg_shift, &ss32->iomem_reg_shift) ||
-                   __put_user(ss.port_high, &ss32->port_high))
+               base = (unsigned long)iomem_base  >> 32 ?
+                       0xffffffff : (unsigned)(unsigned long)iomem_base;
+               if (put_user(base, &ss32->iomem_base) ||
+                   convert_in_user(&ss->iomem_reg_shift,
+                     &ss32->iomem_reg_shift) ||
+                   convert_in_user(&ss->port_high, &ss32->port_high))
                        return -EFAULT;
         }
         return err;
@@ -674,8 +697,8 @@ struct i2c_rdwr_aligned {
        struct i2c_msg msgs[0];
 };
 
-static int do_i2c_rdwr_ioctl(unsigned int fd, unsigned int cmd,
-                       struct i2c_rdwr_ioctl_data32    __user *udata)
+static int do_i2c_rdwr_ioctl(struct file *file,
+       unsigned int cmd, struct i2c_rdwr_ioctl_data32 __user *udata)
 {
        struct i2c_rdwr_aligned         __user *tdata;
        struct i2c_msg                  __user *tmsgs;
@@ -708,11 +731,11 @@ static int do_i2c_rdwr_ioctl(unsigned int fd, unsigned int cmd,
                    put_user(compat_ptr(datap), &tmsgs[i].buf))
                        return -EFAULT;
        }
-       return sys_ioctl(fd, cmd, (unsigned long)tdata);
+       return do_ioctl(file, cmd, (unsigned long)tdata);
 }
 
-static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd,
-                       struct i2c_smbus_ioctl_data32   __user *udata)
+static int do_i2c_smbus_ioctl(struct file *file,
+               unsigned int cmd, struct i2c_smbus_ioctl_data32   __user *udata)
 {
        struct i2c_smbus_ioctl_data     __user *tdata;
        compat_caddr_t                  datap;
@@ -734,7 +757,7 @@ static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd,
            __put_user(compat_ptr(datap), &tdata->data))
                return -EFAULT;
 
-       return sys_ioctl(fd, cmd, (unsigned long)tdata);
+       return do_ioctl(file, cmd, (unsigned long)tdata);
 }
 
 #define RTC_IRQP_READ32                _IOR('p', 0x0b, compat_ulong_t)
@@ -742,29 +765,27 @@ static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd,
 #define RTC_EPOCH_READ32       _IOR('p', 0x0d, compat_ulong_t)
 #define RTC_EPOCH_SET32                _IOW('p', 0x0e, compat_ulong_t)
 
-static int rtc_ioctl(unsigned fd, unsigned cmd, void __user *argp)
+static int rtc_ioctl(struct file *file,
+               unsigned cmd, void __user *argp)
 {
-       mm_segment_t oldfs = get_fs();
-       compat_ulong_t val32;
-       unsigned long kval;
+       unsigned long __user *valp = compat_alloc_user_space(sizeof(*valp));
        int ret;
 
+       if (valp == NULL)
+               return -EFAULT;
        switch (cmd) {
        case RTC_IRQP_READ32:
        case RTC_EPOCH_READ32:
-               set_fs(KERNEL_DS);
-               ret = sys_ioctl(fd, (cmd == RTC_IRQP_READ32) ?
+               ret = do_ioctl(file, (cmd == RTC_IRQP_READ32) ?
                                        RTC_IRQP_READ : RTC_EPOCH_READ,
-                                       (unsigned long)&kval);
-               set_fs(oldfs);
+                                       (unsigned long)valp);
                if (ret)
                        return ret;
-               val32 = kval;
-               return put_user(val32, (unsigned int __user *)argp);
+               return convert_in_user(valp, (unsigned int __user *)argp);
        case RTC_IRQP_SET32:
-               return sys_ioctl(fd, RTC_IRQP_SET, (unsigned long)argp);
+               return do_ioctl(file, RTC_IRQP_SET, (unsigned long)argp);
        case RTC_EPOCH_SET32:
-               return sys_ioctl(fd, RTC_EPOCH_SET, (unsigned long)argp);
+               return do_ioctl(file, RTC_EPOCH_SET, (unsigned long)argp);
        }
 
        return -ENOIOCTLCMD;
@@ -1436,53 +1457,53 @@ IGNORE_IOCTL(FBIOGCURSOR32)
  * a compat_ioctl operation in the place that handleѕ the
  * ioctl for the native case.
  */
-static long do_ioctl_trans(int fd, unsigned int cmd,
+static long do_ioctl_trans(unsigned int cmd,
                 unsigned long arg, struct file *file)
 {
        void __user *argp = compat_ptr(arg);
 
        switch (cmd) {
        case PPPIOCGIDLE32:
-               return ppp_gidle(fd, cmd, argp);
+               return ppp_gidle(file, cmd, argp);
        case PPPIOCSCOMPRESS32:
-               return ppp_scompress(fd, cmd, argp);
+               return ppp_scompress(file, cmd, argp);
        case PPPIOCSPASS32:
        case PPPIOCSACTIVE32:
-               return ppp_sock_fprog_ioctl_trans(fd, cmd, argp);
+               return ppp_sock_fprog_ioctl_trans(file, cmd, argp);
 #ifdef CONFIG_BLOCK
        case SG_IO:
-               return sg_ioctl_trans(fd, cmd, argp);
+               return sg_ioctl_trans(file, cmd, argp);
        case SG_GET_REQUEST_TABLE:
-               return sg_grt_trans(fd, cmd, argp);
+               return sg_grt_trans(file, cmd, argp);
        case MTIOCGET32:
        case MTIOCPOS32:
-               return mt_ioctl_trans(fd, cmd, argp);
+               return mt_ioctl_trans(file, cmd, argp);
 #endif
        /* Serial */
        case TIOCGSERIAL:
        case TIOCSSERIAL:
-               return serial_struct_ioctl(fd, cmd, argp);
+               return serial_struct_ioctl(file, cmd, argp);
        /* i2c */
        case I2C_FUNCS:
-               return w_long(fd, cmd, argp);
+               return w_long(file, cmd, argp);
        case I2C_RDWR:
-               return do_i2c_rdwr_ioctl(fd, cmd, argp);
+               return do_i2c_rdwr_ioctl(file, cmd, argp);
        case I2C_SMBUS:
-               return do_i2c_smbus_ioctl(fd, cmd, argp);
+               return do_i2c_smbus_ioctl(file, cmd, argp);
        /* Not implemented in the native kernel */
        case RTC_IRQP_READ32:
        case RTC_IRQP_SET32:
        case RTC_EPOCH_READ32:
        case RTC_EPOCH_SET32:
-               return rtc_ioctl(fd, cmd, argp);
+               return rtc_ioctl(file, cmd, argp);
 
        /* dvb */
        case VIDEO_GET_EVENT:
-               return do_video_get_event(fd, cmd, argp);
+               return do_video_get_event(file, cmd, argp);
        case VIDEO_STILLPICTURE:
-               return do_video_stillpicture(fd, cmd, argp);
+               return do_video_stillpicture(file, cmd, argp);
        case VIDEO_SET_SPU_PALETTE:
-               return do_video_set_spu_palette(fd, cmd, argp);
+               return do_video_set_spu_palette(file, cmd, argp);
        }
 
        /*
@@ -1513,7 +1534,7 @@ static long do_ioctl_trans(int fd, unsigned int cmd,
        case NBD_SET_BLKSIZE:
        case NBD_SET_SIZE:
        case NBD_SET_SIZE_BLOCKS:
-               return do_vfs_ioctl(file, fd, cmd, arg);
+               return vfs_ioctl(file, cmd, arg);
        }
 
        return -ENOIOCTLCMD;
@@ -1602,7 +1623,7 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
        if (compat_ioctl_check_table(XFORM(cmd)))
                goto found_handler;
 
-       error = do_ioctl_trans(fd, cmd, arg, f.file);
+       error = do_ioctl_trans(cmd, arg, f.file);
        if (error == -ENOIOCTLCMD)
                error = -ENOTTY;
 
index ec5c8325b503d1a1602863769ae43c067d13a047..db6d692896088ebc9745d9c05c85309280885b38 100644 (file)
@@ -279,27 +279,33 @@ static int configfs_getlink(struct dentry *dentry, char * path)
 
 }
 
-static const char *configfs_follow_link(struct dentry *dentry, void **cookie)
+static const char *configfs_get_link(struct dentry *dentry,
+                                    struct inode *inode,
+                                    struct delayed_call *done)
 {
-       unsigned long page = get_zeroed_page(GFP_KERNEL);
+       char *body;
        int error;
 
-       if (!page)
+       if (!dentry)
+               return ERR_PTR(-ECHILD);
+
+       body = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!body)
                return ERR_PTR(-ENOMEM);
 
-       error = configfs_getlink(dentry, (char *)page);
+       error = configfs_getlink(dentry, body);
        if (!error) {
-               return *cookie = (void *)page;
+               set_delayed_call(done, kfree_link, body);
+               return body;
        }
 
-       free_page(page);
+       kfree(body);
        return ERR_PTR(error);
 }
 
 const struct inode_operations configfs_symlink_inode_operations = {
-       .follow_link = configfs_follow_link,
+       .get_link = configfs_get_link,
        .readlink = generic_readlink,
-       .put_link = free_page_put_link,
        .setattr = configfs_setattr,
 };
 
index 355c522f3585a5e3a7667225681383ff85b93a48..b862bc219cd7c7d269a7ba9e786559d1595315d7 100644 (file)
@@ -100,6 +100,7 @@ static struct inode *get_cramfs_inode(struct super_block *sb,
                break;
        case S_IFLNK:
                inode->i_op = &page_symlink_inode_operations;
+               inode_nohighmem(inode);
                inode->i_data.a_ops = &cramfs_aops;
                break;
        default:
index 5c33aeb0f68febdd03e6f478c7949fd847e9fdcd..d27f0909d9f61141b6f6073996ed56858f2249c7 100644 (file)
@@ -1734,7 +1734,7 @@ static unsigned d_flags_for_inode(struct inode *inode)
        }
 
        if (unlikely(!(inode->i_opflags & IOP_NOFOLLOW))) {
-               if (unlikely(inode->i_op->follow_link)) {
+               if (unlikely(inode->i_op->get_link)) {
                        add_flags = DCACHE_SYMLINK_TYPE;
                        goto type_determined;
                }
index e2e47ba5d313a5f2aca58589e08d2d3df969bed2..a4dddc61594cbdb7797b1a75cd50fae0ec3a6e77 100644 (file)
@@ -674,16 +674,24 @@ out:
        return rc ? ERR_PTR(rc) : buf;
 }
 
-static const char *ecryptfs_follow_link(struct dentry *dentry, void **cookie)
+static const char *ecryptfs_get_link(struct dentry *dentry,
+                                    struct inode *inode,
+                                    struct delayed_call *done)
 {
        size_t len;
-       char *buf = ecryptfs_readlink_lower(dentry, &len);
+       char *buf;
+
+       if (!dentry)
+               return ERR_PTR(-ECHILD);
+
+       buf = ecryptfs_readlink_lower(dentry, &len);
        if (IS_ERR(buf))
                return buf;
        fsstack_copy_attr_atime(d_inode(dentry),
                                d_inode(ecryptfs_dentry_to_lower(dentry)));
        buf[len] = '\0';
-       return *cookie = buf;
+       set_delayed_call(done, kfree_link, buf);
+       return buf;
 }
 
 /**
@@ -1095,8 +1103,7 @@ out:
 
 const struct inode_operations ecryptfs_symlink_iops = {
        .readlink = generic_readlink,
-       .follow_link = ecryptfs_follow_link,
-       .put_link = kfree_put_link,
+       .get_link = ecryptfs_get_link,
        .permission = ecryptfs_permission,
        .setattr = ecryptfs_setattr,
        .getattr = ecryptfs_getattr_link,
index 079d20306ee18990f09943c7eff4f9548cf9d761..cdf0872382afa3e4755d5276fa1588be03d272a1 100644 (file)
@@ -151,6 +151,7 @@ struct inode *efs_iget(struct super_block *super, unsigned long ino)
                        break;
                case S_IFLNK:
                        inode->i_op = &page_symlink_inode_operations;
+                       inode_nohighmem(inode);
                        inode->i_data.a_ops = &efs_symlink_aops;
                        break;
                case S_IFCHR:
index 75117d0dac2b174f5b231234b1543cecd95bdbfa..4870cc82deb014be3e28a5f55704ecedfb3b0c91 100644 (file)
@@ -13,7 +13,7 @@
 
 static int efs_symlink_readpage(struct file *file, struct page *page)
 {
-       char *link = kmap(page);
+       char *link = page_address(page);
        struct buffer_head * bh;
        struct inode * inode = page->mapping->host;
        efs_block_t size = inode->i_size;
@@ -39,12 +39,10 @@ static int efs_symlink_readpage(struct file *file, struct page *page)
        }
        link[size] = '\0';
        SetPageUptodate(page);
-       kunmap(page);
        unlock_page(page);
        return 0;
 fail:
        SetPageError(page);
-       kunmap(page);
        unlock_page(page);
        return err;
 }
index 60f03b78914e3012e50c90a9e9069aff615467be..9eaf595aeaf8840cf74f0f02141411a9fed65c1e 100644 (file)
@@ -1224,6 +1224,7 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino)
                        inode->i_link = (char *)oi->i_data;
                } else {
                        inode->i_op = &page_symlink_inode_operations;
+                       inode_nohighmem(inode);
                        inode->i_mapping->a_ops = &exofs_aops;
                }
        } else {
index 994e078da4bb746fd8c088f70efbfaa19a4665a3..c20d77df2679abb185e29a79f5ceab8349204d65 100644 (file)
@@ -111,6 +111,7 @@ static int exofs_symlink(struct inode *dir, struct dentry *dentry,
        if (l > sizeof(oi->i_data)) {
                /* slow symlink */
                inode->i_op = &page_symlink_inode_operations;
+               inode_nohighmem(inode);
                inode->i_mapping->a_ops = &exofs_aops;
                memset(oi->i_data, 0, sizeof(oi->i_data));
 
index 0aa9bf6e6e53e2d1ac14d26917d6afa1b6fae233..338eefda70c6fc4e2055c0165b590febf1295acb 100644 (file)
@@ -1420,6 +1420,7 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
                                sizeof(ei->i_data) - 1);
                } else {
                        inode->i_op = &ext2_symlink_inode_operations;
+                       inode_nohighmem(inode);
                        if (test_opt(inode->i_sb, NOBH))
                                inode->i_mapping->a_ops = &ext2_nobh_aops;
                        else
index 3267a80dbbe26f4fbefb14c82fdb832d9169d6a8..7a2be8f7f3c37a69135cab528b1244e51c5fc2a2 100644 (file)
@@ -183,6 +183,7 @@ static int ext2_symlink (struct inode * dir, struct dentry * dentry,
        if (l > sizeof (EXT2_I(inode)->i_data)) {
                /* slow symlink */
                inode->i_op = &ext2_symlink_inode_operations;
+               inode_nohighmem(inode);
                if (test_opt(inode->i_sb, NOBH))
                        inode->i_mapping->a_ops = &ext2_nobh_aops;
                else
index ae17179f3810b2dd635c81203643a14f8f4c0c10..3495d8ae4b33b1e8dc5a1d9341fa7d6d9835e4c5 100644 (file)
@@ -22,8 +22,7 @@
 
 const struct inode_operations ext2_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = page_follow_link_light,
-       .put_link       = page_put_link,
+       .get_link       = page_get_link,
        .setattr        = ext2_setattr,
 #ifdef CONFIG_EXT2_FS_XATTR
        .setxattr       = generic_setxattr,
@@ -35,7 +34,7 @@ const struct inode_operations ext2_symlink_inode_operations = {
  
 const struct inode_operations ext2_fast_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = simple_follow_link,
+       .get_link       = simple_get_link,
        .setattr        = ext2_setattr,
 #ifdef CONFIG_EXT2_FS_XATTR
        .setxattr       = generic_setxattr,
index fa70848afa8f4c403e988d058966db0b6af456b6..cd95d14f9cc262503479c606401ce32e4f495e7b 100644 (file)
@@ -292,16 +292,21 @@ bad_block:        ext2_error(inode->i_sb, "ext2_xattr_list",
                const struct xattr_handler *handler =
                        ext2_xattr_handler(entry->e_name_index);
 
-               if (handler) {
-                       size_t size = handler->list(handler, dentry, buffer,
-                                                   rest, entry->e_name,
-                                                   entry->e_name_len);
+               if (handler && (!handler->list || handler->list(dentry))) {
+                       const char *prefix = handler->prefix ?: handler->name;
+                       size_t prefix_len = strlen(prefix);
+                       size_t size = prefix_len + entry->e_name_len + 1;
+
                        if (buffer) {
                                if (size > rest) {
                                        error = -ERANGE;
                                        goto cleanup;
                                }
-                               buffer += size;
+                               memcpy(buffer, prefix, prefix_len);
+                               buffer += prefix_len;
+                               memcpy(buffer, entry->e_name, entry->e_name_len);
+                               buffer += entry->e_name_len;
+                               *buffer++ = 0;
                        }
                        rest -= size;
                }
index dfb08750370d85d71a7fc89bef68345229b7740d..ba97f243b0504498d16bde66b55b653d76a8f175 100644 (file)
@@ -7,29 +7,11 @@
 #include <linux/security.h>
 #include "xattr.h"
 
-static size_t
-ext2_xattr_security_list(const struct xattr_handler *handler,
-                        struct dentry *dentry, char *list, size_t list_size,
-                        const char *name, size_t name_len)
-{
-       const int prefix_len = XATTR_SECURITY_PREFIX_LEN;
-       const size_t total_len = prefix_len + name_len + 1;
-
-       if (list && total_len <= list_size) {
-               memcpy(list, XATTR_SECURITY_PREFIX, prefix_len);
-               memcpy(list+prefix_len, name, name_len);
-               list[prefix_len + name_len] = '\0';
-       }
-       return total_len;
-}
-
 static int
 ext2_xattr_security_get(const struct xattr_handler *handler,
                        struct dentry *dentry, const char *name,
                        void *buffer, size_t size)
 {
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
        return ext2_xattr_get(d_inode(dentry), EXT2_XATTR_INDEX_SECURITY, name,
                              buffer, size);
 }
@@ -39,8 +21,6 @@ ext2_xattr_security_set(const struct xattr_handler *handler,
                        struct dentry *dentry, const char *name,
                        const void *value, size_t size, int flags)
 {
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
        return ext2_xattr_set(d_inode(dentry), EXT2_XATTR_INDEX_SECURITY, name,
                              value, size, flags);
 }
@@ -71,7 +51,6 @@ ext2_init_security(struct inode *inode, struct inode *dir,
 
 const struct xattr_handler ext2_xattr_security_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
-       .list   = ext2_xattr_security_list,
        .get    = ext2_xattr_security_get,
        .set    = ext2_xattr_security_set,
 };
index 3150dd3a78595084d0a6bfd5916f86272e68303a..2c94d1930626269e0e4c2155ae924cd8b30e9e41 100644 (file)
@@ -8,23 +8,10 @@
 #include "ext2.h"
 #include "xattr.h"
 
-static size_t
-ext2_xattr_trusted_list(const struct xattr_handler *handler,
-                       struct dentry *dentry, char *list, size_t list_size,
-                       const char *name, size_t name_len)
+static bool
+ext2_xattr_trusted_list(struct dentry *dentry)
 {
-       const int prefix_len = XATTR_TRUSTED_PREFIX_LEN;
-       const size_t total_len = prefix_len + name_len + 1;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return 0;
-
-       if (list && total_len <= list_size) {
-               memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len);
-               memcpy(list+prefix_len, name, name_len);
-               list[prefix_len + name_len] = '\0';
-       }
-       return total_len;
+       return capable(CAP_SYS_ADMIN);
 }
 
 static int
@@ -32,8 +19,6 @@ ext2_xattr_trusted_get(const struct xattr_handler *handler,
                       struct dentry *dentry, const char *name,
                       void *buffer, size_t size)
 {
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
        return ext2_xattr_get(d_inode(dentry), EXT2_XATTR_INDEX_TRUSTED, name,
                              buffer, size);
 }
@@ -43,8 +28,6 @@ ext2_xattr_trusted_set(const struct xattr_handler *handler,
                       struct dentry *dentry, const char *name,
                       const void *value, size_t size, int flags)
 {
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
        return ext2_xattr_set(d_inode(dentry), EXT2_XATTR_INDEX_TRUSTED, name,
                              value, size, flags);
 }
index 339a49bbb8efbee752138fc600399c712d1b98a7..72a2a96d677f9ed455e0ac92cdeaf241b5ab188b 100644 (file)
 #include "ext2.h"
 #include "xattr.h"
 
-static size_t
-ext2_xattr_user_list(const struct xattr_handler *handler,
-                    struct dentry *dentry, char *list, size_t list_size,
-                    const char *name, size_t name_len)
+static bool
+ext2_xattr_user_list(struct dentry *dentry)
 {
-       const size_t prefix_len = XATTR_USER_PREFIX_LEN;
-       const size_t total_len = prefix_len + name_len + 1;
-
-       if (!test_opt(dentry->d_sb, XATTR_USER))
-               return 0;
-
-       if (list && total_len <= list_size) {
-               memcpy(list, XATTR_USER_PREFIX, prefix_len);
-               memcpy(list+prefix_len, name, name_len);
-               list[prefix_len + name_len] = '\0';
-       }
-       return total_len;
+       return test_opt(dentry->d_sb, XATTR_USER);
 }
 
 static int
@@ -34,8 +21,6 @@ ext2_xattr_user_get(const struct xattr_handler *handler,
                    struct dentry *dentry, const char *name,
                    void *buffer, size_t size)
 {
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
        if (!test_opt(dentry->d_sb, XATTR_USER))
                return -EOPNOTSUPP;
        return ext2_xattr_get(d_inode(dentry), EXT2_XATTR_INDEX_USER,
@@ -47,8 +32,6 @@ ext2_xattr_user_set(const struct xattr_handler *handler,
                    struct dentry *dentry, const char *name,
                    const void *value, size_t size, int flags)
 {
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
        if (!test_opt(dentry->d_sb, XATTR_USER))
                return -EOPNOTSUPP;
 
index ea433a7f4bca21511ba84fbfbe52f71883680661..b3bd912df6bfaf475f9304eba7fb1b9ce6368e87 100644 (file)
@@ -4283,6 +4283,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
                        inode->i_op = &ext4_symlink_inode_operations;
                        ext4_set_aops(inode);
                }
+               inode_nohighmem(inode);
        } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
              S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
                inode->i_op = &ext4_special_inode_operations;
index a969ab39f3026187242dbea0881d5ebdb991d978..f27e0c2598c59edb5685c27310c2766d0860838d 100644 (file)
@@ -3132,6 +3132,7 @@ static int ext4_symlink(struct inode *dir,
        if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
                if (!encryption_required)
                        inode->i_op = &ext4_symlink_inode_operations;
+               inode_nohighmem(inode);
                ext4_set_aops(inode);
                /*
                 * We cannot call page_symlink() with transaction started
index e8e7af62ac95fc4e5268c32df1bc496a337202a7..6f7ee30a89ce806ec0e4fbe27d7a0538ccd1f5c7 100644 (file)
 #include "xattr.h"
 
 #ifdef CONFIG_EXT4_FS_ENCRYPTION
-static const char *ext4_encrypted_follow_link(struct dentry *dentry, void **cookie)
+static const char *ext4_encrypted_get_link(struct dentry *dentry,
+                                          struct inode *inode,
+                                          struct delayed_call *done)
 {
        struct page *cpage = NULL;
        char *caddr, *paddr = NULL;
        struct ext4_str cstr, pstr;
-       struct inode *inode = d_inode(dentry);
        struct ext4_encrypted_symlink_data *sd;
        loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1);
        int res;
        u32 plen, max_size = inode->i_sb->s_blocksize;
 
+       if (!dentry)
+               return ERR_PTR(-ECHILD);
+
        res = ext4_get_encryption_info(inode);
        if (res)
                return ERR_PTR(res);
@@ -45,7 +49,7 @@ static const char *ext4_encrypted_follow_link(struct dentry *dentry, void **cook
                cpage = read_mapping_page(inode->i_mapping, 0, NULL);
                if (IS_ERR(cpage))
                        return ERR_CAST(cpage);
-               caddr = kmap(cpage);
+               caddr = page_address(cpage);
                caddr[size] = 0;
        }
 
@@ -75,24 +79,20 @@ static const char *ext4_encrypted_follow_link(struct dentry *dentry, void **cook
        /* Null-terminate the name */
        if (res <= plen)
                paddr[res] = '\0';
-       if (cpage) {
-               kunmap(cpage);
+       if (cpage)
                page_cache_release(cpage);
-       }
-       return *cookie = paddr;
+       set_delayed_call(done, kfree_link, paddr);
+       return paddr;
 errout:
-       if (cpage) {
-               kunmap(cpage);
+       if (cpage)
                page_cache_release(cpage);
-       }
        kfree(paddr);
        return ERR_PTR(res);
 }
 
 const struct inode_operations ext4_encrypted_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = ext4_encrypted_follow_link,
-       .put_link       = kfree_put_link,
+       .get_link       = ext4_encrypted_get_link,
        .setattr        = ext4_setattr,
        .setxattr       = generic_setxattr,
        .getxattr       = generic_getxattr,
@@ -103,8 +103,7 @@ const struct inode_operations ext4_encrypted_symlink_inode_operations = {
 
 const struct inode_operations ext4_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = page_follow_link_light,
-       .put_link       = page_put_link,
+       .get_link       = page_get_link,
        .setattr        = ext4_setattr,
        .setxattr       = generic_setxattr,
        .getxattr       = generic_getxattr,
@@ -114,7 +113,7 @@ const struct inode_operations ext4_symlink_inode_operations = {
 
 const struct inode_operations ext4_fast_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = simple_follow_link,
+       .get_link       = simple_get_link,
        .setattr        = ext4_setattr,
        .setxattr       = generic_setxattr,
        .getxattr       = generic_getxattr,
index 6b6b3e751f8c77ebc9089c412f9019b4774a4301..e9b9afdd1d964ab3bfca8dcc55e26976c5f8b45e 100644 (file)
@@ -404,19 +404,24 @@ ext4_xattr_list_entries(struct dentry *dentry, struct ext4_xattr_entry *entry,
                const struct xattr_handler *handler =
                        ext4_xattr_handler(entry->e_name_index);
 
-               if (handler) {
-                       size_t size = handler->list(handler, dentry, buffer,
-                                                   rest, entry->e_name,
-                                                   entry->e_name_len);
+               if (handler && (!handler->list || handler->list(dentry))) {
+                       const char *prefix = handler->prefix ?: handler->name;
+                       size_t prefix_len = strlen(prefix);
+                       size_t size = prefix_len + entry->e_name_len + 1;
+
                        if (buffer) {
                                if (size > rest)
                                        return -ERANGE;
-                               buffer += size;
+                               memcpy(buffer, prefix, prefix_len);
+                               buffer += prefix_len;
+                               memcpy(buffer, entry->e_name, entry->e_name_len);
+                               buffer += entry->e_name_len;
+                               *buffer++ = 0;
                        }
                        rest -= size;
                }
        }
-       return buffer_size - rest;
+       return buffer_size - rest;  /* total size */
 }
 
 static int
index 36f4c1a84c218307a1ae5c7e5c9805747025cf38..3e81bdca071a6776fa16422bdd9006ddb2abf1e6 100644 (file)
 #include "ext4.h"
 #include "xattr.h"
 
-static size_t
-ext4_xattr_security_list(const struct xattr_handler *handler,
-                        struct dentry *dentry, char *list, size_t list_size,
-                        const char *name, size_t name_len)
-{
-       const size_t prefix_len = sizeof(XATTR_SECURITY_PREFIX)-1;
-       const size_t total_len = prefix_len + name_len + 1;
-
-
-       if (list && total_len <= list_size) {
-               memcpy(list, XATTR_SECURITY_PREFIX, prefix_len);
-               memcpy(list+prefix_len, name, name_len);
-               list[prefix_len + name_len] = '\0';
-       }
-       return total_len;
-}
-
 static int
 ext4_xattr_security_get(const struct xattr_handler *handler,
                        struct dentry *dentry, const char *name,
                        void *buffer, size_t size)
 {
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
        return ext4_xattr_get(d_inode(dentry), EXT4_XATTR_INDEX_SECURITY,
                              name, buffer, size);
 }
@@ -44,8 +25,6 @@ ext4_xattr_security_set(const struct xattr_handler *handler,
                        struct dentry *dentry, const char *name,
                        const void *value, size_t size, int flags)
 {
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
        return ext4_xattr_set(d_inode(dentry), EXT4_XATTR_INDEX_SECURITY,
                              name, value, size, flags);
 }
@@ -79,7 +58,6 @@ ext4_init_security(handle_t *handle, struct inode *inode, struct inode *dir,
 
 const struct xattr_handler ext4_xattr_security_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
-       .list   = ext4_xattr_security_list,
        .get    = ext4_xattr_security_get,
        .set    = ext4_xattr_security_set,
 };
index 4880890533424ca63e67fc8ce0536254ce669028..2a3c6f9b8cb8452115aaaa4fadb786d3a2ca2612 100644 (file)
 #include "ext4.h"
 #include "xattr.h"
 
-static size_t
-ext4_xattr_trusted_list(const struct xattr_handler *handler,
-                       struct dentry *dentry, char *list, size_t list_size,
-                       const char *name, size_t name_len)
+static bool
+ext4_xattr_trusted_list(struct dentry *dentry)
 {
-       const size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN;
-       const size_t total_len = prefix_len + name_len + 1;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return 0;
-
-       if (list && total_len <= list_size) {
-               memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len);
-               memcpy(list+prefix_len, name, name_len);
-               list[prefix_len + name_len] = '\0';
-       }
-       return total_len;
+       return capable(CAP_SYS_ADMIN);
 }
 
 static int
@@ -36,8 +23,6 @@ ext4_xattr_trusted_get(const struct xattr_handler *handler,
                       struct dentry *dentry, const char *name, void *buffer,
                       size_t size)
 {
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
        return ext4_xattr_get(d_inode(dentry), EXT4_XATTR_INDEX_TRUSTED,
                              name, buffer, size);
 }
@@ -47,8 +32,6 @@ ext4_xattr_trusted_set(const struct xattr_handler *handler,
                       struct dentry *dentry, const char *name,
                       const void *value, size_t size, int flags)
 {
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
        return ext4_xattr_set(d_inode(dentry), EXT4_XATTR_INDEX_TRUSTED,
                              name, value, size, flags);
 }
index d2dec33640620024aae408cdb394f4689d23dd87..d152f431e432affe701e4c0729bb8e97517f4075 100644 (file)
 #include "ext4.h"
 #include "xattr.h"
 
-static size_t
-ext4_xattr_user_list(const struct xattr_handler *handler,
-                    struct dentry *dentry, char *list, size_t list_size,
-                    const char *name, size_t name_len)
+static bool
+ext4_xattr_user_list(struct dentry *dentry)
 {
-       const size_t prefix_len = XATTR_USER_PREFIX_LEN;
-       const size_t total_len = prefix_len + name_len + 1;
-
-       if (!test_opt(dentry->d_sb, XATTR_USER))
-               return 0;
-
-       if (list && total_len <= list_size) {
-               memcpy(list, XATTR_USER_PREFIX, prefix_len);
-               memcpy(list+prefix_len, name, name_len);
-               list[prefix_len + name_len] = '\0';
-       }
-       return total_len;
+       return test_opt(dentry->d_sb, XATTR_USER);
 }
 
 static int
@@ -35,8 +22,6 @@ ext4_xattr_user_get(const struct xattr_handler *handler,
                    struct dentry *dentry, const char *name,
                    void *buffer, size_t size)
 {
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
        if (!test_opt(dentry->d_sb, XATTR_USER))
                return -EOPNOTSUPP;
        return ext4_xattr_get(d_inode(dentry), EXT4_XATTR_INDEX_USER,
@@ -48,8 +33,6 @@ ext4_xattr_user_set(const struct xattr_handler *handler,
                    struct dentry *dentry, const char *name,
                    const void *value, size_t size, int flags)
 {
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
        if (!test_opt(dentry->d_sb, XATTR_USER))
                return -EOPNOTSUPP;
        return ext4_xattr_set(d_inode(dentry), EXT4_XATTR_INDEX_USER,
index 97e20decacb4e17677fc3c43cfb5d45a6ab290bc..5528801a5baf3a13a75ffd16c831c1d7b1a650f4 100644 (file)
@@ -202,6 +202,7 @@ make_now:
                        inode->i_op = &f2fs_encrypted_symlink_inode_operations;
                else
                        inode->i_op = &f2fs_symlink_inode_operations;
+               inode_nohighmem(inode);
                inode->i_mapping->a_ops = &f2fs_dblock_aops;
        } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
                        S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
index 2c32110f9fc082408b318cac2142602ab7888a9e..e7587fce1b8065bf80f35571d4a2c25b40b7c265 100644 (file)
@@ -315,12 +315,15 @@ fail:
        return err;
 }
 
-static const char *f2fs_follow_link(struct dentry *dentry, void **cookie)
+static const char *f2fs_get_link(struct dentry *dentry,
+                                struct inode *inode,
+                                struct delayed_call *done)
 {
-       const char *link = page_follow_link_light(dentry, cookie);
+       const char *link = page_get_link(dentry, inode, done);
        if (!IS_ERR(link) && !*link) {
                /* this is broken symlink case */
-               page_put_link(NULL, *cookie);
+               do_delayed_call(done);
+               clear_delayed_call(done);
                link = ERR_PTR(-ENOENT);
        }
        return link;
@@ -351,6 +354,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
                inode->i_op = &f2fs_encrypted_symlink_inode_operations;
        else
                inode->i_op = &f2fs_symlink_inode_operations;
+       inode_nohighmem(inode);
        inode->i_mapping->a_ops = &f2fs_dblock_aops;
 
        f2fs_lock_op(sbi);
@@ -923,18 +927,22 @@ static int f2fs_rename2(struct inode *old_dir, struct dentry *old_dentry,
 }
 
 #ifdef CONFIG_F2FS_FS_ENCRYPTION
-static const char *f2fs_encrypted_follow_link(struct dentry *dentry, void **cookie)
+static const char *f2fs_encrypted_get_link(struct dentry *dentry,
+                                          struct inode *inode,
+                                          struct delayed_call *done)
 {
        struct page *cpage = NULL;
        char *caddr, *paddr = NULL;
        struct f2fs_str cstr;
        struct f2fs_str pstr = FSTR_INIT(NULL, 0);
-       struct inode *inode = d_inode(dentry);
        struct f2fs_encrypted_symlink_data *sd;
        loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1);
        u32 max_size = inode->i_sb->s_blocksize;
        int res;
 
+       if (!dentry)
+               return ERR_PTR(-ECHILD);
+
        res = f2fs_get_encryption_info(inode);
        if (res)
                return ERR_PTR(res);
@@ -942,7 +950,7 @@ static const char *f2fs_encrypted_follow_link(struct dentry *dentry, void **cook
        cpage = read_mapping_page(inode->i_mapping, 0, NULL);
        if (IS_ERR(cpage))
                return ERR_CAST(cpage);
-       caddr = kmap(cpage);
+       caddr = page_address(cpage);
        caddr[size] = 0;
 
        /* Symlink is encrypted */
@@ -982,21 +990,19 @@ static const char *f2fs_encrypted_follow_link(struct dentry *dentry, void **cook
        /* Null-terminate the name */
        paddr[res] = '\0';
 
-       kunmap(cpage);
        page_cache_release(cpage);
-       return *cookie = paddr;
+       set_delayed_call(done, kfree_link, paddr);
+       return paddr;
 errout:
        kfree(cstr.name);
        f2fs_fname_crypto_free_buffer(&pstr);
-       kunmap(cpage);
        page_cache_release(cpage);
        return ERR_PTR(res);
 }
 
 const struct inode_operations f2fs_encrypted_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = f2fs_encrypted_follow_link,
-       .put_link       = kfree_put_link,
+       .get_link       = f2fs_encrypted_get_link,
        .getattr        = f2fs_getattr,
        .setattr        = f2fs_setattr,
        .setxattr       = generic_setxattr,
@@ -1031,8 +1037,7 @@ const struct inode_operations f2fs_dir_inode_operations = {
 
 const struct inode_operations f2fs_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = f2fs_follow_link,
-       .put_link       = page_put_link,
+       .get_link       = f2fs_get_link,
        .getattr        = f2fs_getattr,
        .setattr        = f2fs_setattr,
 #ifdef CONFIG_F2FS_FS_XATTR
index 862368a32e5354c3d9458f39f933e87d05c3e287..036952a945faf918378dae2dc25a144330d14864 100644 (file)
 #include "f2fs.h"
 #include "xattr.h"
 
-static size_t f2fs_xattr_generic_list(const struct xattr_handler *handler,
-               struct dentry *dentry, char *list, size_t list_size,
-               const char *name, size_t len)
-{
-       struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
-       int total_len, prefix_len;
-
-       switch (handler->flags) {
-       case F2FS_XATTR_INDEX_USER:
-               if (!test_opt(sbi, XATTR_USER))
-                       return -EOPNOTSUPP;
-               break;
-       case F2FS_XATTR_INDEX_TRUSTED:
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               break;
-       case F2FS_XATTR_INDEX_SECURITY:
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       prefix_len = strlen(handler->prefix);
-       total_len = prefix_len + len + 1;
-       if (list && total_len <= list_size) {
-               memcpy(list, handler->prefix, prefix_len);
-               memcpy(list + prefix_len, name, len);
-               list[prefix_len + len] = '\0';
-       }
-       return total_len;
-}
-
 static int f2fs_xattr_generic_get(const struct xattr_handler *handler,
                struct dentry *dentry, const char *name, void *buffer,
                size_t size)
@@ -77,8 +45,6 @@ static int f2fs_xattr_generic_get(const struct xattr_handler *handler,
        default:
                return -EINVAL;
        }
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
        return f2fs_getxattr(d_inode(dentry), handler->flags, name,
                             buffer, size, NULL);
 }
@@ -103,24 +69,20 @@ static int f2fs_xattr_generic_set(const struct xattr_handler *handler,
        default:
                return -EINVAL;
        }
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
-
        return f2fs_setxattr(d_inode(dentry), handler->flags, name,
                                        value, size, NULL, flags);
 }
 
-static size_t f2fs_xattr_advise_list(const struct xattr_handler *handler,
-               struct dentry *dentry, char *list, size_t list_size,
-               const char *name, size_t len)
+static bool f2fs_xattr_user_list(struct dentry *dentry)
 {
-       const char *xname = F2FS_SYSTEM_ADVISE_PREFIX;
-       size_t size;
+       struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
 
-       size = strlen(xname) + 1;
-       if (list && size <= list_size)
-               memcpy(list, xname, size);
-       return size;
+       return test_opt(sbi, XATTR_USER);
+}
+
+static bool f2fs_xattr_trusted_list(struct dentry *dentry)
+{
+       return capable(CAP_SYS_ADMIN);
 }
 
 static int f2fs_xattr_advise_get(const struct xattr_handler *handler,
@@ -129,9 +91,6 @@ static int f2fs_xattr_advise_get(const struct xattr_handler *handler,
 {
        struct inode *inode = d_inode(dentry);
 
-       if (strcmp(name, "") != 0)
-               return -EINVAL;
-
        if (buffer)
                *((char *)buffer) = F2FS_I(inode)->i_advise;
        return sizeof(char);
@@ -143,8 +102,6 @@ static int f2fs_xattr_advise_set(const struct xattr_handler *handler,
 {
        struct inode *inode = d_inode(dentry);
 
-       if (strcmp(name, "") != 0)
-               return -EINVAL;
        if (!inode_owner_or_capable(inode))
                return -EPERM;
        if (value == NULL)
@@ -183,7 +140,7 @@ int f2fs_init_security(struct inode *inode, struct inode *dir,
 const struct xattr_handler f2fs_xattr_user_handler = {
        .prefix = XATTR_USER_PREFIX,
        .flags  = F2FS_XATTR_INDEX_USER,
-       .list   = f2fs_xattr_generic_list,
+       .list   = f2fs_xattr_user_list,
        .get    = f2fs_xattr_generic_get,
        .set    = f2fs_xattr_generic_set,
 };
@@ -191,15 +148,14 @@ const struct xattr_handler f2fs_xattr_user_handler = {
 const struct xattr_handler f2fs_xattr_trusted_handler = {
        .prefix = XATTR_TRUSTED_PREFIX,
        .flags  = F2FS_XATTR_INDEX_TRUSTED,
-       .list   = f2fs_xattr_generic_list,
+       .list   = f2fs_xattr_trusted_list,
        .get    = f2fs_xattr_generic_get,
        .set    = f2fs_xattr_generic_set,
 };
 
 const struct xattr_handler f2fs_xattr_advise_handler = {
-       .prefix = F2FS_SYSTEM_ADVISE_PREFIX,
+       .name   = F2FS_SYSTEM_ADVISE_NAME,
        .flags  = F2FS_XATTR_INDEX_ADVISE,
-       .list   = f2fs_xattr_advise_list,
        .get    = f2fs_xattr_advise_get,
        .set    = f2fs_xattr_advise_set,
 };
@@ -207,7 +163,6 @@ const struct xattr_handler f2fs_xattr_advise_handler = {
 const struct xattr_handler f2fs_xattr_security_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
        .flags  = F2FS_XATTR_INDEX_SECURITY,
-       .list   = f2fs_xattr_generic_list,
        .get    = f2fs_xattr_generic_get,
        .set    = f2fs_xattr_generic_set,
 };
@@ -455,20 +410,27 @@ ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
        list_for_each_xattr(entry, base_addr) {
                const struct xattr_handler *handler =
                        f2fs_xattr_handler(entry->e_name_index);
+               const char *prefix;
+               size_t prefix_len;
                size_t size;
 
-               if (!handler)
+               if (!handler || (handler->list && !handler->list(dentry)))
                        continue;
 
-               size = handler->list(handler, dentry, buffer, rest,
-                                    entry->e_name, entry->e_name_len);
-               if (buffer && size > rest) {
-                       error = -ERANGE;
-                       goto cleanup;
+               prefix = handler->prefix ?: handler->name;
+               prefix_len = strlen(prefix);
+               size = prefix_len + entry->e_name_len + 1;
+               if (buffer) {
+                       if (size > rest) {
+                               error = -ERANGE;
+                               goto cleanup;
+                       }
+                       memcpy(buffer, prefix, prefix_len);
+                       buffer += prefix_len;
+                       memcpy(buffer, entry->e_name, entry->e_name_len);
+                       buffer += entry->e_name_len;
+                       *buffer++ = 0;
                }
-
-               if (buffer)
-                       buffer += size;
                rest -= size;
        }
        error = buffer_size - rest;
index 71a7100d5492e830125b32f560c5021bb6ada30a..79dccc8252ddb8f36a14b1d9c69b216e138ca0b4 100644 (file)
@@ -27,7 +27,7 @@
 #define F2FS_XATTR_REFCOUNT_MAX         1024
 
 /* Name indexes */
-#define F2FS_SYSTEM_ADVISE_PREFIX              "system.advise"
+#define F2FS_SYSTEM_ADVISE_NAME                        "system.advise"
 #define F2FS_XATTR_INDEX_USER                  1
 #define F2FS_XATTR_INDEX_POSIX_ACL_ACCESS      2
 #define F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT     3
index ef73ed674a27162917845b0507269bdf86b273da..3e2ccade61edb4e4a9a7d27d9229d5ed37175dbc 100644 (file)
@@ -326,6 +326,7 @@ vxfs_iget(struct super_block *sbp, ino_t ino)
        } else if (S_ISLNK(ip->i_mode)) {
                if (!VXFS_ISIMMED(vip)) {
                        ip->i_op = &page_symlink_inode_operations;
+                       inode_nohighmem(ip);
                        ip->i_mapping->a_ops = &vxfs_aops;
                } else {
                        ip->i_op = &simple_symlink_inode_operations;
index 5e2e08712d3ba614a46687d5688fc2f01cd835be..712601f299b8a1436d69f0a31362ab57032f24b7 100644 (file)
@@ -1365,15 +1365,19 @@ static int fuse_readdir(struct file *file, struct dir_context *ctx)
        return err;
 }
 
-static const char *fuse_follow_link(struct dentry *dentry, void **cookie)
+static const char *fuse_get_link(struct dentry *dentry,
+                                struct inode *inode,
+                                struct delayed_call *done)
 {
-       struct inode *inode = d_inode(dentry);
        struct fuse_conn *fc = get_fuse_conn(inode);
        FUSE_ARGS(args);
        char *link;
        ssize_t ret;
 
-       link = (char *) __get_free_page(GFP_KERNEL);
+       if (!dentry)
+               return ERR_PTR(-ECHILD);
+
+       link = kmalloc(PAGE_SIZE, GFP_KERNEL);
        if (!link)
                return ERR_PTR(-ENOMEM);
 
@@ -1385,11 +1389,11 @@ static const char *fuse_follow_link(struct dentry *dentry, void **cookie)
        args.out.args[0].value = link;
        ret = fuse_simple_request(fc, &args);
        if (ret < 0) {
-               free_page((unsigned long) link);
+               kfree(link);
                link = ERR_PTR(ret);
        } else {
                link[ret] = '\0';
-               *cookie = link;
+               set_delayed_call(done, kfree_link, link);
        }
        fuse_invalidate_atime(inode);
        return link;
@@ -1909,8 +1913,7 @@ static const struct inode_operations fuse_common_inode_operations = {
 
 static const struct inode_operations fuse_symlink_inode_operations = {
        .setattr        = fuse_setattr,
-       .follow_link    = fuse_follow_link,
-       .put_link       = free_page_put_link,
+       .get_link       = fuse_get_link,
        .readlink       = generic_readlink,
        .getattr        = fuse_getattr,
        .setxattr       = fuse_setxattr,
index 1be3b061c05c921f60ddfebcce809875fe8de662..791932617d1a39972aee07a87ed35e8597e6b7bd 100644 (file)
@@ -31,9 +31,9 @@ static const char *gfs2_acl_name(int type)
 {
        switch (type) {
        case ACL_TYPE_ACCESS:
-               return GFS2_POSIX_ACL_ACCESS;
+               return XATTR_POSIX_ACL_ACCESS;
        case ACL_TYPE_DEFAULT:
-               return GFS2_POSIX_ACL_DEFAULT;
+               return XATTR_POSIX_ACL_DEFAULT;
        }
        return NULL;
 }
index 2d65ec4cd4bef60b87c0291c9ef84ce3abcf65a2..3af4f407a483e53bf3f5fae9df334204758bb39a 100644 (file)
@@ -12,8 +12,6 @@
 
 #include "incore.h"
 
-#define GFS2_POSIX_ACL_ACCESS          "posix_acl_access"
-#define GFS2_POSIX_ACL_DEFAULT         "posix_acl_default"
 #define GFS2_ACL_MAX_ENTRIES(sdp) ((300 << (sdp)->sd_sb.sb_bsize_shift) >> 12)
 
 extern struct posix_acl *gfs2_get_acl(struct inode *inode, int type);
index 063fdfcf82758a0c77f4cc44fe7b1f873b3cbb21..1bae189f32453c5e1bb46c11547768974c49c9ba 100644 (file)
@@ -1712,24 +1712,30 @@ static int gfs2_rename2(struct inode *odir, struct dentry *odentry,
 }
 
 /**
- * gfs2_follow_link - Follow a symbolic link
+ * gfs2_get_link - Follow a symbolic link
  * @dentry: The dentry of the link
- * @nd: Data that we pass to vfs_follow_link()
+ * @inode: The inode of the link
+ * @done: destructor for return value
  *
  * This can handle symlinks of any size.
  *
  * Returns: 0 on success or error code
  */
 
-static const char *gfs2_follow_link(struct dentry *dentry, void **cookie)
+static const char *gfs2_get_link(struct dentry *dentry,
+                                struct inode *inode,
+                                struct delayed_call *done)
 {
-       struct gfs2_inode *ip = GFS2_I(d_inode(dentry));
+       struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_holder i_gh;
        struct buffer_head *dibh;
        unsigned int size;
        char *buf;
        int error;
 
+       if (!dentry)
+               return ERR_PTR(-ECHILD);
+
        gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh);
        error = gfs2_glock_nq(&i_gh);
        if (error) {
@@ -1759,7 +1765,7 @@ static const char *gfs2_follow_link(struct dentry *dentry, void **cookie)
 out:
        gfs2_glock_dq_uninit(&i_gh);
        if (!IS_ERR(buf))
-               *cookie = buf;
+               set_delayed_call(done, kfree_link, buf);
        return buf;
 }
 
@@ -2132,8 +2138,7 @@ const struct inode_operations gfs2_dir_iops = {
 
 const struct inode_operations gfs2_symlink_iops = {
        .readlink = generic_readlink,
-       .follow_link = gfs2_follow_link,
-       .put_link = kfree_put_link,
+       .get_link = gfs2_get_link,
        .permission = gfs2_permission,
        .setattr = gfs2_setattr,
        .getattr = gfs2_getattr,
index 53ce76a374fe7313314eafd274b8a58db81b52d0..84f2d81fe4512d18c8b1b4bc2df41bf052bd9c52 100644 (file)
@@ -1237,56 +1237,6 @@ static int gfs2_xattr_set(const struct xattr_handler *handler,
                                size, flags, handler->flags);
 }
 
-
-static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip,
-                                 struct gfs2_ea_header *ea, char *data)
-{
-       struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-       unsigned int amount = GFS2_EA_DATA_LEN(ea);
-       unsigned int nptrs = DIV_ROUND_UP(amount, sdp->sd_jbsize);
-       int ret;
-
-       ret = gfs2_trans_begin(sdp, nptrs + RES_DINODE, 0);
-       if (ret)
-               return ret;
-
-       ret = gfs2_iter_unstuffed(ip, ea, data, NULL);
-       gfs2_trans_end(sdp);
-
-       return ret;
-}
-
-int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
-{
-       struct inode *inode = &ip->i_inode;
-       struct gfs2_sbd *sdp = GFS2_SB(inode);
-       struct gfs2_ea_location el;
-       int error;
-
-       error = gfs2_ea_find(ip, GFS2_EATYPE_SYS, GFS2_POSIX_ACL_ACCESS, &el);
-       if (error)
-               return error;
-
-       if (GFS2_EA_IS_STUFFED(el.el_ea)) {
-               error = gfs2_trans_begin(sdp, RES_DINODE + RES_EATTR, 0);
-               if (error == 0) {
-                       gfs2_trans_add_meta(ip->i_gl, el.el_bh);
-                       memcpy(GFS2_EA2DATA(el.el_ea), data,
-                              GFS2_EA_DATA_LEN(el.el_ea));
-               }
-       } else {
-               error = ea_acl_chmod_unstuffed(ip, el.el_ea, data);
-       }
-
-       brelse(el.el_bh);
-       if (error)
-               return error;
-
-       error = gfs2_setattr_simple(inode, attr);
-       gfs2_trans_end(sdp);
-       return error;
-}
-
 static int ea_dealloc_indirect(struct gfs2_inode *ip)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
index d392f8358f2ff0e47687aee4a1cf1b664d5b1589..2d887c88eb49852445e432ed4c3d11d518411455 100644 (file)
@@ -62,6 +62,5 @@ extern int gfs2_ea_dealloc(struct gfs2_inode *ip);
 /* Exported to acl.c */
 
 extern int gfs2_xattr_acl_get(struct gfs2_inode *ip, const char *name, char **data);
-extern int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data);
 
 #endif /* __EATTR_DOT_H__ */
index 6dd107d7421ec05368845846d6a9cd9f558e9d23..19b33f8151f1ab2cb0957b7e5772ff1206659aad 100644 (file)
@@ -403,6 +403,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode)
        } else if (S_ISLNK(inode->i_mode)) {
                sbi->file_count++;
                inode->i_op = &page_symlink_inode_operations;
+               inode_nohighmem(inode);
                inode->i_mapping->a_ops = &hfsplus_aops;
                hip->clump_blocks = 1;
        } else
@@ -526,6 +527,7 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
                        inode->i_mapping->a_ops = &hfsplus_aops;
                } else if (S_ISLNK(inode->i_mode)) {
                        inode->i_op = &page_symlink_inode_operations;
+                       inode_nohighmem(inode);
                        inode->i_mapping->a_ops = &hfsplus_aops;
                } else {
                        init_special_inode(inode, inode->i_mode,
index df0c9af68d05ef0df5a127d53562677bc8a2d882..afb33eda6d7dbae7ea5dab4d19b1edc401db151a 100644 (file)
@@ -21,10 +21,10 @@ struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type)
 
        switch (type) {
        case ACL_TYPE_ACCESS:
-               xattr_name = POSIX_ACL_XATTR_ACCESS;
+               xattr_name = XATTR_NAME_POSIX_ACL_ACCESS;
                break;
        case ACL_TYPE_DEFAULT:
-               xattr_name = POSIX_ACL_XATTR_DEFAULT;
+               xattr_name = XATTR_NAME_POSIX_ACL_DEFAULT;
                break;
        default:
                return ERR_PTR(-EINVAL);
@@ -66,7 +66,7 @@ int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
 
        switch (type) {
        case ACL_TYPE_ACCESS:
-               xattr_name = POSIX_ACL_XATTR_ACCESS;
+               xattr_name = XATTR_NAME_POSIX_ACL_ACCESS;
                if (acl) {
                        err = posix_acl_equiv_mode(acl, &inode->i_mode);
                        if (err < 0)
@@ -76,7 +76,7 @@ int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
                break;
 
        case ACL_TYPE_DEFAULT:
-               xattr_name = POSIX_ACL_XATTR_DEFAULT;
+               xattr_name = XATTR_NAME_POSIX_ACL_DEFAULT;
                if (!S_ISDIR(inode->i_mode))
                        return acl ? -EACCES : 0;
                break;
index e41a010cd89ca6ca8e76dec51d2d8914782e1db6..ab01530b4930f4bf49aec02659a8fd903ee4a047 100644 (file)
@@ -431,9 +431,6 @@ int hfsplus_setxattr(struct dentry *dentry, const char *name,
        char *xattr_name;
        int res;
 
-       if (!strcmp(name, ""))
-               return -EINVAL;
-
        xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1,
                GFP_KERNEL);
        if (!xattr_name)
@@ -589,9 +586,6 @@ ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
        int res;
        char *xattr_name;
 
-       if (!strcmp(name, ""))
-               return -EINVAL;
-
        xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1,
                             GFP_KERNEL);
        if (!xattr_name)
@@ -853,9 +847,6 @@ static int hfsplus_osx_getxattr(const struct xattr_handler *handler,
                                struct dentry *dentry, const char *name,
                                void *buffer, size_t size)
 {
-       if (!strcmp(name, ""))
-               return -EINVAL;
-
        /*
         * Don't allow retrieving properly prefixed attributes
         * by prepending them with "osx."
@@ -876,9 +867,6 @@ static int hfsplus_osx_setxattr(const struct xattr_handler *handler,
                                struct dentry *dentry, const char *name,
                                const void *buffer, size_t size, int flags)
 {
-       if (!strcmp(name, ""))
-               return -EINVAL;
-
        /*
         * Don't allow setting properly prefixed attributes
         * by prepending them with "osx."
index 5a7b3229b956ea99fe57b1e88f7d8234b5fee690..f49be23e78aab4a25599fe97839848211432c05a 100644 (file)
@@ -890,9 +890,14 @@ static const struct inode_operations hostfs_dir_iops = {
        .setattr        = hostfs_setattr,
 };
 
-static const char *hostfs_follow_link(struct dentry *dentry, void **cookie)
+static const char *hostfs_get_link(struct dentry *dentry,
+                                  struct inode *inode,
+                                  struct delayed_call *done)
 {
-       char *link = __getname();
+       char *link;
+       if (!dentry)
+               return ERR_PTR(-ECHILD);
+       link = kmalloc(PATH_MAX, GFP_KERNEL);
        if (link) {
                char *path = dentry_name(dentry);
                int err = -ENOMEM;
@@ -903,25 +908,20 @@ static const char *hostfs_follow_link(struct dentry *dentry, void **cookie)
                        __putname(path);
                }
                if (err < 0) {
-                       __putname(link);
+                       kfree(link);
                        return ERR_PTR(err);
                }
        } else {
                return ERR_PTR(-ENOMEM);
        }
 
-       return *cookie = link;
-}
-
-static void hostfs_put_link(struct inode *unused, void *cookie)
-{
-       __putname(cookie);
+       set_delayed_call(done, kfree_link, link);
+       return link;
 }
 
 static const struct inode_operations hostfs_link_iops = {
        .readlink       = generic_readlink,
-       .follow_link    = hostfs_follow_link,
-       .put_link       = hostfs_put_link,
+       .get_link       = hostfs_get_link,
 };
 
 static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
index 933c73780813198b8953376eaa1e595d786e36e1..1f3c6d76200bea68aa7d879955f0351b74b9cdc0 100644 (file)
@@ -77,6 +77,7 @@ void hpfs_read_inode(struct inode *i)
                        kfree(ea);
                        i->i_mode = S_IFLNK | 0777;
                        i->i_op = &page_symlink_inode_operations;
+                       inode_nohighmem(i);
                        i->i_data.a_ops = &hpfs_symlink_aops;
                        set_nlink(i, 1);
                        i->i_size = ea_size;
index ae4d5a1fa4c9b7f75ce188d8ec80e69d0a820892..506765afa1a3135d1ff9bccc48f06634439fa69e 100644 (file)
@@ -332,6 +332,7 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy
        result->i_blocks = 1;
        set_nlink(result, 1);
        result->i_size = strlen(symlink);
+       inode_nohighmem(result);
        result->i_op = &page_symlink_inode_operations;
        result->i_data.a_ops = &hpfs_symlink_aops;
 
@@ -500,7 +501,7 @@ out:
 
 static int hpfs_symlink_readpage(struct file *file, struct page *page)
 {
-       char *link = kmap(page);
+       char *link = page_address(page);
        struct inode *i = page->mapping->host;
        struct fnode *fnode;
        struct buffer_head *bh;
@@ -516,14 +517,12 @@ static int hpfs_symlink_readpage(struct file *file, struct page *page)
                goto fail;
        hpfs_unlock(i->i_sb);
        SetPageUptodate(page);
-       kunmap(page);
        unlock_page(page);
        return 0;
 
 fail:
        hpfs_unlock(i->i_sb);
        SetPageError(page);
-       kunmap(page);
        unlock_page(page);
        return err;
 }
index de4bdfac0cec36f7f3e1d5cee94ec4aecef3e311..d8f51ee8126b3282156721d2d2639e24d3aa536e 100644 (file)
@@ -760,6 +760,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
                        break;
                case S_IFLNK:
                        inode->i_op = &page_symlink_inode_operations;
+                       inode_nohighmem(inode);
                        break;
                }
                lockdep_annotate_inode_mutex_key(inode);
index 1be5f9003eb38852f68957fcd287cdd5b820b310..5bb85a064ce7fade86383db89c252fe920032279 100644 (file)
@@ -2028,3 +2028,9 @@ void inode_set_flags(struct inode *inode, unsigned int flags,
                                  new_flags) != old_flags));
 }
 EXPORT_SYMBOL(inode_set_flags);
+
+void inode_nohighmem(struct inode *inode)
+{
+       mapping_set_gfp_mask(inode->i_mapping, GFP_USER);
+}
+EXPORT_SYMBOL(inode_nohighmem);
index 71859c4d0b41b820dfe22bca4d30d8863ad86df7..e38c08ca437dcdeed706b1cb0d043fd99d53600c 100644 (file)
@@ -151,3 +151,10 @@ extern void mnt_pin_kill(struct mount *m);
  * fs/nsfs.c
  */
 extern struct dentry_operations ns_dentry_operations;
+
+/*
+ * fs/ioctl.c
+ */
+extern int do_vfs_ioctl(struct file *file, unsigned int fd, unsigned int cmd,
+                   unsigned long arg);
+extern long vfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
index 5d01d2638ca5482cc4edb2144be7ba3fc5f16aa4..41c352e8119381dc646e94e89c18becd40206ec8 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/writeback.h>
 #include <linux/buffer_head.h>
 #include <linux/falloc.h>
+#include "internal.h"
 
 #include <asm/ioctls.h>
 
@@ -32,8 +33,7 @@
  *
  * Returns 0 on success, -errno on error.
  */
-static long vfs_ioctl(struct file *filp, unsigned int cmd,
-                     unsigned long arg)
+long vfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        int error = -ENOTTY;
 
index d67a16f2a45df8fcce56b9ff3ec56f334d951c9c..61abdc4920dab0056e998682f01038ef0a17f178 100644 (file)
@@ -1417,6 +1417,7 @@ static int isofs_read_inode(struct inode *inode, int relocated)
                inode->i_fop = &isofs_dir_operations;
        } else if (S_ISLNK(inode->i_mode)) {
                inode->i_op = &page_symlink_inode_operations;
+               inode_nohighmem(inode);
                inode->i_data.a_ops = &isofs_symlink_aops;
        } else
                /* XXX - parse_rock_ridge_inode() had already set i_rdev. */
index 735d7522a3a911f19af593d6b5f7d366d6cf448d..5384ceb35b1cc829442d6aa440db19c553a6eed8 100644 (file)
@@ -687,7 +687,7 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page)
        struct inode *inode = page->mapping->host;
        struct iso_inode_info *ei = ISOFS_I(inode);
        struct isofs_sb_info *sbi = ISOFS_SB(inode->i_sb);
-       char *link = kmap(page);
+       char *link = page_address(page);
        unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
        struct buffer_head *bh;
        char *rpnt = link;
@@ -774,7 +774,6 @@ repeat:
        brelse(bh);
        *rpnt = '\0';
        SetPageUptodate(page);
-       kunmap(page);
        unlock_page(page);
        return 0;
 
@@ -791,7 +790,6 @@ fail:
        brelse(bh);
 error:
        SetPageError(page);
-       kunmap(page);
        unlock_page(page);
        return -EIO;
 }
index bf12fe5f83d7e66fa1cf34883539126f12cadfe0..7a28facd71750c80f087db06f50e71be8d556710 100644 (file)
@@ -52,9 +52,6 @@ static int jffs2_security_getxattr(const struct xattr_handler *handler,
                                   struct dentry *dentry, const char *name,
                                   void *buffer, size_t size)
 {
-       if (!strcmp(name, ""))
-               return -EINVAL;
-
        return do_jffs2_getxattr(d_inode(dentry), JFFS2_XPREFIX_SECURITY,
                                 name, buffer, size);
 }
@@ -63,31 +60,12 @@ static int jffs2_security_setxattr(const struct xattr_handler *handler,
                                   struct dentry *dentry, const char *name,
                                   const void *buffer, size_t size, int flags)
 {
-       if (!strcmp(name, ""))
-               return -EINVAL;
-
        return do_jffs2_setxattr(d_inode(dentry), JFFS2_XPREFIX_SECURITY,
                                 name, buffer, size, flags);
 }
 
-static size_t jffs2_security_listxattr(const struct xattr_handler *handler,
-                                      struct dentry *dentry, char *list,
-                                      size_t list_size, const char *name,
-                                      size_t name_len)
-{
-       size_t retlen = XATTR_SECURITY_PREFIX_LEN + name_len + 1;
-
-       if (list && retlen <= list_size) {
-               strcpy(list, XATTR_SECURITY_PREFIX);
-               strcpy(list + XATTR_SECURITY_PREFIX_LEN, name);
-       }
-
-       return retlen;
-}
-
 const struct xattr_handler jffs2_security_xattr_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
-       .list = jffs2_security_listxattr,
        .set = jffs2_security_setxattr,
        .get = jffs2_security_getxattr
 };
index 8ce2f240125b39803b4ebf2d681b6a95d40c33f5..2cabd649d4fb69dbdbd22aeb40d19f605f605f20 100644 (file)
@@ -14,7 +14,7 @@
 const struct inode_operations jffs2_symlink_inode_operations =
 {
        .readlink =     generic_readlink,
-       .follow_link =  simple_follow_link,
+       .get_link =     simple_get_link,
        .setattr =      jffs2_setattr,
        .setxattr =     jffs2_setxattr,
        .getxattr =     jffs2_getxattr,
index 4c2c03663533dc2fbf1e0c24dc5b08dec6ea943f..da3e18503c6582074257e2714216bfb24b3a6f32 100644 (file)
@@ -967,7 +967,8 @@ ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
        struct jffs2_xattr_ref *ref, **pref;
        struct jffs2_xattr_datum *xd;
        const struct xattr_handler *xhandle;
-       ssize_t len, rc;
+       const char *prefix;
+       ssize_t prefix_len, len, rc;
        int retry = 0;
 
        rc = check_xattr_ref_inode(c, ic);
@@ -998,18 +999,23 @@ ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
                        }
                }
                xhandle = xprefix_to_handler(xd->xprefix);
-               if (!xhandle)
+               if (!xhandle || (xhandle->list && !xhandle->list(dentry)))
                        continue;
+               prefix = xhandle->prefix ?: xhandle->name;
+               prefix_len = strlen(prefix);
+               rc = prefix_len + xd->name_len + 1;
+
                if (buffer) {
-                       rc = xhandle->list(xhandle, dentry, buffer + len,
-                                          size - len, xd->xname,
-                                          xd->name_len);
-               } else {
-                       rc = xhandle->list(xhandle, dentry, NULL, 0,
-                                          xd->xname, xd->name_len);
+                       if (rc > size - len) {
+                               rc = -ERANGE;
+                               goto out;
+                       }
+                       memcpy(buffer, prefix, prefix_len);
+                       buffer += prefix_len;
+                       memcpy(buffer, xd->xname, xd->name_len);
+                       buffer += xd->name_len;
+                       *buffer++ = 0;
                }
-               if (rc < 0)
-                       goto out;
                len += rc;
        }
        rc = len;
index a562da0d6a26186dc2116d6b8a05795903a46897..b2555ef07a12b1f969f63cac461e0f06f7517533 100644 (file)
@@ -20,8 +20,6 @@ static int jffs2_trusted_getxattr(const struct xattr_handler *handler,
                                  struct dentry *dentry, const char *name,
                                  void *buffer, size_t size)
 {
-       if (!strcmp(name, ""))
-               return -EINVAL;
        return do_jffs2_getxattr(d_inode(dentry), JFFS2_XPREFIX_TRUSTED,
                                 name, buffer, size);
 }
@@ -30,28 +28,13 @@ static int jffs2_trusted_setxattr(const struct xattr_handler *handler,
                                  struct dentry *dentry, const char *name,
                                  const void *buffer, size_t size, int flags)
 {
-       if (!strcmp(name, ""))
-               return -EINVAL;
        return do_jffs2_setxattr(d_inode(dentry), JFFS2_XPREFIX_TRUSTED,
                                 name, buffer, size, flags);
 }
 
-static size_t jffs2_trusted_listxattr(const struct xattr_handler *handler,
-                                     struct dentry *dentry, char *list,
-                                     size_t list_size, const char *name,
-                                     size_t name_len)
+static bool jffs2_trusted_listxattr(struct dentry *dentry)
 {
-       size_t retlen = XATTR_TRUSTED_PREFIX_LEN + name_len + 1;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return 0;
-
-       if (list && retlen<=list_size) {
-               strcpy(list, XATTR_TRUSTED_PREFIX);
-               strcpy(list + XATTR_TRUSTED_PREFIX_LEN, name);
-       }
-
-       return retlen;
+       return capable(CAP_SYS_ADMIN);
 }
 
 const struct xattr_handler jffs2_trusted_xattr_handler = {
index cbc0472e59a8b01b81ea142f35d29c88c3a12c00..539bd630b5e42120c7c185394959c05036df629a 100644 (file)
@@ -20,8 +20,6 @@ static int jffs2_user_getxattr(const struct xattr_handler *handler,
                               struct dentry *dentry, const char *name,
                               void *buffer, size_t size)
 {
-       if (!strcmp(name, ""))
-               return -EINVAL;
        return do_jffs2_getxattr(d_inode(dentry), JFFS2_XPREFIX_USER,
                                 name, buffer, size);
 }
@@ -30,30 +28,12 @@ static int jffs2_user_setxattr(const struct xattr_handler *handler,
                               struct dentry *dentry, const char *name,
                               const void *buffer, size_t size, int flags)
 {
-       if (!strcmp(name, ""))
-               return -EINVAL;
        return do_jffs2_setxattr(d_inode(dentry), JFFS2_XPREFIX_USER,
                                 name, buffer, size, flags);
 }
 
-static size_t jffs2_user_listxattr(const struct xattr_handler *handler,
-                                  struct dentry *dentry, char *list,
-                                  size_t list_size, const char *name,
-                                  size_t name_len)
-{
-       size_t retlen = XATTR_USER_PREFIX_LEN + name_len + 1;
-
-       if (list && retlen <= list_size) {
-               strcpy(list, XATTR_USER_PREFIX);
-               strcpy(list + XATTR_USER_PREFIX_LEN, name);
-       }
-
-       return retlen;
-}
-
 const struct xattr_handler jffs2_user_xattr_handler = {
        .prefix = XATTR_USER_PREFIX,
-       .list = jffs2_user_listxattr,
        .set = jffs2_user_setxattr,
        .get = jffs2_user_getxattr
 };
index 0c8ca830b113e62246d3f2629846958bdee32775..49456853e9de230822b4cb97b407c565525d2ffe 100644 (file)
@@ -40,10 +40,10 @@ struct posix_acl *jfs_get_acl(struct inode *inode, int type)
 
        switch(type) {
                case ACL_TYPE_ACCESS:
-                       ea_name = POSIX_ACL_XATTR_ACCESS;
+                       ea_name = XATTR_NAME_POSIX_ACL_ACCESS;
                        break;
                case ACL_TYPE_DEFAULT:
-                       ea_name = POSIX_ACL_XATTR_DEFAULT;
+                       ea_name = XATTR_NAME_POSIX_ACL_DEFAULT;
                        break;
                default:
                        return ERR_PTR(-EINVAL);
@@ -82,7 +82,7 @@ static int __jfs_set_acl(tid_t tid, struct inode *inode, int type,
 
        switch (type) {
        case ACL_TYPE_ACCESS:
-               ea_name = POSIX_ACL_XATTR_ACCESS;
+               ea_name = XATTR_NAME_POSIX_ACL_ACCESS;
                if (acl) {
                        rc = posix_acl_equiv_mode(acl, &inode->i_mode);
                        if (rc < 0)
@@ -94,7 +94,7 @@ static int __jfs_set_acl(tid_t tid, struct inode *inode, int type,
                }
                break;
        case ACL_TYPE_DEFAULT:
-               ea_name = POSIX_ACL_XATTR_DEFAULT;
+               ea_name = XATTR_NAME_POSIX_ACL_DEFAULT;
                break;
        default:
                return -EINVAL;
index 41aa3ca6a6a4995104d12f38cc5945ebb63a0f7d..9d9bae63ae2a2d44b36c4b1bcd53adae2158e896 100644 (file)
@@ -60,6 +60,7 @@ struct inode *jfs_iget(struct super_block *sb, unsigned long ino)
        } else if (S_ISLNK(inode->i_mode)) {
                if (inode->i_size >= IDATASIZE) {
                        inode->i_op = &page_symlink_inode_operations;
+                       inode_nohighmem(inode);
                        inode->i_mapping->a_ops = &jfs_aops;
                } else {
                        inode->i_op = &jfs_fast_symlink_inode_operations;
index 9d7551f5c32a9ffb9a166f588e5f2211d62d0249..701f89370de7afb7d9a7402f1cbe4fe0d42b19fa 100644 (file)
@@ -983,6 +983,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
                jfs_info("jfs_symlink: allocate extent ip:0x%p", ip);
 
                ip->i_op = &jfs_symlink_inode_operations;
+               inode_nohighmem(ip);
                ip->i_mapping->a_ops = &jfs_aops;
 
                /*
index 5929e2363cb85eddc0d54bf3a04754383cb395db..f8db4fde0b0b65502ce89887efaec7b40c4d8a6e 100644 (file)
@@ -23,7 +23,7 @@
 
 const struct inode_operations jfs_fast_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = simple_follow_link,
+       .get_link       = simple_get_link,
        .setattr        = jfs_setattr,
        .setxattr       = jfs_setxattr,
        .getxattr       = jfs_getxattr,
@@ -33,8 +33,7 @@ const struct inode_operations jfs_fast_symlink_inode_operations = {
 
 const struct inode_operations jfs_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = page_follow_link_light,
-       .put_link       = page_put_link,
+       .get_link       = page_get_link,
        .setattr        = jfs_setattr,
        .setxattr       = jfs_setxattr,
        .getxattr       = jfs_getxattr,
index 756dd56aaf60acd337fb251fb287cbd382d57740..16405ae88d2d657f278f2e5cf66f399582565eb0 100644 (file)
@@ -205,7 +205,7 @@ int kernfs_iop_removexattr(struct dentry *dentry, const char *name)
        if (!attrs)
                return -ENOMEM;
 
-       return simple_xattr_remove(&attrs->xattrs, name);
+       return simple_xattr_set(&attrs->xattrs, name, NULL, 0, XATTR_REPLACE);
 }
 
 ssize_t kernfs_iop_getxattr(struct dentry *dentry, const char *name, void *buf,
@@ -230,7 +230,7 @@ ssize_t kernfs_iop_listxattr(struct dentry *dentry, char *buf, size_t size)
        if (!attrs)
                return -ENOMEM;
 
-       return simple_xattr_list(&attrs->xattrs, buf, size);
+       return simple_xattr_list(d_inode(dentry), &attrs->xattrs, buf, size);
 }
 
 static inline void set_default_inode_attr(struct inode *inode, umode_t mode)
index db272528ab5bb01c192b5502650f29e0784663ce..117b8b3416f9e761dacf36e8a3e3ff1e84f9e29b 100644 (file)
@@ -112,18 +112,25 @@ static int kernfs_getlink(struct dentry *dentry, char *path)
        return error;
 }
 
-static const char *kernfs_iop_follow_link(struct dentry *dentry, void **cookie)
+static const char *kernfs_iop_get_link(struct dentry *dentry,
+                                      struct inode *inode,
+                                      struct delayed_call *done)
 {
-       int error = -ENOMEM;
-       unsigned long page = get_zeroed_page(GFP_KERNEL);
-       if (!page)
+       char *body;
+       int error;
+
+       if (!dentry)
+               return ERR_PTR(-ECHILD);
+       body = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!body)
                return ERR_PTR(-ENOMEM);
-       error = kernfs_getlink(dentry, (char *)page);
+       error = kernfs_getlink(dentry, body);
        if (unlikely(error < 0)) {
-               free_page((unsigned long)page);
+               kfree(body);
                return ERR_PTR(error);
        }
-       return *cookie = (char *)page;
+       set_delayed_call(done, kfree_link, body);
+       return body;
 }
 
 const struct inode_operations kernfs_symlink_iops = {
@@ -132,8 +139,7 @@ const struct inode_operations kernfs_symlink_iops = {
        .getxattr       = kernfs_iop_getxattr,
        .listxattr      = kernfs_iop_listxattr,
        .readlink       = generic_readlink,
-       .follow_link    = kernfs_iop_follow_link,
-       .put_link       = free_page_put_link,
+       .get_link       = kernfs_iop_get_link,
        .setattr        = kernfs_iop_setattr,
        .getattr        = kernfs_iop_getattr,
        .permission     = kernfs_iop_permission,
index c7cbfb092e9467db1795145816faa91e1eda731f..01491299f348c965adc27cbcd70340ab2d980946 100644 (file)
@@ -1019,17 +1019,12 @@ int noop_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 }
 EXPORT_SYMBOL(noop_fsync);
 
-void kfree_put_link(struct inode *unused, void *cookie)
+/* Because kfree isn't assignment-compatible with void(void*) ;-/ */
+void kfree_link(void *p)
 {
-       kfree(cookie);
+       kfree(p);
 }
-EXPORT_SYMBOL(kfree_put_link);
-
-void free_page_put_link(struct inode *unused, void *cookie)
-{
-       free_page((unsigned long) cookie);
-}
-EXPORT_SYMBOL(free_page_put_link);
+EXPORT_SYMBOL(kfree_link);
 
 /*
  * nop .set_page_dirty method so that people can use .page_mkwrite on
@@ -1092,14 +1087,15 @@ simple_nosetlease(struct file *filp, long arg, struct file_lock **flp,
 }
 EXPORT_SYMBOL(simple_nosetlease);
 
-const char *simple_follow_link(struct dentry *dentry, void **cookie)
+const char *simple_get_link(struct dentry *dentry, struct inode *inode,
+                           struct delayed_call *done)
 {
-       return d_inode(dentry)->i_link;
+       return inode->i_link;
 }
-EXPORT_SYMBOL(simple_follow_link);
+EXPORT_SYMBOL(simple_get_link);
 
 const struct inode_operations simple_symlink_inode_operations = {
-       .follow_link = simple_follow_link,
+       .get_link = simple_get_link,
        .readlink = generic_readlink
 };
 EXPORT_SYMBOL(simple_symlink_inode_operations);
index f9b45d46d4c483ea0be1ceca4c35b9b3075b56b9..542468e9bfb492f8333221a80bcfbcc4b01aa39a 100644 (file)
@@ -528,7 +528,8 @@ static int logfs_symlink(struct inode *dir, struct dentry *dentry,
        if (IS_ERR(inode))
                return PTR_ERR(inode);
 
-       inode->i_op = &logfs_symlink_iops;
+       inode->i_op = &page_symlink_inode_operations;
+       inode_nohighmem(inode);
        inode->i_mapping->a_ops = &logfs_reg_aops;
 
        return __logfs_create(dir, dentry, inode, target, destlen);
@@ -776,12 +777,6 @@ fail:
        return -EIO;
 }
 
-const struct inode_operations logfs_symlink_iops = {
-       .readlink       = generic_readlink,
-       .follow_link    = page_follow_link_light,
-       .put_link       = page_put_link,
-};
-
 const struct inode_operations logfs_dir_iops = {
        .create         = logfs_create,
        .link           = logfs_link,
index af49e2d6941a7c2f8120ee3ca99095e0bb2ea767..0fce46d62b9c20491a9fb248f55a39b2273def74 100644 (file)
@@ -64,7 +64,8 @@ static void logfs_inode_setops(struct inode *inode)
                inode->i_mapping->a_ops = &logfs_reg_aops;
                break;
        case S_IFLNK:
-               inode->i_op = &logfs_symlink_iops;
+               inode->i_op = &page_symlink_inode_operations;
+               inode_nohighmem(inode);
                inode->i_mapping->a_ops = &logfs_reg_aops;
                break;
        case S_IFSOCK:  /* fall through */
index 5f09376094651c76c7ded9f52535fe1a1351ed6b..209a26d84c3835eda1ae30638e5edc2d3896cc49 100644 (file)
@@ -495,7 +495,6 @@ static inline int logfs_get_sb_mtd(struct logfs_super *s, int mtdnr)
 #endif
 
 /* dir.c */
-extern const struct inode_operations logfs_symlink_iops;
 extern const struct inode_operations logfs_dir_iops;
 extern const struct file_operations logfs_dir_fops;
 int logfs_replay_journal(struct super_block *sb);
index 086cd0a61e8015e60ccebcb99464ab23e58bb266..cb1789ca1ee675d1d101fb272ec05c28557b0186 100644 (file)
@@ -435,8 +435,7 @@ static const struct address_space_operations minix_aops = {
 
 static const struct inode_operations minix_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = page_follow_link_light,
-       .put_link       = page_put_link,
+       .get_link       = page_get_link,
        .getattr        = minix_getattr,
 };
 
@@ -452,6 +451,7 @@ void minix_set_inode(struct inode *inode, dev_t rdev)
                inode->i_mapping->a_ops = &minix_aops;
        } else if (S_ISLNK(inode->i_mode)) {
                inode->i_op = &minix_symlink_inode_operations;
+               inode_nohighmem(inode);
                inode->i_mapping->a_ops = &minix_aops;
        } else
                init_special_inode(inode, inode->i_mode, rdev);
index 0c3974cd3ecd55670ccab51c596b0b141cbdd721..3c909aebef70f8a8a091960bd3ba434a15e2f829 100644 (file)
@@ -505,13 +505,13 @@ struct nameidata {
        int             total_link_count;
        struct saved {
                struct path link;
-               void *cookie;
+               struct delayed_call done;
                const char *name;
-               struct inode *inode;
                unsigned seq;
        } *stack, internal[EMBEDDED_LEVELS];
        struct filename *name;
        struct nameidata *saved;
+       struct inode    *link_inode;
        unsigned        root_seq;
        int             dfd;
 };
@@ -592,11 +592,8 @@ static void drop_links(struct nameidata *nd)
        int i = nd->depth;
        while (i--) {
                struct saved *last = nd->stack + i;
-               struct inode *inode = last->inode;
-               if (last->cookie && inode->i_op->put_link) {
-                       inode->i_op->put_link(inode, last->cookie);
-                       last->cookie = NULL;
-               }
+               do_delayed_call(&last->done);
+               clear_delayed_call(&last->done);
        }
 }
 
@@ -842,7 +839,7 @@ static inline void path_to_nameidata(const struct path *path,
 }
 
 /*
- * Helper to directly jump to a known parsed path from ->follow_link,
+ * Helper to directly jump to a known parsed path from ->get_link,
  * caller must have taken a reference to path beforehand.
  */
 void nd_jump_link(struct path *path)
@@ -858,9 +855,7 @@ void nd_jump_link(struct path *path)
 static inline void put_link(struct nameidata *nd)
 {
        struct saved *last = nd->stack + --nd->depth;
-       struct inode *inode = last->inode;
-       if (last->cookie && inode->i_op->put_link)
-               inode->i_op->put_link(inode, last->cookie);
+       do_delayed_call(&last->done);
        if (!(nd->flags & LOOKUP_RCU))
                path_put(&last->link);
 }
@@ -892,7 +887,7 @@ static inline int may_follow_link(struct nameidata *nd)
                return 0;
 
        /* Allowed if owner and follower match. */
-       inode = nd->stack[0].inode;
+       inode = nd->link_inode;
        if (uid_eq(current_cred()->fsuid, inode->i_uid))
                return 0;
 
@@ -983,7 +978,7 @@ const char *get_link(struct nameidata *nd)
 {
        struct saved *last = nd->stack + nd->depth - 1;
        struct dentry *dentry = last->link.dentry;
-       struct inode *inode = last->inode;
+       struct inode *inode = nd->link_inode;
        int error;
        const char *res;
 
@@ -1004,15 +999,21 @@ const char *get_link(struct nameidata *nd)
        nd->last_type = LAST_BIND;
        res = inode->i_link;
        if (!res) {
+               const char * (*get)(struct dentry *, struct inode *,
+                               struct delayed_call *);
+               get = inode->i_op->get_link;
                if (nd->flags & LOOKUP_RCU) {
-                       if (unlikely(unlazy_walk(nd, NULL, 0)))
-                               return ERR_PTR(-ECHILD);
+                       res = get(NULL, inode, &last->done);
+                       if (res == ERR_PTR(-ECHILD)) {
+                               if (unlikely(unlazy_walk(nd, NULL, 0)))
+                                       return ERR_PTR(-ECHILD);
+                               res = get(dentry, inode, &last->done);
+                       }
+               } else {
+                       res = get(dentry, inode, &last->done);
                }
-               res = inode->i_op->follow_link(dentry, &last->cookie);
-               if (IS_ERR_OR_NULL(res)) {
-                       last->cookie = NULL;
+               if (IS_ERR_OR_NULL(res))
                        return res;
-               }
        }
        if (*res == '/') {
                if (nd->flags & LOOKUP_RCU) {
@@ -1691,8 +1692,8 @@ static int pick_link(struct nameidata *nd, struct path *link,
 
        last = nd->stack + nd->depth++;
        last->link = *link;
-       last->cookie = NULL;
-       last->inode = inode;
+       clear_delayed_call(&last->done);
+       nd->link_inode = inode;
        last->seq = seq;
        return 1;
 }
@@ -4495,72 +4496,73 @@ EXPORT_SYMBOL(readlink_copy);
 
 /*
  * A helper for ->readlink().  This should be used *ONLY* for symlinks that
- * have ->follow_link() touching nd only in nd_set_link().  Using (or not
- * using) it for any given inode is up to filesystem.
+ * have ->get_link() not calling nd_jump_link().  Using (or not using) it
+ * for any given inode is up to filesystem.
  */
 int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
 {
-       void *cookie;
+       DEFINE_DELAYED_CALL(done);
        struct inode *inode = d_inode(dentry);
        const char *link = inode->i_link;
        int res;
 
        if (!link) {
-               link = inode->i_op->follow_link(dentry, &cookie);
+               link = inode->i_op->get_link(dentry, inode, &done);
                if (IS_ERR(link))
                        return PTR_ERR(link);
        }
        res = readlink_copy(buffer, buflen, link);
-       if (inode->i_op->put_link)
-               inode->i_op->put_link(inode, cookie);
+       do_delayed_call(&done);
        return res;
 }
 EXPORT_SYMBOL(generic_readlink);
 
 /* get the link contents into pagecache */
-static char *page_getlink(struct dentry * dentry, struct page **ppage)
+const char *page_get_link(struct dentry *dentry, struct inode *inode,
+                         struct delayed_call *callback)
 {
        char *kaddr;
        struct page *page;
-       struct address_space *mapping = dentry->d_inode->i_mapping;
-       page = read_mapping_page(mapping, 0, NULL);
-       if (IS_ERR(page))
-               return (char*)page;
-       *ppage = page;
-       kaddr = kmap(page);
-       nd_terminate_link(kaddr, dentry->d_inode->i_size, PAGE_SIZE - 1);
+       struct address_space *mapping = inode->i_mapping;
+
+       if (!dentry) {
+               page = find_get_page(mapping, 0);
+               if (!page)
+                       return ERR_PTR(-ECHILD);
+               if (!PageUptodate(page)) {
+                       put_page(page);
+                       return ERR_PTR(-ECHILD);
+               }
+       } else {
+               page = read_mapping_page(mapping, 0, NULL);
+               if (IS_ERR(page))
+                       return (char*)page;
+       }
+       set_delayed_call(callback, page_put_link, page);
+       BUG_ON(mapping_gfp_mask(mapping) & __GFP_HIGHMEM);
+       kaddr = page_address(page);
+       nd_terminate_link(kaddr, inode->i_size, PAGE_SIZE - 1);
        return kaddr;
 }
 
-int page_readlink(struct dentry *dentry, char __user *buffer, int buflen)
-{
-       struct page *page = NULL;
-       int res = readlink_copy(buffer, buflen, page_getlink(dentry, &page));
-       if (page) {
-               kunmap(page);
-               page_cache_release(page);
-       }
-       return res;
-}
-EXPORT_SYMBOL(page_readlink);
+EXPORT_SYMBOL(page_get_link);
 
-const char *page_follow_link_light(struct dentry *dentry, void **cookie)
+void page_put_link(void *arg)
 {
-       struct page *page = NULL;
-       char *res = page_getlink(dentry, &page);
-       if (!IS_ERR(res))
-               *cookie = page;
-       return res;
+       put_page(arg);
 }
-EXPORT_SYMBOL(page_follow_link_light);
+EXPORT_SYMBOL(page_put_link);
 
-void page_put_link(struct inode *unused, void *cookie)
+int page_readlink(struct dentry *dentry, char __user *buffer, int buflen)
 {
-       struct page *page = cookie;
-       kunmap(page);
-       page_cache_release(page);
+       DEFINE_DELAYED_CALL(done);
+       int res = readlink_copy(buffer, buflen,
+                               page_get_link(dentry, d_inode(dentry),
+                                             &done));
+       do_delayed_call(&done);
+       return res;
 }
-EXPORT_SYMBOL(page_put_link);
+EXPORT_SYMBOL(page_readlink);
 
 /*
  * The nofs argument instructs pagecache_write_begin to pass AOP_FLAG_NOFS
@@ -4571,7 +4573,6 @@ int __page_symlink(struct inode *inode, const char *symname, int len, int nofs)
        struct page *page;
        void *fsdata;
        int err;
-       char *kaddr;
        unsigned int flags = AOP_FLAG_UNINTERRUPTIBLE;
        if (nofs)
                flags |= AOP_FLAG_NOFS;
@@ -4582,9 +4583,7 @@ retry:
        if (err)
                goto fail;
 
-       kaddr = kmap_atomic(page);
-       memcpy(kaddr, symname, len-1);
-       kunmap_atomic(kaddr);
+       memcpy(page_address(page), symname, len-1);
 
        err = pagecache_write_end(NULL, mapping, 0, len-1, len-1,
                                                        page, fsdata);
@@ -4609,7 +4608,6 @@ EXPORT_SYMBOL(page_symlink);
 
 const struct inode_operations page_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = page_follow_link_light,
-       .put_link       = page_put_link,
+       .get_link       = page_get_link,
 };
 EXPORT_SYMBOL(page_symlink_inode_operations);
index 9605a2f635490ddf498c72049d7b40d84e7f977b..ce1eb3f9dfe8005e34567bab5cbb04d3f8ce10a5 100644 (file)
@@ -244,8 +244,7 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
 static const struct inode_operations ncp_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = page_follow_link_light,
-       .put_link       = page_put_link,
+       .get_link       = page_get_link,
        .setattr        = ncp_notify_change,
 };
 #endif
@@ -283,6 +282,7 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
                } else if (S_ISLNK(inode->i_mode)) {
                        inode->i_op = &ncp_symlink_inode_operations;
+                       inode_nohighmem(inode);
                        inode->i_data.a_ops = &ncp_symlink_aops;
 #endif
                } else {
index c7e8b87da5b24d13dff36f5d2510244c01b7abf4..bdb4dc7b4ecde1531d6801b6cacbab3a004d1fb4 100644 (file)
@@ -408,9 +408,10 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
                                inode->i_fop = NULL;
                                inode->i_flags |= S_AUTOMOUNT;
                        }
-               } else if (S_ISLNK(inode->i_mode))
+               } else if (S_ISLNK(inode->i_mode)) {
                        inode->i_op = &nfs_symlink_inode_operations;
-               else
+                       inode_nohighmem(inode);
+               } else
                        init_special_inode(inode, inode->i_mode, fattr->rdev);
 
                memset(&inode->i_atime, 0, sizeof(inode->i_atime));
@@ -1086,6 +1087,27 @@ static bool nfs_mapping_need_revalidate_inode(struct inode *inode)
                || NFS_STALE(inode);
 }
 
+int nfs_revalidate_mapping_rcu(struct inode *inode)
+{
+       struct nfs_inode *nfsi = NFS_I(inode);
+       unsigned long *bitlock = &nfsi->flags;
+       int ret = 0;
+
+       if (IS_SWAPFILE(inode))
+               goto out;
+       if (nfs_mapping_need_revalidate_inode(inode)) {
+               ret = -ECHILD;
+               goto out;
+       }
+       spin_lock(&inode->i_lock);
+       if (test_bit(NFS_INO_INVALIDATING, bitlock) ||
+           (nfsi->cache_validity & NFS_INO_INVALID_DATA))
+               ret = -ECHILD;
+       spin_unlock(&inode->i_lock);
+out:
+       return ret;
+}
+
 /**
  * __nfs_revalidate_mapping - Revalidate the pagecache
  * @inode - pointer to host inode
index 1ebe2fc7cda2778edfb968da2c8f079dd2870431..17c0fa1eccfaad22710fe6e938dc4904cc5b8cdf 100644 (file)
@@ -284,12 +284,12 @@ nfs3_listxattr(struct dentry *dentry, char *data, size_t size)
        int error;
 
        error = nfs3_list_one_acl(inode, ACL_TYPE_ACCESS,
-                       POSIX_ACL_XATTR_ACCESS, data, size, &result);
+                       XATTR_NAME_POSIX_ACL_ACCESS, data, size, &result);
        if (error)
                return error;
 
        error = nfs3_list_one_acl(inode, ACL_TYPE_DEFAULT,
-                       POSIX_ACL_XATTR_DEFAULT, data, size, &result);
+                       XATTR_NAME_POSIX_ACL_DEFAULT, data, size, &result);
        if (error)
                return error;
        return result;
index 89818036f035b01eaaa4e45797205d53f48e9934..c57d1332c1c87d2da7c3716fa5cba99654dd5e1c 100644 (file)
@@ -6253,9 +6253,6 @@ static int nfs4_xattr_set_nfs4_acl(const struct xattr_handler *handler,
                                   const void *buf, size_t buflen,
                                   int flags)
 {
-       if (strcmp(key, "") != 0)
-               return -EINVAL;
-
        return nfs4_proc_set_acl(d_inode(dentry), buf, buflen);
 }
 
@@ -6263,32 +6260,15 @@ static int nfs4_xattr_get_nfs4_acl(const struct xattr_handler *handler,
                                   struct dentry *dentry, const char *key,
                                   void *buf, size_t buflen)
 {
-       if (strcmp(key, "") != 0)
-               return -EINVAL;
-
        return nfs4_proc_get_acl(d_inode(dentry), buf, buflen);
 }
 
-static size_t nfs4_xattr_list_nfs4_acl(const struct xattr_handler *handler,
-                                      struct dentry *dentry, char *list,
-                                      size_t list_len, const char *name,
-                                      size_t name_len)
+static bool nfs4_xattr_list_nfs4_acl(struct dentry *dentry)
 {
-       size_t len = sizeof(XATTR_NAME_NFSV4_ACL);
-
-       if (!nfs4_server_supports_acls(NFS_SERVER(d_inode(dentry))))
-               return 0;
-
-       if (list && len <= list_len)
-               memcpy(list, XATTR_NAME_NFSV4_ACL, len);
-       return len;
+       return nfs4_server_supports_acls(NFS_SERVER(d_inode(dentry)));
 }
 
 #ifdef CONFIG_NFS_V4_SECURITY_LABEL
-static inline int nfs4_server_supports_labels(struct nfs_server *server)
-{
-       return server->caps & NFS_CAP_SECURITY_LABEL;
-}
 
 static int nfs4_xattr_set_nfs4_label(const struct xattr_handler *handler,
                                     struct dentry *dentry, const char *key,
@@ -6310,29 +6290,34 @@ static int nfs4_xattr_get_nfs4_label(const struct xattr_handler *handler,
        return -EOPNOTSUPP;
 }
 
-static size_t nfs4_xattr_list_nfs4_label(const struct xattr_handler *handler,
-                                        struct dentry *dentry, char *list,
-                                        size_t list_len, const char *name,
-                                        size_t name_len)
+static ssize_t
+nfs4_listxattr_nfs4_label(struct inode *inode, char *list, size_t list_len)
 {
-       size_t len = 0;
+       int len = 0;
 
-       if (nfs_server_capable(d_inode(dentry), NFS_CAP_SECURITY_LABEL)) {
-               len = security_inode_listsecurity(d_inode(dentry), NULL, 0);
-               if (list && len <= list_len)
-                       security_inode_listsecurity(d_inode(dentry), list, len);
+       if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) {
+               len = security_inode_listsecurity(inode, list, list_len);
+               if (list_len && len > list_len)
+                       return -ERANGE;
        }
        return len;
 }
 
 static const struct xattr_handler nfs4_xattr_nfs4_label_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
-       .list   = nfs4_xattr_list_nfs4_label,
        .get    = nfs4_xattr_get_nfs4_label,
        .set    = nfs4_xattr_set_nfs4_label,
 };
-#endif
 
+#else
+
+static ssize_t
+nfs4_listxattr_nfs4_label(struct inode *inode, char *list, size_t list_len)
+{
+       return 0;
+}
+
+#endif
 
 /*
  * nfs_fhget will use either the mounted_on_fileid or the fileid
@@ -8749,6 +8734,24 @@ const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = {
 #endif
 };
 
+ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size)
+{
+       ssize_t error, error2;
+
+       error = generic_listxattr(dentry, list, size);
+       if (error < 0)
+               return error;
+       if (list) {
+               list += error;
+               size -= error;
+       }
+
+       error2 = nfs4_listxattr_nfs4_label(d_inode(dentry), list, size);
+       if (error2 < 0)
+               return error2;
+       return error + error2;
+}
+
 static const struct inode_operations nfs4_dir_inode_operations = {
        .create         = nfs_create,
        .lookup         = nfs_lookup,
@@ -8765,7 +8768,7 @@ static const struct inode_operations nfs4_dir_inode_operations = {
        .setattr        = nfs_setattr,
        .getxattr       = generic_getxattr,
        .setxattr       = generic_setxattr,
-       .listxattr      = generic_listxattr,
+       .listxattr      = nfs4_listxattr,
        .removexattr    = generic_removexattr,
 };
 
@@ -8775,7 +8778,7 @@ static const struct inode_operations nfs4_file_inode_operations = {
        .setattr        = nfs_setattr,
        .getxattr       = generic_getxattr,
        .setxattr       = generic_setxattr,
-       .listxattr      = generic_listxattr,
+       .listxattr      = nfs4_listxattr,
        .removexattr    = generic_removexattr,
 };
 
@@ -8834,7 +8837,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
 };
 
 static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
-       .prefix = XATTR_NAME_NFSV4_ACL,
+       .name   = XATTR_NAME_NFSV4_ACL,
        .list   = nfs4_xattr_list_nfs4_acl,
        .get    = nfs4_xattr_get_nfs4_acl,
        .set    = nfs4_xattr_set_nfs4_acl,
index b6de433da5db14ab788ba358ce94b5952d5c601f..4fe3eead3868ebe418432b4593c10464188fb4ed 100644 (file)
@@ -42,21 +42,35 @@ error:
        return -EIO;
 }
 
-static const char *nfs_follow_link(struct dentry *dentry, void **cookie)
+static const char *nfs_get_link(struct dentry *dentry,
+                               struct inode *inode,
+                               struct delayed_call *done)
 {
-       struct inode *inode = d_inode(dentry);
        struct page *page;
        void *err;
 
-       err = ERR_PTR(nfs_revalidate_mapping(inode, inode->i_mapping));
-       if (err)
-               return err;
-       page = read_cache_page(&inode->i_data, 0,
-                               (filler_t *)nfs_symlink_filler, inode);
-       if (IS_ERR(page))
-               return ERR_CAST(page);
-       *cookie = page;
-       return kmap(page);
+       if (!dentry) {
+               err = ERR_PTR(nfs_revalidate_mapping_rcu(inode));
+               if (err)
+                       return err;
+               page = find_get_page(inode->i_mapping, 0);
+               if (!page)
+                       return ERR_PTR(-ECHILD);
+               if (!PageUptodate(page)) {
+                       put_page(page);
+                       return ERR_PTR(-ECHILD);
+               }
+       } else {
+               err = ERR_PTR(nfs_revalidate_mapping(inode, inode->i_mapping));
+               if (err)
+                       return err;
+               page = read_cache_page(&inode->i_data, 0,
+                                       (filler_t *)nfs_symlink_filler, inode);
+               if (IS_ERR(page))
+                       return ERR_CAST(page);
+       }
+       set_delayed_call(done, page_put_link, page);
+       return page_address(page);
 }
 
 /*
@@ -64,8 +78,7 @@ static const char *nfs_follow_link(struct dentry *dentry, void **cookie)
  */
 const struct inode_operations nfs_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = nfs_follow_link,
-       .put_link       = page_put_link,
+       .get_link       = nfs_get_link,
        .getattr        = nfs_getattr,
        .setattr        = nfs_setattr,
 };
index ac2f64943ff4c257f3fe2cd8d32de581de601cc6..10b22527a617dcdefc36d36ce4fc3d3658e20330 100644 (file)
@@ -510,6 +510,7 @@ static int __nilfs_read_inode(struct super_block *sb,
                inode->i_mapping->a_ops = &nilfs_aops;
        } else if (S_ISLNK(inode->i_mode)) {
                inode->i_op = &nilfs_symlink_inode_operations;
+               inode_nohighmem(inode);
                inode->i_mapping->a_ops = &nilfs_aops;
        } else {
                inode->i_op = &nilfs_special_inode_operations;
index c9a1a491aa9124b4cad5941e477f7ac3ae5de8b1..7ccdb961eea90d2ed313ef688feca1451112f5ba 100644 (file)
@@ -161,6 +161,7 @@ static int nilfs_symlink(struct inode *dir, struct dentry *dentry,
 
        /* slow symlink */
        inode->i_op = &nilfs_symlink_inode_operations;
+       inode_nohighmem(inode);
        inode->i_mapping->a_ops = &nilfs_aops;
        err = page_symlink(inode, symname, l);
        if (err)
@@ -568,8 +569,7 @@ const struct inode_operations nilfs_special_inode_operations = {
 
 const struct inode_operations nilfs_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = page_follow_link_light,
-       .put_link       = page_put_link,
+       .get_link       = page_get_link,
        .permission     = nilfs_permission,
 };
 
index ce38b4ccc9ab6c52c796a148b496bab0d8d46510..84f2f8079466a7fc07c8a4fda50d3513a02b68f9 100644 (file)
@@ -2843,6 +2843,8 @@ again:
        res->state &= ~DLM_LOCK_RES_BLOCK_DIRTY;
        if (!ret)
                BUG_ON(!(res->state & DLM_LOCK_RES_MIGRATING));
+       else
+               res->migration_pending = 0;
        spin_unlock(&res->spinlock);
 
        /*
index 8f87e05ee25d3824524c7f6e040a5f43d87c723d..97a563bab9a871ee3e371a9796b990c24835f47f 100644 (file)
@@ -361,6 +361,7 @@ void ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
                    break;
            case S_IFLNK:
                    inode->i_op = &ocfs2_symlink_inode_operations;
+                   inode_nohighmem(inode);
                    i_size_write(inode, le64_to_cpu(fe->i_size));
                    break;
            default:
index 652ece4a9d9e2e90a72a95b4be1d910ea46cfc9f..d56f0079b858081241357b26667bf7fba9de5e3e 100644 (file)
@@ -67,7 +67,10 @@ static int ocfs2_do_flock(struct file *file, struct inode *inode,
                 */
 
                locks_lock_file_wait(file,
-                                    &(struct file_lock){.fl_type = F_UNLCK});
+                               &(struct file_lock) {
+                                       .fl_type = F_UNLCK,
+                                       .fl_flags = FL_FLOCK
+                               });
 
                ocfs2_file_unlock(file);
        }
index 3123408da9352b365e8bb3ca5e619a8f188cdc5a..afb81eae2c1876f595e8f24446fb19bb992bb313 100644 (file)
@@ -1958,6 +1958,7 @@ static int ocfs2_symlink(struct inode *dir,
        inode->i_rdev = 0;
        newsize = l - 1;
        inode->i_op = &ocfs2_symlink_inode_operations;
+       inode_nohighmem(inode);
        if (l > ocfs2_fast_symlink_chars(sb)) {
                u32 offset = 0;
 
index d5da6f624142812ab63e83f5ab1b90e05151fed3..79b8021302b3eed84b9c59637cddd0e4844eb78b 100644 (file)
 static u16 ocfs2_calc_new_backup_super(struct inode *inode,
                                       struct ocfs2_group_desc *gd,
                                       u16 cl_cpg,
+                                      u16 old_bg_clusters,
                                       int set)
 {
        int i;
        u16 backups = 0;
-       u32 cluster;
+       u32 cluster, lgd_cluster;
        u64 blkno, gd_blkno, lgd_blkno = le64_to_cpu(gd->bg_blkno);
 
        for (i = 0; i < OCFS2_MAX_BACKUP_SUPERBLOCKS; i++) {
@@ -71,6 +72,12 @@ static u16 ocfs2_calc_new_backup_super(struct inode *inode,
                else if (gd_blkno > lgd_blkno)
                        break;
 
+               /* check if already done backup super */
+               lgd_cluster = ocfs2_blocks_to_clusters(inode->i_sb, lgd_blkno);
+               lgd_cluster += old_bg_clusters;
+               if (lgd_cluster >= cluster)
+                       continue;
+
                if (set)
                        ocfs2_set_bit(cluster % cl_cpg,
                                      (unsigned long *)gd->bg_bitmap);
@@ -99,6 +106,7 @@ static int ocfs2_update_last_group_and_inode(handle_t *handle,
        u16 chain, num_bits, backups = 0;
        u16 cl_bpc = le16_to_cpu(cl->cl_bpc);
        u16 cl_cpg = le16_to_cpu(cl->cl_cpg);
+       u16 old_bg_clusters;
 
        trace_ocfs2_update_last_group_and_inode(new_clusters,
                                                first_new_cluster);
@@ -112,6 +120,7 @@ static int ocfs2_update_last_group_and_inode(handle_t *handle,
 
        group = (struct ocfs2_group_desc *)group_bh->b_data;
 
+       old_bg_clusters = le16_to_cpu(group->bg_bits) / cl_bpc;
        /* update the group first. */
        num_bits = new_clusters * cl_bpc;
        le16_add_cpu(&group->bg_bits, num_bits);
@@ -125,7 +134,7 @@ static int ocfs2_update_last_group_and_inode(handle_t *handle,
                                     OCFS2_FEATURE_COMPAT_BACKUP_SB)) {
                backups = ocfs2_calc_new_backup_super(bm_inode,
                                                     group,
-                                                    cl_cpg, 1);
+                                                    cl_cpg, old_bg_clusters, 1);
                le16_add_cpu(&group->bg_free_bits_count, -1 * backups);
        }
 
@@ -163,7 +172,7 @@ out_rollback:
        if (ret < 0) {
                ocfs2_calc_new_backup_super(bm_inode,
                                            group,
-                                           cl_cpg, 0);
+                                           cl_cpg, old_bg_clusters, 0);
                le16_add_cpu(&group->bg_free_bits_count, backups);
                le16_add_cpu(&group->bg_bits, -1 * num_bits);
                le16_add_cpu(&group->bg_free_bits_count, -1 * num_bits);
index 66edce7ecfd78f807451bdbf724cfabc071dbd5a..6c2a3e3c521ce66fbd6085840ae69897628ca45b 100644 (file)
@@ -88,8 +88,7 @@ const struct address_space_operations ocfs2_fast_symlink_aops = {
 
 const struct inode_operations ocfs2_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = page_follow_link_light,
-       .put_link       = page_put_link,
+       .get_link       = page_get_link,
        .getattr        = ocfs2_getattr,
        .setattr        = ocfs2_setattr,
        .setxattr       = generic_setxattr,
index e9164f09841bfd6bc3f5baf439b91f8dfe5345f2..f0e241ffd94fc9d9e4ffb3d9afbda6e6eb932c3b 100644 (file)
@@ -544,8 +544,7 @@ static inline const char *ocfs2_xattr_prefix(int name_index)
 
        if (name_index > 0 && name_index < OCFS2_XATTR_MAX)
                handler = ocfs2_xattr_handler_map[name_index];
-
-       return handler ? handler->prefix : NULL;
+       return handler ? xattr_prefix(handler) : NULL;
 }
 
 static u32 ocfs2_xattr_name_hash(struct inode *inode,
@@ -884,14 +883,39 @@ static int ocfs2_xattr_value_truncate(struct inode *inode,
        return ret;
 }
 
-static int ocfs2_xattr_list_entry(char *buffer, size_t size,
-                                 size_t *result, const char *prefix,
+static int ocfs2_xattr_list_entry(struct super_block *sb,
+                                 char *buffer, size_t size,
+                                 size_t *result, int type,
                                  const char *name, int name_len)
 {
        char *p = buffer + *result;
-       int prefix_len = strlen(prefix);
-       int total_len = prefix_len + name_len + 1;
+       const char *prefix;
+       int prefix_len;
+       int total_len;
 
+       switch(type) {
+       case OCFS2_XATTR_INDEX_USER:
+               if (OCFS2_SB(sb)->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
+                       return 0;
+               break;
+
+       case OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS:
+       case OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT:
+               if (!(sb->s_flags & MS_POSIXACL))
+                       return 0;
+               break;
+
+       case OCFS2_XATTR_INDEX_TRUSTED:
+               if (!capable(CAP_SYS_ADMIN))
+                       return 0;
+               break;
+       }
+
+       prefix = ocfs2_xattr_prefix(type);
+       if (!prefix)
+               return 0;
+       prefix_len = strlen(prefix);
+       total_len = prefix_len + name_len + 1;
        *result += total_len;
 
        /* we are just looking for how big our buffer needs to be */
@@ -914,23 +938,20 @@ static int ocfs2_xattr_list_entries(struct inode *inode,
 {
        size_t result = 0;
        int i, type, ret;
-       const char *prefix, *name;
+       const char *name;
 
        for (i = 0 ; i < le16_to_cpu(header->xh_count); i++) {
                struct ocfs2_xattr_entry *entry = &header->xh_entries[i];
                type = ocfs2_xattr_get_type(entry);
-               prefix = ocfs2_xattr_prefix(type);
-
-               if (prefix) {
-                       name = (const char *)header +
-                               le16_to_cpu(entry->xe_name_offset);
+               name = (const char *)header +
+                       le16_to_cpu(entry->xe_name_offset);
 
-                       ret = ocfs2_xattr_list_entry(buffer, buffer_size,
-                                                    &result, prefix, name,
-                                                    entry->xe_name_len);
-                       if (ret)
-                               return ret;
-               }
+               ret = ocfs2_xattr_list_entry(inode->i_sb,
+                                            buffer, buffer_size,
+                                            &result, type, name,
+                                            entry->xe_name_len);
+               if (ret)
+                       return ret;
        }
 
        return result;
@@ -4033,32 +4054,30 @@ static int ocfs2_list_xattr_bucket(struct inode *inode,
        int ret = 0, type;
        struct ocfs2_xattr_tree_list *xl = (struct ocfs2_xattr_tree_list *)para;
        int i, block_off, new_offset;
-       const char *prefix, *name;
+       const char *name;
 
        for (i = 0 ; i < le16_to_cpu(bucket_xh(bucket)->xh_count); i++) {
                struct ocfs2_xattr_entry *entry = &bucket_xh(bucket)->xh_entries[i];
                type = ocfs2_xattr_get_type(entry);
-               prefix = ocfs2_xattr_prefix(type);
 
-               if (prefix) {
-                       ret = ocfs2_xattr_bucket_get_name_value(inode->i_sb,
-                                                               bucket_xh(bucket),
-                                                               i,
-                                                               &block_off,
-                                                               &new_offset);
-                       if (ret)
-                               break;
+               ret = ocfs2_xattr_bucket_get_name_value(inode->i_sb,
+                                                       bucket_xh(bucket),
+                                                       i,
+                                                       &block_off,
+                                                       &new_offset);
+               if (ret)
+                       break;
 
-                       name = (const char *)bucket_block(bucket, block_off) +
-                               new_offset;
-                       ret = ocfs2_xattr_list_entry(xl->buffer,
-                                                    xl->buffer_size,
-                                                    &xl->result,
-                                                    prefix, name,
-                                                    entry->xe_name_len);
-                       if (ret)
-                               break;
-               }
+               name = (const char *)bucket_block(bucket, block_off) +
+                       new_offset;
+               ret = ocfs2_xattr_list_entry(inode->i_sb,
+                                            xl->buffer,
+                                            xl->buffer_size,
+                                            &xl->result,
+                                            type, name,
+                                            entry->xe_name_len);
+               if (ret)
+                       break;
        }
 
        return ret;
@@ -7226,31 +7245,14 @@ int ocfs2_init_security_and_acl(struct inode *dir,
 leave:
        return ret;
 }
+
 /*
  * 'security' attributes support
  */
-static size_t ocfs2_xattr_security_list(const struct xattr_handler *handler,
-                                       struct dentry *dentry, char *list,
-                                       size_t list_size, const char *name,
-                                       size_t name_len)
-{
-       const size_t prefix_len = XATTR_SECURITY_PREFIX_LEN;
-       const size_t total_len = prefix_len + name_len + 1;
-
-       if (list && total_len <= list_size) {
-               memcpy(list, XATTR_SECURITY_PREFIX, prefix_len);
-               memcpy(list + prefix_len, name, name_len);
-               list[prefix_len + name_len] = '\0';
-       }
-       return total_len;
-}
-
 static int ocfs2_xattr_security_get(const struct xattr_handler *handler,
                                    struct dentry *dentry, const char *name,
                                    void *buffer, size_t size)
 {
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
        return ocfs2_xattr_get(d_inode(dentry), OCFS2_XATTR_INDEX_SECURITY,
                               name, buffer, size);
 }
@@ -7259,9 +7261,6 @@ static int ocfs2_xattr_security_set(const struct xattr_handler *handler,
                                    struct dentry *dentry, const char *name,
                                    const void *value, size_t size, int flags)
 {
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
-
        return ocfs2_xattr_set(d_inode(dentry), OCFS2_XATTR_INDEX_SECURITY,
                               name, value, size, flags);
 }
@@ -7314,7 +7313,6 @@ int ocfs2_init_security_set(handle_t *handle,
 
 const struct xattr_handler ocfs2_xattr_security_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
-       .list   = ocfs2_xattr_security_list,
        .get    = ocfs2_xattr_security_get,
        .set    = ocfs2_xattr_security_set,
 };
@@ -7322,31 +7320,10 @@ const struct xattr_handler ocfs2_xattr_security_handler = {
 /*
  * 'trusted' attributes support
  */
-static size_t ocfs2_xattr_trusted_list(const struct xattr_handler *handler,
-                                      struct dentry *dentry, char *list,
-                                      size_t list_size, const char *name,
-                                      size_t name_len)
-{
-       const size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN;
-       const size_t total_len = prefix_len + name_len + 1;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return 0;
-
-       if (list && total_len <= list_size) {
-               memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len);
-               memcpy(list + prefix_len, name, name_len);
-               list[prefix_len + name_len] = '\0';
-       }
-       return total_len;
-}
-
 static int ocfs2_xattr_trusted_get(const struct xattr_handler *handler,
                                   struct dentry *dentry, const char *name,
                                   void *buffer, size_t size)
 {
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
        return ocfs2_xattr_get(d_inode(dentry), OCFS2_XATTR_INDEX_TRUSTED,
                               name, buffer, size);
 }
@@ -7355,16 +7332,12 @@ static int ocfs2_xattr_trusted_set(const struct xattr_handler *handler,
                                   struct dentry *dentry, const char *name,
                                   const void *value, size_t size, int flags)
 {
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
-
        return ocfs2_xattr_set(d_inode(dentry), OCFS2_XATTR_INDEX_TRUSTED,
                               name, value, size, flags);
 }
 
 const struct xattr_handler ocfs2_xattr_trusted_handler = {
        .prefix = XATTR_TRUSTED_PREFIX,
-       .list   = ocfs2_xattr_trusted_list,
        .get    = ocfs2_xattr_trusted_get,
        .set    = ocfs2_xattr_trusted_set,
 };
@@ -7372,34 +7345,12 @@ const struct xattr_handler ocfs2_xattr_trusted_handler = {
 /*
  * 'user' attributes support
  */
-static size_t ocfs2_xattr_user_list(const struct xattr_handler *handler,
-                                   struct dentry *dentry, char *list,
-                                   size_t list_size, const char *name,
-                                   size_t name_len)
-{
-       const size_t prefix_len = XATTR_USER_PREFIX_LEN;
-       const size_t total_len = prefix_len + name_len + 1;
-       struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
-
-       if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
-               return 0;
-
-       if (list && total_len <= list_size) {
-               memcpy(list, XATTR_USER_PREFIX, prefix_len);
-               memcpy(list + prefix_len, name, name_len);
-               list[prefix_len + name_len] = '\0';
-       }
-       return total_len;
-}
-
 static int ocfs2_xattr_user_get(const struct xattr_handler *handler,
                                struct dentry *dentry, const char *name,
                                void *buffer, size_t size)
 {
        struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
 
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
        if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
                return -EOPNOTSUPP;
        return ocfs2_xattr_get(d_inode(dentry), OCFS2_XATTR_INDEX_USER, name,
@@ -7412,8 +7363,6 @@ static int ocfs2_xattr_user_set(const struct xattr_handler *handler,
 {
        struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
 
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
        if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
                return -EOPNOTSUPP;
 
@@ -7423,7 +7372,6 @@ static int ocfs2_xattr_user_set(const struct xattr_handler *handler,
 
 const struct xattr_handler ocfs2_xattr_user_handler = {
        .prefix = XATTR_USER_PREFIX,
-       .list   = ocfs2_xattr_user_list,
        .get    = ocfs2_xattr_user_get,
        .set    = ocfs2_xattr_user_set,
 };
index 4060ffde87225c81114d086c000773d4019255b5..964a60fa7afc53ad902c05b23daac017ba78fc1e 100644 (file)
@@ -131,57 +131,23 @@ out_dput:
        return err;
 }
 
-
-struct ovl_link_data {
-       struct dentry *realdentry;
-       void *cookie;
-};
-
-static const char *ovl_follow_link(struct dentry *dentry, void **cookie)
+static const char *ovl_get_link(struct dentry *dentry,
+                               struct inode *inode,
+                               struct delayed_call *done)
 {
        struct dentry *realdentry;
        struct inode *realinode;
-       struct ovl_link_data *data = NULL;
-       const char *ret;
+
+       if (!dentry)
+               return ERR_PTR(-ECHILD);
 
        realdentry = ovl_dentry_real(dentry);
        realinode = realdentry->d_inode;
 
-       if (WARN_ON(!realinode->i_op->follow_link))
+       if (WARN_ON(!realinode->i_op->get_link))
                return ERR_PTR(-EPERM);
 
-       if (realinode->i_op->put_link) {
-               data = kmalloc(sizeof(struct ovl_link_data), GFP_KERNEL);
-               if (!data)
-                       return ERR_PTR(-ENOMEM);
-               data->realdentry = realdentry;
-       }
-
-       ret = realinode->i_op->follow_link(realdentry, cookie);
-       if (IS_ERR_OR_NULL(ret)) {
-               kfree(data);
-               return ret;
-       }
-
-       if (data)
-               data->cookie = *cookie;
-
-       *cookie = data;
-
-       return ret;
-}
-
-static void ovl_put_link(struct inode *unused, void *c)
-{
-       struct inode *realinode;
-       struct ovl_link_data *data = c;
-
-       if (!data)
-               return;
-
-       realinode = data->realdentry->d_inode;
-       realinode->i_op->put_link(realinode, data->cookie);
-       kfree(data);
+       return realinode->i_op->get_link(realdentry, realinode, done);
 }
 
 static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
@@ -378,8 +344,7 @@ static const struct inode_operations ovl_file_inode_operations = {
 
 static const struct inode_operations ovl_symlink_inode_operations = {
        .setattr        = ovl_setattr,
-       .follow_link    = ovl_follow_link,
-       .put_link       = ovl_put_link,
+       .get_link       = ovl_get_link,
        .readlink       = ovl_readlink,
        .getattr        = ovl_getattr,
        .setxattr       = ovl_setxattr,
index 4adde1e2cbece693ebab67527a555e3a33e6fbfa..711dd517037689ac03fa1b31085a72ca010ab314 100644 (file)
@@ -769,8 +769,6 @@ posix_acl_xattr_get(const struct xattr_handler *handler,
        struct posix_acl *acl;
        int error;
 
-       if (strcmp(name, "") != 0)
-               return -EINVAL;
        if (!IS_POSIXACL(d_backing_inode(dentry)))
                return -EOPNOTSUPP;
        if (d_is_symlink(dentry))
@@ -797,8 +795,6 @@ posix_acl_xattr_set(const struct xattr_handler *handler,
        struct posix_acl *acl = NULL;
        int ret;
 
-       if (strcmp(name, "") != 0)
-               return -EINVAL;
        if (!IS_POSIXACL(inode))
                return -EOPNOTSUPP;
        if (!inode->i_op->set_acl)
@@ -827,25 +823,14 @@ out:
        return ret;
 }
 
-static size_t
-posix_acl_xattr_list(const struct xattr_handler *handler,
-                    struct dentry *dentry, char *list, size_t list_size,
-                    const char *name, size_t name_len)
+static bool
+posix_acl_xattr_list(struct dentry *dentry)
 {
-       const char *xname = handler->prefix;
-       size_t size;
-
-       if (!IS_POSIXACL(d_backing_inode(dentry)))
-               return 0;
-
-       size = strlen(xname) + 1;
-       if (list && size <= list_size)
-               memcpy(list, xname, size);
-       return size;
+       return IS_POSIXACL(d_backing_inode(dentry));
 }
 
 const struct xattr_handler posix_acl_access_xattr_handler = {
-       .prefix = POSIX_ACL_XATTR_ACCESS,
+       .name = XATTR_NAME_POSIX_ACL_ACCESS,
        .flags = ACL_TYPE_ACCESS,
        .list = posix_acl_xattr_list,
        .get = posix_acl_xattr_get,
@@ -854,7 +839,7 @@ const struct xattr_handler posix_acl_access_xattr_handler = {
 EXPORT_SYMBOL_GPL(posix_acl_access_xattr_handler);
 
 const struct xattr_handler posix_acl_default_xattr_handler = {
-       .prefix = POSIX_ACL_XATTR_DEFAULT,
+       .name = XATTR_NAME_POSIX_ACL_DEFAULT,
        .flags = ACL_TYPE_DEFAULT,
        .list = posix_acl_xattr_list,
        .get = posix_acl_xattr_get,
index 4bd5d3118acd4b152d6e6f17b38b0a03b0f723d6..55e01f88eac9d1156e240700598fd9688c6c503e 100644 (file)
@@ -1564,12 +1564,16 @@ static int proc_exe_link(struct dentry *dentry, struct path *exe_path)
                return -ENOENT;
 }
 
-static const char *proc_pid_follow_link(struct dentry *dentry, void **cookie)
+static const char *proc_pid_get_link(struct dentry *dentry,
+                                    struct inode *inode,
+                                    struct delayed_call *done)
 {
-       struct inode *inode = d_inode(dentry);
        struct path path;
        int error = -EACCES;
 
+       if (!dentry)
+               return ERR_PTR(-ECHILD);
+
        /* Are we allowed to snoop on the tasks file descriptors? */
        if (!proc_fd_access_allowed(inode))
                goto out;
@@ -1630,7 +1634,7 @@ out:
 
 const struct inode_operations proc_pid_link_inode_operations = {
        .readlink       = proc_pid_readlink,
-       .follow_link    = proc_pid_follow_link,
+       .get_link       = proc_pid_get_link,
        .setattr        = proc_setattr,
 };
 
@@ -1895,7 +1899,7 @@ static const struct dentry_operations tid_map_files_dentry_operations = {
        .d_delete       = pid_delete_dentry,
 };
 
-static int proc_map_files_get_link(struct dentry *dentry, struct path *path)
+static int map_files_get_link(struct dentry *dentry, struct path *path)
 {
        unsigned long vm_start, vm_end;
        struct vm_area_struct *vma;
@@ -1945,20 +1949,22 @@ struct map_files_info {
  * path to the file in question.
  */
 static const char *
-proc_map_files_follow_link(struct dentry *dentry, void **cookie)
+proc_map_files_get_link(struct dentry *dentry,
+                       struct inode *inode,
+                       struct delayed_call *done)
 {
        if (!capable(CAP_SYS_ADMIN))
                return ERR_PTR(-EPERM);
 
-       return proc_pid_follow_link(dentry, NULL);
+       return proc_pid_get_link(dentry, inode, done);
 }
 
 /*
- * Identical to proc_pid_link_inode_operations except for follow_link()
+ * Identical to proc_pid_link_inode_operations except for get_link()
  */
 static const struct inode_operations proc_map_files_link_inode_operations = {
        .readlink       = proc_pid_readlink,
-       .follow_link    = proc_map_files_follow_link,
+       .get_link       = proc_map_files_get_link,
        .setattr        = proc_setattr,
 };
 
@@ -1975,7 +1981,7 @@ proc_map_files_instantiate(struct inode *dir, struct dentry *dentry,
                return -ENOENT;
 
        ei = PROC_I(inode);
-       ei->op.proc_get_link = proc_map_files_get_link;
+       ei->op.proc_get_link = map_files_get_link;
 
        inode->i_op = &proc_map_files_link_inode_operations;
        inode->i_size = 64;
index bd95b9fdebb005cd9912c3b80027cfc1659fc530..d0e9b9b6223e984879620839effb830fb7937219 100644 (file)
@@ -393,24 +393,25 @@ static const struct file_operations proc_reg_file_ops_no_compat = {
 };
 #endif
 
-static const char *proc_follow_link(struct dentry *dentry, void **cookie)
+static void proc_put_link(void *p)
 {
-       struct proc_dir_entry *pde = PDE(d_inode(dentry));
-       if (unlikely(!use_pde(pde)))
-               return ERR_PTR(-EINVAL);
-       *cookie = pde;
-       return pde->data;
+       unuse_pde(p);
 }
 
-static void proc_put_link(struct inode *unused, void *p)
+static const char *proc_get_link(struct dentry *dentry,
+                                struct inode *inode,
+                                struct delayed_call *done)
 {
-       unuse_pde(p);
+       struct proc_dir_entry *pde = PDE(inode);
+       if (unlikely(!use_pde(pde)))
+               return ERR_PTR(-EINVAL);
+       set_delayed_call(done, proc_put_link, pde);
+       return pde->data;
 }
 
 const struct inode_operations proc_link_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = proc_follow_link,
-       .put_link       = proc_put_link,
+       .get_link       = proc_get_link,
 };
 
 struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)
index f6e8354b8cea20a936f6a4f8ae0335fd7fa36bd4..1dece8781f91687307155c38a4c85a3ffba5c6b9 100644 (file)
@@ -30,14 +30,18 @@ static const struct proc_ns_operations *ns_entries[] = {
        &mntns_operations,
 };
 
-static const char *proc_ns_follow_link(struct dentry *dentry, void **cookie)
+static const char *proc_ns_get_link(struct dentry *dentry,
+                                   struct inode *inode,
+                                   struct delayed_call *done)
 {
-       struct inode *inode = d_inode(dentry);
        const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops;
        struct task_struct *task;
        struct path ns_path;
        void *error = ERR_PTR(-EACCES);
 
+       if (!dentry)
+               return ERR_PTR(-ECHILD);
+
        task = get_proc_task(inode);
        if (!task)
                return error;
@@ -74,7 +78,7 @@ static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int bufl
 
 static const struct inode_operations proc_ns_link_inode_operations = {
        .readlink       = proc_ns_readlink,
-       .follow_link    = proc_ns_follow_link,
+       .get_link       = proc_ns_get_link,
        .setattr        = proc_setattr,
 };
 
index 113b8d061fc023858ab152a5033e029d085f27a6..67e8db442cf03802c7758a76dd8adf79b46a3a50 100644 (file)
@@ -18,26 +18,28 @@ static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
        return readlink_copy(buffer, buflen, tmp);
 }
 
-static const char *proc_self_follow_link(struct dentry *dentry, void **cookie)
+static const char *proc_self_get_link(struct dentry *dentry,
+                                     struct inode *inode,
+                                     struct delayed_call *done)
 {
-       struct pid_namespace *ns = dentry->d_sb->s_fs_info;
+       struct pid_namespace *ns = inode->i_sb->s_fs_info;
        pid_t tgid = task_tgid_nr_ns(current, ns);
        char *name;
 
        if (!tgid)
                return ERR_PTR(-ENOENT);
        /* 11 for max length of signed int in decimal + NULL term */
-       name = kmalloc(12, GFP_KERNEL);
-       if (!name)
-               return ERR_PTR(-ENOMEM);
+       name = kmalloc(12, dentry ? GFP_KERNEL : GFP_ATOMIC);
+       if (unlikely(!name))
+               return dentry ? ERR_PTR(-ENOMEM) : ERR_PTR(-ECHILD);
        sprintf(name, "%d", tgid);
-       return *cookie = name;
+       set_delayed_call(done, kfree_link, name);
+       return name;
 }
 
 static const struct inode_operations proc_self_inode_operations = {
        .readlink       = proc_self_readlink,
-       .follow_link    = proc_self_follow_link,
-       .put_link       = kfree_put_link,
+       .get_link       = proc_self_get_link,
 };
 
 static unsigned self_inum;
index 947b0f4fd0a194057334762bafeff3548c276568..9eacd59e0360f1367a084a1e7bfa5dca0e3fe170 100644 (file)
@@ -19,26 +19,29 @@ static int proc_thread_self_readlink(struct dentry *dentry, char __user *buffer,
        return readlink_copy(buffer, buflen, tmp);
 }
 
-static const char *proc_thread_self_follow_link(struct dentry *dentry, void **cookie)
+static const char *proc_thread_self_get_link(struct dentry *dentry,
+                                            struct inode *inode,
+                                            struct delayed_call *done)
 {
-       struct pid_namespace *ns = dentry->d_sb->s_fs_info;
+       struct pid_namespace *ns = inode->i_sb->s_fs_info;
        pid_t tgid = task_tgid_nr_ns(current, ns);
        pid_t pid = task_pid_nr_ns(current, ns);
        char *name;
 
        if (!pid)
                return ERR_PTR(-ENOENT);
-       name = kmalloc(PROC_NUMBUF + 6 + PROC_NUMBUF, GFP_KERNEL);
-       if (!name)
-               return ERR_PTR(-ENOMEM);
+       name = kmalloc(PROC_NUMBUF + 6 + PROC_NUMBUF,
+                               dentry ? GFP_KERNEL : GFP_ATOMIC);
+       if (unlikely(!name))
+               return dentry ? ERR_PTR(-ENOMEM) : ERR_PTR(-ECHILD);
        sprintf(name, "%d/task/%d", tgid, pid);
-       return *cookie = name;
+       set_delayed_call(done, kfree_link, name);
+       return name;
 }
 
 static const struct inode_operations proc_thread_self_inode_operations = {
        .readlink       = proc_thread_self_readlink,
-       .follow_link    = proc_thread_self_follow_link,
-       .put_link       = kfree_put_link,
+       .get_link       = proc_thread_self_get_link,
 };
 
 static unsigned thread_self_inum;
index c4bcb778886e5c79c4dcc9381cf13f0a76358838..f37b3deb01b4d5f2d07ea90774a5bf99c39992bd 100644 (file)
@@ -316,6 +316,7 @@ struct inode *qnx4_iget(struct super_block *sb, unsigned long ino)
                inode->i_fop = &qnx4_dir_operations;
        } else if (S_ISLNK(inode->i_mode)) {
                inode->i_op = &page_symlink_inode_operations;
+               inode_nohighmem(inode);
                inode->i_mapping->a_ops = &qnx4_aops;
                qnx4_i(inode)->mmu_private = inode->i_size;
        } else {
index 32d2e1a9774ca66005d92786df99a70865efb3fa..9728b5499e1d5a1eae80344ff0e9e76dd1a04153 100644 (file)
@@ -582,6 +582,7 @@ struct inode *qnx6_iget(struct super_block *sb, unsigned ino)
                inode->i_mapping->a_ops = &qnx6_aops;
        } else if (S_ISLNK(inode->i_mode)) {
                inode->i_op = &page_symlink_inode_operations;
+               inode_nohighmem(inode);
                inode->i_mapping->a_ops = &qnx6_aops;
        } else
                init_special_inode(inode, inode->i_mode, 0);
index 889d558b4e05518e6b14280d8ffea7ec28d7f85c..38981b03752433de71197c5c724999a33dc2d53d 100644 (file)
@@ -79,6 +79,7 @@ struct inode *ramfs_get_inode(struct super_block *sb,
                        break;
                case S_IFLNK:
                        inode->i_op = &page_symlink_inode_operations;
+                       inode_nohighmem(inode);
                        break;
                }
        }
index 3d8e7e671d5ba7d15fe4a14e1b803673c220cdee..ae9e5b308cf9f5775300e7ee109e4e2f72720b12 100644 (file)
@@ -1361,6 +1361,7 @@ static void init_inode(struct inode *inode, struct treepath *path)
                inode->i_fop = &reiserfs_dir_operations;
        } else if (S_ISLNK(inode->i_mode)) {
                inode->i_op = &reiserfs_symlink_inode_operations;
+               inode_nohighmem(inode);
                inode->i_mapping->a_ops = &reiserfs_address_space_operations;
        } else {
                inode->i_blocks = 0;
index 47f96988fdd478dbc6ce325232d38754258864cc..2a12d46d7fb4154e2119ac94c50a7e74c998c437 100644 (file)
@@ -1170,6 +1170,7 @@ static int reiserfs_symlink(struct inode *parent_dir,
        reiserfs_update_inode_transaction(parent_dir);
 
        inode->i_op = &reiserfs_symlink_inode_operations;
+       inode_nohighmem(inode);
        inode->i_mapping->a_ops = &reiserfs_address_space_operations;
 
        retval = reiserfs_add_entry(&th, parent_dir, dentry->d_name.name,
@@ -1664,8 +1665,7 @@ const struct inode_operations reiserfs_dir_inode_operations = {
  */
 const struct inode_operations reiserfs_symlink_inode_operations = {
        .readlink = generic_readlink,
-       .follow_link = page_follow_link_light,
-       .put_link = page_put_link,
+       .get_link       = page_get_link,
        .setattr = reiserfs_setattr,
        .setxattr = reiserfs_setxattr,
        .getxattr = reiserfs_getxattr,
index 66b26fdfff8d6de51082b48b0f9a61fba9567466..e5ddb4e5ea9497956cfa7b04dca84eba790829d1 100644 (file)
@@ -756,7 +756,8 @@ find_xattr_handler_prefix(const struct xattr_handler **handlers,
                return NULL;
 
        for_each_xattr_handler(handlers, xah) {
-               if (strncmp(xah->prefix, name, strlen(xah->prefix)) == 0)
+               const char *prefix = xattr_prefix(xah);
+               if (strncmp(prefix, name, strlen(prefix)) == 0)
                        break;
        }
 
@@ -839,19 +840,16 @@ static int listxattr_filler(struct dir_context *ctx, const char *name,
 
                handler = find_xattr_handler_prefix(b->dentry->d_sb->s_xattr,
                                                    name);
-               if (!handler)   /* Unsupported xattr name */
+               if (!handler /* Unsupported xattr name */ ||
+                   (handler->list && !handler->list(b->dentry)))
                        return 0;
+               size = namelen + 1;
                if (b->buf) {
-                       size = handler->list(handler, b->dentry,
-                                            b->buf + b->pos, b->size, name,
-                                            namelen);
                        if (size > b->size)
                                return -ERANGE;
-               } else {
-                       size = handler->list(handler, b->dentry,
-                                            NULL, 0, name, namelen);
+                       memcpy(b->buf + b->pos, name, namelen);
+                       b->buf[b->pos + namelen] = 0;
                }
-
                b->pos += size;
        }
        return 0;
index 4b34b9dc03dda9fffd8da5d3ab7221bd9ab139b7..558a16beaacb994749e74cf74acf869f611a1064 100644 (file)
@@ -186,10 +186,10 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
 
        switch (type) {
        case ACL_TYPE_ACCESS:
-               name = POSIX_ACL_XATTR_ACCESS;
+               name = XATTR_NAME_POSIX_ACL_ACCESS;
                break;
        case ACL_TYPE_DEFAULT:
-               name = POSIX_ACL_XATTR_DEFAULT;
+               name = XATTR_NAME_POSIX_ACL_DEFAULT;
                break;
        default:
                BUG();
@@ -244,7 +244,7 @@ __reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
 
        switch (type) {
        case ACL_TYPE_ACCESS:
-               name = POSIX_ACL_XATTR_ACCESS;
+               name = XATTR_NAME_POSIX_ACL_ACCESS;
                if (acl) {
                        error = posix_acl_equiv_mode(acl, &inode->i_mode);
                        if (error < 0)
@@ -256,7 +256,7 @@ __reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
                }
                break;
        case ACL_TYPE_DEFAULT:
-               name = POSIX_ACL_XATTR_DEFAULT;
+               name = XATTR_NAME_POSIX_ACL_DEFAULT;
                if (!S_ISDIR(inode->i_mode))
                        return acl ? -EACCES : 0;
                break;
index ac659af431aec83d5ba7b85e7b69c1ac49e7b4c0..ab0217d320396447110e0d8d3218d22b69046352 100644 (file)
@@ -34,21 +34,9 @@ security_set(const struct xattr_handler *handler, struct dentry *dentry,
        return reiserfs_xattr_set(d_inode(dentry), name, buffer, size, flags);
 }
 
-static size_t security_list(const struct xattr_handler *handler,
-                           struct dentry *dentry, char *list, size_t list_len,
-                           const char *name, size_t namelen)
+static bool security_list(struct dentry *dentry)
 {
-       const size_t len = namelen + 1;
-
-       if (IS_PRIVATE(d_inode(dentry)))
-               return 0;
-
-       if (list && len <= list_len) {
-               memcpy(list, name, namelen);
-               list[namelen] = '\0';
-       }
-
-       return len;
+       return !IS_PRIVATE(d_inode(dentry));
 }
 
 /* Initializes the security context for a new inode and returns the number
index a338adf1b8b4816c19ca84557a0142179f93b9a7..64b67aa643a96909b2759824fcbfdd0fda43c562 100644 (file)
@@ -33,20 +33,9 @@ trusted_set(const struct xattr_handler *handler, struct dentry *dentry,
        return reiserfs_xattr_set(d_inode(dentry), name, buffer, size, flags);
 }
 
-static size_t trusted_list(const struct xattr_handler *handler,
-                          struct dentry *dentry, char *list, size_t list_size,
-                          const char *name, size_t name_len)
+static bool trusted_list(struct dentry *dentry)
 {
-       const size_t len = name_len + 1;
-
-       if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(d_inode(dentry)))
-               return 0;
-
-       if (list && len <= list_size) {
-               memcpy(list, name, name_len);
-               list[name_len] = '\0';
-       }
-       return len;
+       return capable(CAP_SYS_ADMIN) && !IS_PRIVATE(d_inode(dentry));
 }
 
 const struct xattr_handler reiserfs_xattr_trusted_handler = {
index 39c9667191c5db5b3c930e538d81799b96bea6fb..12e6306f562a3f9ff1cddbf3b2818d5ae134127e 100644 (file)
@@ -30,19 +30,9 @@ user_set(const struct xattr_handler *handler, struct dentry *dentry,
        return reiserfs_xattr_set(d_inode(dentry), name, buffer, size, flags);
 }
 
-static size_t user_list(const struct xattr_handler *handler,
-                       struct dentry *dentry, char *list, size_t list_size,
-                       const char *name, size_t name_len)
+static bool user_list(struct dentry *dentry)
 {
-       const size_t len = name_len + 1;
-
-       if (!reiserfs_xattrs_user(dentry->d_sb))
-               return 0;
-       if (list && len <= list_size) {
-               memcpy(list, name, name_len);
-               list[name_len] = '\0';
-       }
-       return len;
+       return reiserfs_xattrs_user(dentry->d_sb);
 }
 
 const struct xattr_handler reiserfs_xattr_user_handler = {
index 268733cda397eb7780f45d966cdca822daad16e8..bb894e78a821ef4643e25cbf684832b5baaf054c 100644 (file)
@@ -360,6 +360,7 @@ static struct inode *romfs_iget(struct super_block *sb, unsigned long pos)
                break;
        case ROMFH_SYM:
                i->i_op = &page_symlink_inode_operations;
+               inode_nohighmem(i);
                i->i_data.a_ops = &romfs_aops;
                mode |= S_IRWXUGO;
                break;
index a1ce5ce60632e892fc0f17859e99963eb1a67235..0927b1e80ab6e0b5a039f41840131c3f40988f75 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/fs.h>
 #include <linux/vfs.h>
 #include <linux/xattr.h>
+#include <linux/pagemap.h>
 
 #include "squashfs_fs.h"
 #include "squashfs_fs_sb.h"
@@ -291,6 +292,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
                set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
                inode->i_size = le32_to_cpu(sqsh_ino->symlink_size);
                inode->i_op = &squashfs_symlink_inode_ops;
+               inode_nohighmem(inode);
                inode->i_data.a_ops = &squashfs_symlink_aops;
                inode->i_mode |= S_IFLNK;
                squashfs_i(inode)->start = block;
index 12806dffb3454ed1a898bbdd7b2ca272d071694f..dbcc2f54bad46f9af564e37f4e9b153e439d0205 100644 (file)
@@ -119,8 +119,7 @@ const struct address_space_operations squashfs_symlink_aops = {
 
 const struct inode_operations squashfs_symlink_inode_ops = {
        .readlink = generic_readlink,
-       .follow_link = page_follow_link_light,
-       .put_link = page_put_link,
+       .get_link = page_get_link,
        .getxattr = generic_getxattr,
        .listxattr = squashfs_listxattr
 };
index 6a4cc344085c0a9ecb3ce4106b168172739dd161..1e9de96288d8f8ff106ff23a248b3f654569d0ca 100644 (file)
@@ -58,7 +58,7 @@ ssize_t squashfs_listxattr(struct dentry *d, char *buffer,
                struct squashfs_xattr_entry entry;
                struct squashfs_xattr_val val;
                const struct xattr_handler *handler;
-               int name_size, prefix_size = 0;
+               int name_size;
 
                err = squashfs_read_metadata(sb, &entry, &start, &offset,
                                                        sizeof(entry));
@@ -67,15 +67,16 @@ ssize_t squashfs_listxattr(struct dentry *d, char *buffer,
 
                name_size = le16_to_cpu(entry.size);
                handler = squashfs_xattr_handler(le16_to_cpu(entry.type));
-               if (handler)
-                       prefix_size = handler->list(handler, d, buffer, rest,
-                                                   NULL, name_size);
-               if (prefix_size) {
+               if (handler && (!handler->list || handler->list(d))) {
+                       const char *prefix = handler->prefix ?: handler->name;
+                       size_t prefix_size = strlen(prefix);
+
                        if (buffer) {
                                if (prefix_size + name_size + 1 > rest) {
                                        err = -ERANGE;
                                        goto failed;
                                }
+                               memcpy(buffer, prefix, prefix_size);
                                buffer += prefix_size;
                        }
                        err = squashfs_read_metadata(sb, buffer, &start,
@@ -212,25 +213,10 @@ failed:
 }
 
 
-static size_t squashfs_xattr_handler_list(const struct xattr_handler *handler,
-                                         struct dentry *d, char *list,
-                                         size_t list_size, const char *name,
-                                         size_t name_len)
-{
-       int len = strlen(handler->prefix);
-
-       if (list && len <= list_size)
-               memcpy(list, handler->prefix, len);
-       return len;
-}
-
 static int squashfs_xattr_handler_get(const struct xattr_handler *handler,
                                      struct dentry *d, const char *name,
                                      void *buffer, size_t size)
 {
-       if (name[0] == '\0')
-               return  -EINVAL;
-
        return squashfs_xattr_get(d_inode(d), handler->flags, name,
                buffer, size);
 }
@@ -241,22 +227,15 @@ static int squashfs_xattr_handler_get(const struct xattr_handler *handler,
 static const struct xattr_handler squashfs_xattr_user_handler = {
        .prefix = XATTR_USER_PREFIX,
        .flags  = SQUASHFS_XATTR_USER,
-       .list   = squashfs_xattr_handler_list,
        .get    = squashfs_xattr_handler_get
 };
 
 /*
  * Trusted namespace support
  */
-static size_t squashfs_trusted_xattr_handler_list(const struct xattr_handler *handler,
-                                                 struct dentry *d, char *list,
-                                                 size_t list_size, const char *name,
-                                                 size_t name_len)
+static bool squashfs_trusted_xattr_handler_list(struct dentry *d)
 {
-       if (!capable(CAP_SYS_ADMIN))
-               return 0;
-       return squashfs_xattr_handler_list(handler, d, list, list_size, name,
-                                          name_len);
+       return capable(CAP_SYS_ADMIN);
 }
 
 static const struct xattr_handler squashfs_xattr_trusted_handler = {
@@ -272,7 +251,6 @@ static const struct xattr_handler squashfs_xattr_trusted_handler = {
 static const struct xattr_handler squashfs_xattr_security_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
        .flags  = SQUASHFS_XATTR_SECURITY,
-       .list   = squashfs_xattr_handler_list,
        .get    = squashfs_xattr_handler_get
 };
 
index 02fa1dcc5969f6b596a6c527170fcf9193c437e5..07ac18c355e777e0fe869225a70b5d6d9dba1f24 100644 (file)
@@ -146,8 +146,7 @@ static inline void write3byte(struct sysv_sb_info *sbi,
 
 static const struct inode_operations sysv_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = page_follow_link_light,
-       .put_link       = page_put_link,
+       .get_link       = page_get_link,
        .getattr        = sysv_getattr,
 };
 
@@ -163,6 +162,7 @@ void sysv_set_inode(struct inode *inode, dev_t rdev)
                inode->i_mapping->a_ops = &sysv_aops;
        } else if (S_ISLNK(inode->i_mode)) {
                inode->i_op = &sysv_symlink_inode_operations;
+               inode_nohighmem(inode);
                inode->i_mapping->a_ops = &sysv_aops;
        } else
                init_special_inode(inode, inode->i_mode, rdev);
index 0edc128561476a804656fba068810cf47a76fa32..eff62801acbf10524e31f8ad7816c160e6f88a90 100644 (file)
@@ -1608,7 +1608,7 @@ const struct inode_operations ubifs_file_inode_operations = {
 
 const struct inode_operations ubifs_symlink_inode_operations = {
        .readlink    = generic_readlink,
-       .follow_link = simple_follow_link,
+       .get_link    = simple_get_link,
        .setattr     = ubifs_setattr,
        .getattr     = ubifs_getattr,
        .setxattr    = ubifs_setxattr,
index 8d0b3ade0ff0ef8a65f8714330a3bfd49201c0d8..055746350d16f90be47fe892d093c51d4959eedb 100644 (file)
@@ -1540,7 +1540,8 @@ reread:
                break;
        case ICBTAG_FILE_TYPE_SYMLINK:
                inode->i_data.a_ops = &udf_symlink_aops;
-               inode->i_op = &udf_symlink_inode_operations;
+               inode->i_op = &page_symlink_inode_operations;
+               inode_nohighmem(inode);
                inode->i_mode = S_IFLNK | S_IRWXUGO;
                break;
        case ICBTAG_FILE_TYPE_MAIN:
index c97b5a8d1e24cfe831824e7beff18efc84340916..42eafb91f7ff3c092fd38f6fb6136862ca6508c8 100644 (file)
@@ -921,7 +921,8 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
        }
 
        inode->i_data.a_ops = &udf_symlink_aops;
-       inode->i_op = &udf_symlink_inode_operations;
+       inode->i_op = &page_symlink_inode_operations;
+       inode_nohighmem(inode);
 
        if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
                struct kernel_lb_addr eloc;
@@ -1344,8 +1345,3 @@ const struct inode_operations udf_dir_inode_operations = {
        .rename                         = udf_rename,
        .tmpfile                        = udf_tmpfile,
 };
-const struct inode_operations udf_symlink_inode_operations = {
-       .readlink       = generic_readlink,
-       .follow_link    = page_follow_link_light,
-       .put_link       = page_put_link,
-};
index 862535b3ba58a8a6f6ca3d23b35b0b66fee36c22..8d619773056b5ef0b0a3f2d7dd27b74a6eb76434 100644 (file)
@@ -107,7 +107,7 @@ static int udf_symlink_filler(struct file *file, struct page *page)
        struct buffer_head *bh = NULL;
        unsigned char *symlink;
        int err;
-       unsigned char *p = kmap(page);
+       unsigned char *p = page_address(page);
        struct udf_inode_info *iinfo;
        uint32_t pos;
 
@@ -141,7 +141,6 @@ static int udf_symlink_filler(struct file *file, struct page *page)
 
        up_read(&iinfo->i_data_sem);
        SetPageUptodate(page);
-       kunmap(page);
        unlock_page(page);
        return 0;
 
@@ -149,7 +148,6 @@ out_unlock_inode:
        up_read(&iinfo->i_data_sem);
        SetPageError(page);
 out_unmap:
-       kunmap(page);
        unlock_page(page);
        return err;
 }
index 47bb3f5ca360d4f1be8f92036685278868ab99e3..ce169b49429d86a2b18e84b1e1159fad2eb5651d 100644 (file)
@@ -85,7 +85,6 @@ 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 392db25c0b567a7ddcd8eeaf403bd564875023df..ec4a6b49fa13fae382c9968bfb30a18943836c7f 100644 (file)
@@ -5,5 +5,5 @@
 obj-$(CONFIG_UFS_FS) += ufs.o
 
 ufs-objs := balloc.o cylinder.o dir.o file.o ialloc.o inode.o \
-           namei.o super.o symlink.o util.o
+           namei.o super.o util.o
 ccflags-$(CONFIG_UFS_DEBUG)    += -DDEBUG
index a064cf44b1435c838a5f446f048ed00b68d48e7b..d897e169ab9c4f240e1f4023955f37bf0fe8f266 100644 (file)
@@ -528,11 +528,12 @@ static void ufs_set_inode_ops(struct inode *inode)
                inode->i_mapping->a_ops = &ufs_aops;
        } else if (S_ISLNK(inode->i_mode)) {
                if (!inode->i_blocks) {
-                       inode->i_op = &ufs_fast_symlink_inode_operations;
                        inode->i_link = (char *)UFS_I(inode)->i_u1.i_symlink;
+                       inode->i_op = &simple_symlink_inode_operations;
                } else {
-                       inode->i_op = &ufs_symlink_inode_operations;
                        inode->i_mapping->a_ops = &ufs_aops;
+                       inode->i_op = &page_symlink_inode_operations;
+                       inode_nohighmem(inode);
                }
        } else
                init_special_inode(inode, inode->i_mode,
index 47966554317c922da9c73d904f0ea104ec0392f2..acf4a3b61b81fcc58342819eabbc768e6ba33bae 100644 (file)
@@ -123,14 +123,15 @@ static int ufs_symlink (struct inode * dir, struct dentry * dentry,
 
        if (l > UFS_SB(sb)->s_uspi->s_maxsymlinklen) {
                /* slow symlink */
-               inode->i_op = &ufs_symlink_inode_operations;
+               inode->i_op = &page_symlink_inode_operations;
+               inode_nohighmem(inode);
                inode->i_mapping->a_ops = &ufs_aops;
                err = page_symlink(inode, symname, l);
                if (err)
                        goto out_fail;
        } else {
                /* fast symlink */
-               inode->i_op = &ufs_fast_symlink_inode_operations;
+               inode->i_op = &simple_symlink_inode_operations;
                inode->i_link = (char *)UFS_I(inode)->i_u1.i_symlink;
                memcpy(inode->i_link, symname, l);
                inode->i_size = l-1;
diff --git a/fs/ufs/symlink.c b/fs/ufs/symlink.c
deleted file mode 100644 (file)
index 874480b..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- *  linux/fs/ufs/symlink.c
- *
- * Only fast symlinks left here - the rest is done by generic code. AV, 1999
- *
- * Copyright (C) 1998
- * Daniel Pirkl <daniel.pirkl@emai.cz>
- * Charles University, Faculty of Mathematics and Physics
- *
- *  from
- *
- *  linux/fs/ext2/symlink.c
- *
- * Copyright (C) 1992, 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- *
- *  from
- *
- *  linux/fs/minix/symlink.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *
- *  ext2 symlink handling code
- */
-
-#include "ufs_fs.h"
-#include "ufs.h"
-
-const struct inode_operations ufs_fast_symlink_inode_operations = {
-       .readlink       = generic_readlink,
-       .follow_link    = simple_follow_link,
-       .setattr        = ufs_setattr,
-};
-
-const struct inode_operations ufs_symlink_inode_operations = {
-       .readlink       = generic_readlink,
-       .follow_link    = page_follow_link_light,
-       .put_link       = page_put_link,
-       .setattr        = ufs_setattr,
-};
index 7da4aca868c067b57c9d012f12bdffdf788d1a05..c87f4c3fa9ddd87849403a58e817a63ebf441cf1 100644 (file)
@@ -136,10 +136,6 @@ extern __printf(3, 4)
 void ufs_panic(struct super_block *, const char *, const char *, ...);
 void ufs_mark_sb_dirty(struct super_block *sb);
 
-/* symlink.c */
-extern const struct inode_operations ufs_fast_symlink_inode_operations;
-extern const struct inode_operations ufs_symlink_inode_operations;
-
 static inline struct ufs_sb_info *UFS_SB(struct super_block *sb)
 {
        return sb->s_fs_info;
index 9b932b95d74e4faeb5653d1a3c4b11553d1e51e1..d7f5037a17b5585676e8594498f59da94a087650 100644 (file)
@@ -208,25 +208,6 @@ vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value,
        return error;
 }
 
-/* Compare an extended attribute value with the given value */
-int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name,
-                 const char *value, size_t size, gfp_t flags)
-{
-       char *xattr_value = NULL;
-       int rc;
-
-       rc = vfs_getxattr_alloc(dentry, xattr_name, &xattr_value, 0, flags);
-       if (rc < 0)
-               return rc;
-
-       if ((rc != size) || (memcmp(xattr_value, value, rc) != 0))
-               rc = -EINVAL;
-       else
-               rc = 0;
-       kfree(xattr_value);
-       return rc;
-}
-
 ssize_t
 vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
 {
@@ -700,13 +681,20 @@ xattr_resolve_name(const struct xattr_handler **handlers, const char **name)
                return NULL;
 
        for_each_xattr_handler(handlers, handler) {
-               const char *n = strcmp_prefix(*name, handler->prefix);
+               const char *n;
+
+               n = strcmp_prefix(*name, xattr_prefix(handler));
                if (n) {
+                       if (!handler->prefix ^ !*n) {
+                               if (*n)
+                                       continue;
+                               return ERR_PTR(-EINVAL);
+                       }
                        *name = n;
-                       break;
+                       return handler;
                }
        }
-       return handler;
+       return ERR_PTR(-EOPNOTSUPP);
 }
 
 /*
@@ -718,8 +706,8 @@ generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t s
        const struct xattr_handler *handler;
 
        handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
-       if (!handler)
-               return -EOPNOTSUPP;
+       if (IS_ERR(handler))
+               return PTR_ERR(handler);
        return handler->get(handler, dentry, name, buffer, size);
 }
 
@@ -735,19 +723,25 @@ generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
 
        if (!buffer) {
                for_each_xattr_handler(handlers, handler) {
-                       size += handler->list(handler, dentry, NULL, 0,
-                                             NULL, 0);
+                       if (!handler->name ||
+                           (handler->list && !handler->list(dentry)))
+                               continue;
+                       size += strlen(handler->name) + 1;
                }
        } else {
                char *buf = buffer;
+               size_t len;
 
                for_each_xattr_handler(handlers, handler) {
-                       size = handler->list(handler, dentry, buf, buffer_size,
-                                            NULL, 0);
-                       if (size > buffer_size)
+                       if (!handler->name ||
+                           (handler->list && !handler->list(dentry)))
+                               continue;
+                       len = strlen(handler->name);
+                       if (len + 1 > buffer_size)
                                return -ERANGE;
-                       buf += size;
-                       buffer_size -= size;
+                       memcpy(buf, handler->name, len + 1);
+                       buf += len + 1;
+                       buffer_size -= len + 1;
                }
                size = buf - buffer;
        }
@@ -765,8 +759,8 @@ generic_setxattr(struct dentry *dentry, const char *name, const void *value, siz
        if (size == 0)
                value = "";  /* empty EA, do not remove */
        handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
-       if (!handler)
-               return -EOPNOTSUPP;
+       if (IS_ERR(handler))
+               return PTR_ERR(handler);
        return handler->set(handler, dentry, name, value, size, flags);
 }
 
@@ -780,8 +774,8 @@ generic_removexattr(struct dentry *dentry, const char *name)
        const struct xattr_handler *handler;
 
        handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
-       if (!handler)
-               return -EOPNOTSUPP;
+       if (IS_ERR(handler))
+               return PTR_ERR(handler);
        return handler->set(handler, dentry, name, NULL, 0, XATTR_REPLACE);
 }
 
@@ -808,7 +802,7 @@ EXPORT_SYMBOL(generic_removexattr);
 const char *xattr_full_name(const struct xattr_handler *handler,
                            const char *name)
 {
-       size_t prefix_len = strlen(handler->prefix);
+       size_t prefix_len = strlen(xattr_prefix(handler));
 
        return name - prefix_len;
 }
@@ -863,8 +857,22 @@ int simple_xattr_get(struct simple_xattrs *xattrs, const char *name,
        return ret;
 }
 
-static int __simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
-                             const void *value, size_t size, int flags)
+/**
+ * simple_xattr_set - xattr SET operation for in-memory/pseudo filesystems
+ * @xattrs: target simple_xattr list
+ * @name: name of the extended attribute
+ * @value: value of the xattr. If %NULL, will remove the attribute.
+ * @size: size of the new xattr
+ * @flags: %XATTR_{CREATE|REPLACE}
+ *
+ * %XATTR_CREATE is set, the xattr shouldn't exist already; otherwise fails
+ * with -EEXIST.  If %XATTR_REPLACE is set, the xattr should exist;
+ * otherwise, fails with -ENODATA.
+ *
+ * Returns 0 on success, -errno on failure.
+ */
+int simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
+                    const void *value, size_t size, int flags)
 {
        struct simple_xattr *xattr;
        struct simple_xattr *new_xattr = NULL;
@@ -914,73 +922,64 @@ out:
 
 }
 
-/**
- * simple_xattr_set - xattr SET operation for in-memory/pseudo filesystems
- * @xattrs: target simple_xattr list
- * @name: name of the new extended attribute
- * @value: value of the new xattr. If %NULL, will remove the attribute
- * @size: size of the new xattr
- * @flags: %XATTR_{CREATE|REPLACE}
- *
- * %XATTR_CREATE is set, the xattr shouldn't exist already; otherwise fails
- * with -EEXIST.  If %XATTR_REPLACE is set, the xattr should exist;
- * otherwise, fails with -ENODATA.
- *
- * Returns 0 on success, -errno on failure.
- */
-int simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
-                    const void *value, size_t size, int flags)
-{
-       if (size == 0)
-               value = ""; /* empty EA, do not remove */
-       return __simple_xattr_set(xattrs, name, value, size, flags);
-}
-
-/*
- * xattr REMOVE operation for in-memory/pseudo filesystems
- */
-int simple_xattr_remove(struct simple_xattrs *xattrs, const char *name)
+static bool xattr_is_trusted(const char *name)
 {
-       return __simple_xattr_set(xattrs, name, NULL, 0, XATTR_REPLACE);
+       return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
 }
 
-static bool xattr_is_trusted(const char *name)
+static int xattr_list_one(char **buffer, ssize_t *remaining_size,
+                         const char *name)
 {
-       return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
+       size_t len = strlen(name) + 1;
+       if (*buffer) {
+               if (*remaining_size < len)
+                       return -ERANGE;
+               memcpy(*buffer, name, len);
+               *buffer += len;
+       }
+       *remaining_size -= len;
+       return 0;
 }
 
 /*
  * xattr LIST operation for in-memory/pseudo filesystems
  */
-ssize_t simple_xattr_list(struct simple_xattrs *xattrs, char *buffer,
-                         size_t size)
+ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs,
+                         char *buffer, size_t size)
 {
        bool trusted = capable(CAP_SYS_ADMIN);
        struct simple_xattr *xattr;
-       size_t used = 0;
+       ssize_t remaining_size = size;
+       int err;
+
+#ifdef CONFIG_FS_POSIX_ACL
+       if (inode->i_acl) {
+               err = xattr_list_one(&buffer, &remaining_size,
+                                    XATTR_NAME_POSIX_ACL_ACCESS);
+               if (err)
+                       return err;
+       }
+       if (inode->i_default_acl) {
+               err = xattr_list_one(&buffer, &remaining_size,
+                                    XATTR_NAME_POSIX_ACL_DEFAULT);
+               if (err)
+                       return err;
+       }
+#endif
 
        spin_lock(&xattrs->lock);
        list_for_each_entry(xattr, &xattrs->head, list) {
-               size_t len;
-
                /* skip "trusted." attributes for unprivileged callers */
                if (!trusted && xattr_is_trusted(xattr->name))
                        continue;
 
-               len = strlen(xattr->name) + 1;
-               used += len;
-               if (buffer) {
-                       if (size < used) {
-                               used = -ERANGE;
-                               break;
-                       }
-                       memcpy(buffer, xattr->name, len);
-                       buffer += len;
-               }
+               err = xattr_list_one(&buffer, &remaining_size, xattr->name);
+               if (err)
+                       return err;
        }
        spin_unlock(&xattrs->lock);
 
-       return used;
+       return size - remaining_size;
 }
 
 /*
index 6bb470fbb8e8ff3567abfb23b774607c7eab2dda..2d5df1f23bbcbe47cebc087023d04126230cbe6c 100644 (file)
@@ -252,29 +252,6 @@ xfs_set_mode(struct inode *inode, umode_t mode)
        return error;
 }
 
-static int
-xfs_acl_exists(struct inode *inode, unsigned char *name)
-{
-       int len = XFS_ACL_MAX_SIZE(XFS_M(inode->i_sb));
-
-       return (xfs_attr_get(XFS_I(inode), name, NULL, &len,
-                           ATTR_ROOT|ATTR_KERNOVAL) == 0);
-}
-
-int
-posix_acl_access_exists(struct inode *inode)
-{
-       return xfs_acl_exists(inode, SGI_ACL_FILE);
-}
-
-int
-posix_acl_default_exists(struct inode *inode)
-{
-       if (!S_ISDIR(inode->i_mode))
-               return 0;
-       return xfs_acl_exists(inode, SGI_ACL_DEFAULT);
-}
-
 int
 xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
index 52f8255d6bdfe0c511bd9d29fb76b89a5b05efdf..286fa89217f5cbeda44bed3f28698690e1efe06e 100644 (file)
@@ -24,16 +24,12 @@ struct posix_acl;
 #ifdef CONFIG_XFS_POSIX_ACL
 extern struct posix_acl *xfs_get_acl(struct inode *inode, int type);
 extern int xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
-extern int posix_acl_access_exists(struct inode *inode);
-extern int posix_acl_default_exists(struct inode *inode);
 #else
 static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type)
 {
        return NULL;
 }
 # define xfs_set_acl                                   NULL
-# define posix_acl_access_exists(inode)                        0
-# define posix_acl_default_exists(inode)               0
 #endif /* CONFIG_XFS_POSIX_ACL */
 
 extern void xfs_forget_acl(struct inode *inode, const char *name, int xflags);
index 245268a0cdf06e4d518ee915a0add70ef5a42dc6..06eafafe636e20f90e8f696ee20c0bb01b64ea8f 100644 (file)
@@ -414,13 +414,17 @@ xfs_vn_rename(
  * uio is kmalloced for this reason...
  */
 STATIC const char *
-xfs_vn_follow_link(
+xfs_vn_get_link(
        struct dentry           *dentry,
-       void                    **cookie)
+       struct inode            *inode,
+       struct delayed_call     *done)
 {
        char                    *link;
        int                     error = -ENOMEM;
 
+       if (!dentry)
+               return ERR_PTR(-ECHILD);
+
        link = kmalloc(MAXPATHLEN+1, GFP_KERNEL);
        if (!link)
                goto out_err;
@@ -429,7 +433,8 @@ xfs_vn_follow_link(
        if (unlikely(error))
                goto out_kfree;
 
-       return *cookie = link;
+       set_delayed_call(done, kfree_link, link);
+       return link;
 
  out_kfree:
        kfree(link);
@@ -1172,8 +1177,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {
 
 static const struct inode_operations xfs_symlink_inode_operations = {
        .readlink               = generic_readlink,
-       .follow_link            = xfs_vn_follow_link,
-       .put_link               = kfree_put_link,
+       .get_link               = xfs_vn_get_link,
        .getattr                = xfs_vn_getattr,
        .setattr                = xfs_vn_setattr,
        .setxattr               = generic_setxattr,
index 839b35ca21c69320c736ac636ef681b1362402ce..110f1d7d86b0b4ab5a0fa72d8f752d5b29ea9e5f 100644 (file)
@@ -39,9 +39,6 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *dentry,
        struct xfs_inode *ip = XFS_I(d_inode(dentry));
        int error, asize = size;
 
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
-
        /* Convert Linux syscall to XFS internal ATTR flags */
        if (!size) {
                xflags |= ATTR_KERNOVAL;
@@ -84,9 +81,6 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *dentry,
        struct xfs_inode        *ip = XFS_I(d_inode(dentry));
        int                     error;
 
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
-
        /* Convert Linux syscall to XFS internal ATTR flags */
        if (flags & XATTR_CREATE)
                xflags |= ATTR_CREATE;
@@ -135,47 +129,19 @@ const struct xattr_handler *xfs_xattr_handlers[] = {
        NULL
 };
 
-static unsigned int xfs_xattr_prefix_len(int flags)
-{
-       if (flags & XFS_ATTR_SECURE)
-               return sizeof("security");
-       else if (flags & XFS_ATTR_ROOT)
-               return sizeof("trusted");
-       else
-               return sizeof("user");
-}
-
-static const char *xfs_xattr_prefix(int flags)
-{
-       if (flags & XFS_ATTR_SECURE)
-               return xfs_xattr_security_handler.prefix;
-       else if (flags & XFS_ATTR_ROOT)
-               return xfs_xattr_trusted_handler.prefix;
-       else
-               return xfs_xattr_user_handler.prefix;
-}
-
 static int
-xfs_xattr_put_listent(
+__xfs_xattr_put_listent(
        struct xfs_attr_list_context *context,
-       int             flags,
-       unsigned char   *name,
-       int             namelen,
-       int             valuelen,
-       unsigned char   *value)
+       char *prefix,
+       int prefix_len,
+       unsigned char *name,
+       int namelen)
 {
-       unsigned int prefix_len = xfs_xattr_prefix_len(flags);
        char *offset;
        int arraytop;
 
-       ASSERT(context->count >= 0);
-
-       /*
-        * Only show root namespace entries if we are actually allowed to
-        * see them.
-        */
-       if ((flags & XFS_ATTR_ROOT) && !capable(CAP_SYS_ADMIN))
-               return 0;
+       if (!context->alist)
+               goto compute_size;
 
        arraytop = context->count + prefix_len + namelen + 1;
        if (arraytop > context->firstu) {
@@ -183,17 +149,19 @@ xfs_xattr_put_listent(
                return 1;
        }
        offset = (char *)context->alist + context->count;
-       strncpy(offset, xfs_xattr_prefix(flags), prefix_len);
+       strncpy(offset, prefix, prefix_len);
        offset += prefix_len;
        strncpy(offset, (char *)name, namelen);                 /* real name */
        offset += namelen;
        *offset = '\0';
+
+compute_size:
        context->count += prefix_len + namelen + 1;
        return 0;
 }
 
 static int
-xfs_xattr_put_listent_sizes(
+xfs_xattr_put_listent(
        struct xfs_attr_list_context *context,
        int             flags,
        unsigned char   *name,
@@ -201,24 +169,55 @@ xfs_xattr_put_listent_sizes(
        int             valuelen,
        unsigned char   *value)
 {
-       context->count += xfs_xattr_prefix_len(flags) + namelen + 1;
-       return 0;
-}
+       char *prefix;
+       int prefix_len;
 
-static int
-list_one_attr(const char *name, const size_t len, void *data,
-               size_t size, ssize_t *result)
-{
-       char *p = data + *result;
+       ASSERT(context->count >= 0);
 
-       *result += len;
-       if (!size)
-               return 0;
-       if (*result > size)
-               return -ERANGE;
+       if (flags & XFS_ATTR_ROOT) {
+#ifdef CONFIG_XFS_POSIX_ACL
+               if (namelen == SGI_ACL_FILE_SIZE &&
+                   strncmp(name, SGI_ACL_FILE,
+                           SGI_ACL_FILE_SIZE) == 0) {
+                       int ret = __xfs_xattr_put_listent(
+                                       context, XATTR_SYSTEM_PREFIX,
+                                       XATTR_SYSTEM_PREFIX_LEN,
+                                       XATTR_POSIX_ACL_ACCESS,
+                                       strlen(XATTR_POSIX_ACL_ACCESS));
+                       if (ret)
+                               return ret;
+               } else if (namelen == SGI_ACL_DEFAULT_SIZE &&
+                        strncmp(name, SGI_ACL_DEFAULT,
+                                SGI_ACL_DEFAULT_SIZE) == 0) {
+                       int ret = __xfs_xattr_put_listent(
+                                       context, XATTR_SYSTEM_PREFIX,
+                                       XATTR_SYSTEM_PREFIX_LEN,
+                                       XATTR_POSIX_ACL_DEFAULT,
+                                       strlen(XATTR_POSIX_ACL_DEFAULT));
+                       if (ret)
+                               return ret;
+               }
+#endif
 
-       strcpy(p, name);
-       return 0;
+               /*
+                * Only show root namespace entries if we are actually allowed to
+                * see them.
+                */
+               if (!capable(CAP_SYS_ADMIN))
+                       return 0;
+
+               prefix = XATTR_TRUSTED_PREFIX;
+               prefix_len = XATTR_TRUSTED_PREFIX_LEN;
+       } else if (flags & XFS_ATTR_SECURE) {
+               prefix = XATTR_SECURITY_PREFIX;
+               prefix_len = XATTR_SECURITY_PREFIX_LEN;
+       } else {
+               prefix = XATTR_USER_PREFIX;
+               prefix_len = XATTR_USER_PREFIX_LEN;
+       }
+
+       return __xfs_xattr_put_listent(context, prefix, prefix_len, name,
+                                      namelen);
 }
 
 ssize_t
@@ -227,7 +226,6 @@ xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
        struct xfs_attr_list_context context;
        struct attrlist_cursor_kern cursor = { 0 };
        struct inode            *inode = d_inode(dentry);
-       int                     error;
 
        /*
         * First read the regular on-disk attributes.
@@ -236,37 +234,14 @@ xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
        context.dp = XFS_I(inode);
        context.cursor = &cursor;
        context.resynch = 1;
-       context.alist = data;
+       context.alist = size ? data : NULL;
        context.bufsize = size;
        context.firstu = context.bufsize;
-
-       if (size)
-               context.put_listent = xfs_xattr_put_listent;
-       else
-               context.put_listent = xfs_xattr_put_listent_sizes;
+       context.put_listent = xfs_xattr_put_listent;
 
        xfs_attr_list_int(&context);
        if (context.count < 0)
                return -ERANGE;
 
-       /*
-        * Then add the two synthetic ACL attributes.
-        */
-       if (posix_acl_access_exists(inode)) {
-               error = list_one_attr(POSIX_ACL_XATTR_ACCESS,
-                               strlen(POSIX_ACL_XATTR_ACCESS) + 1,
-                               data, size, &context.count);
-               if (error)
-                       return error;
-       }
-
-       if (posix_acl_default_exists(inode)) {
-               error = list_one_attr(POSIX_ACL_XATTR_DEFAULT,
-                               strlen(POSIX_ACL_XATTR_DEFAULT) + 1,
-                               data, size, &context.count);
-               if (error)
-                       return error;
-       }
-
        return context.count;
 }
index b42afada1280e08534d6e98fbf9364b3dcae9d8a..0f45f93ef6922ba1417966ba99680a96f81a19f9 100644 (file)
@@ -93,7 +93,7 @@
 #endif /* CONFIG_SMP */
 
 #ifndef smp_store_mb
-#define smp_store_mb(var, value)  do { WRITE_ONCE(var, value); mb(); } while (0)
+#define smp_store_mb(var, value)  do { WRITE_ONCE(var, value); smp_mb(); } while (0)
 #endif
 
 #ifndef smp_mb__before_atomic
index 14b0ff32fb9f16c6ce30e0e54c3f3b4885216699..3a6803cb0ec9848c31a5a200be24f3e928be520a 100644 (file)
@@ -569,7 +569,7 @@ static inline int track_pfn_copy(struct vm_area_struct *vma)
 }
 
 /*
- * untrack_pfn_vma is called while unmapping a pfnmap for a region.
+ * untrack_pfn is called while unmapping a pfnmap for a region.
  * untrack can be called for a specific region indicated by pfn and size or
  * can be for the entire vma (in which case pfn, size are zero).
  */
@@ -577,6 +577,13 @@ static inline void untrack_pfn(struct vm_area_struct *vma,
                               unsigned long pfn, unsigned long size)
 {
 }
+
+/*
+ * untrack_pfn_moved is called while mremapping a pfnmap for a new region.
+ */
+static inline void untrack_pfn_moved(struct vm_area_struct *vma)
+{
+}
 #else
 extern int track_pfn_remap(struct vm_area_struct *vma, pgprot_t *prot,
                           unsigned long pfn, unsigned long addr,
@@ -586,6 +593,7 @@ extern int track_pfn_insert(struct vm_area_struct *vma, pgprot_t *prot,
 extern int track_pfn_copy(struct vm_area_struct *vma);
 extern void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn,
                        unsigned long size);
+extern void untrack_pfn_moved(struct vm_area_struct *vma);
 #endif
 
 #ifdef __HAVE_COLOR_ZERO_PAGE
index e2aadbc7151f4cd69b8745e80a0af403257f1678..39e1cb201b8eaa00ffe759ce7147cc8b3647fb5d 100644 (file)
@@ -12,8 +12,9 @@
  * GNU General Public License for more details.
  *
  * (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+ * (C) Copyright 2015 Hewlett-Packard Enterprise Development LP
  *
- * Authors: Waiman Long <waiman.long@hp.com>
+ * Authors: Waiman Long <waiman.long@hpe.com>
  */
 #ifndef __ASM_GENERIC_QSPINLOCK_H
 #define __ASM_GENERIC_QSPINLOCK_H
@@ -62,7 +63,7 @@ static __always_inline int queued_spin_is_contended(struct qspinlock *lock)
 static __always_inline int queued_spin_trylock(struct qspinlock *lock)
 {
        if (!atomic_read(&lock->val) &&
-          (atomic_cmpxchg(&lock->val, 0, _Q_LOCKED_VAL) == 0))
+          (atomic_cmpxchg_acquire(&lock->val, 0, _Q_LOCKED_VAL) == 0))
                return 1;
        return 0;
 }
@@ -77,7 +78,7 @@ static __always_inline void queued_spin_lock(struct qspinlock *lock)
 {
        u32 val;
 
-       val = atomic_cmpxchg(&lock->val, 0, _Q_LOCKED_VAL);
+       val = atomic_cmpxchg_acquire(&lock->val, 0, _Q_LOCKED_VAL);
        if (likely(val == 0))
                return;
        queued_spin_lock_slowpath(lock, val);
@@ -93,7 +94,7 @@ static __always_inline void queued_spin_unlock(struct qspinlock *lock)
        /*
         * smp_mb__before_atomic() in order to guarantee release semantics
         */
-       smp_mb__before_atomic_dec();
+       smp_mb__before_atomic();
        atomic_sub(_Q_LOCKED_VAL, &lock->val);
 }
 #endif
index 9916d0e4eff505f18cf5e30ad52dbe2e37b3fa3b..25d0914481a26d04a001a91216df6fd68c52e87c 100644 (file)
 #define ARCH_TIMER_CTRL_IT_MASK                (1 << 1)
 #define ARCH_TIMER_CTRL_IT_STAT                (1 << 2)
 
+#define CNTHCTL_EL1PCTEN               (1 << 0)
+#define CNTHCTL_EL1PCEN                        (1 << 1)
+#define CNTHCTL_EVNTEN                 (1 << 2)
+#define CNTHCTL_EVNTDIR                        (1 << 3)
+#define CNTHCTL_EVNTI                  (0xF << 4)
+
 enum arch_timer_reg {
        ARCH_TIMER_REG_CTRL,
        ARCH_TIMER_REG_TVAL,
index d2f41477f8ae77600a8683890b3615766b9a3701..13a3d537811b9f7d12b3fa892b8312330f89d70f 100644 (file)
@@ -279,6 +279,12 @@ struct vgic_v2_cpu_if {
        u32             vgic_lr[VGIC_V2_MAX_LRS];
 };
 
+/*
+ * LRs are stored in reverse order in memory. make sure we index them
+ * correctly.
+ */
+#define VGIC_V3_LR_INDEX(lr)           (VGIC_V3_MAX_LRS - 1 - lr)
+
 struct vgic_v3_cpu_if {
 #ifdef CONFIG_KVM_ARM_VGIC_V3
        u32             vgic_hcr;
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
new file mode 100644 (file)
index 0000000..b5abfda
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __LINUX_ARM_SMCCC_H
+#define __LINUX_ARM_SMCCC_H
+
+#include <linux/linkage.h>
+#include <linux/types.h>
+
+/*
+ * This file provides common defines for ARM SMC Calling Convention as
+ * specified in
+ * http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
+ */
+
+#define ARM_SMCCC_STD_CALL             0
+#define ARM_SMCCC_FAST_CALL            1
+#define ARM_SMCCC_TYPE_SHIFT           31
+
+#define ARM_SMCCC_SMC_32               0
+#define ARM_SMCCC_SMC_64               1
+#define ARM_SMCCC_CALL_CONV_SHIFT      30
+
+#define ARM_SMCCC_OWNER_MASK           0x3F
+#define ARM_SMCCC_OWNER_SHIFT          24
+
+#define ARM_SMCCC_FUNC_MASK            0xFFFF
+
+#define ARM_SMCCC_IS_FAST_CALL(smc_val)        \
+       ((smc_val) & (ARM_SMCCC_FAST_CALL << ARM_SMCCC_TYPE_SHIFT))
+#define ARM_SMCCC_IS_64(smc_val) \
+       ((smc_val) & (ARM_SMCCC_SMC_64 << ARM_SMCCC_CALL_CONV_SHIFT))
+#define ARM_SMCCC_FUNC_NUM(smc_val)    ((smc_val) & ARM_SMCCC_FUNC_MASK)
+#define ARM_SMCCC_OWNER_NUM(smc_val) \
+       (((smc_val) >> ARM_SMCCC_OWNER_SHIFT) & ARM_SMCCC_OWNER_MASK)
+
+#define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \
+       (((type) << ARM_SMCCC_TYPE_SHIFT) | \
+       ((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \
+       (((owner) & ARM_SMCCC_OWNER_MASK) << ARM_SMCCC_OWNER_SHIFT) | \
+       ((func_num) & ARM_SMCCC_FUNC_MASK))
+
+#define ARM_SMCCC_OWNER_ARCH           0
+#define ARM_SMCCC_OWNER_CPU            1
+#define ARM_SMCCC_OWNER_SIP            2
+#define ARM_SMCCC_OWNER_OEM            3
+#define ARM_SMCCC_OWNER_STANDARD       4
+#define ARM_SMCCC_OWNER_TRUSTED_APP    48
+#define ARM_SMCCC_OWNER_TRUSTED_APP_END        49
+#define ARM_SMCCC_OWNER_TRUSTED_OS     50
+#define ARM_SMCCC_OWNER_TRUSTED_OS_END 63
+
+/**
+ * struct arm_smccc_res - Result from SMC/HVC call
+ * @a0-a3 result values from registers 0 to 3
+ */
+struct arm_smccc_res {
+       unsigned long a0;
+       unsigned long a1;
+       unsigned long a2;
+       unsigned long a3;
+};
+
+/**
+ * arm_smccc_smc() - make SMC calls
+ * @a0-a7: arguments passed in registers 0 to 7
+ * @res: result values from registers 0 to 3
+ *
+ * This function is used to make SMC calls following SMC Calling Convention.
+ * The content of the supplied param are copied to registers 0 to 7 prior
+ * to the SMC instruction. The return values are updated with the content
+ * from register 0 to 3 on return from the SMC instruction.
+ */
+asmlinkage void arm_smccc_smc(unsigned long a0, unsigned long a1,
+                       unsigned long a2, unsigned long a3, unsigned long a4,
+                       unsigned long a5, unsigned long a6, unsigned long a7,
+                       struct arm_smccc_res *res);
+
+/**
+ * arm_smccc_hvc() - make HVC calls
+ * @a0-a7: arguments passed in registers 0 to 7
+ * @res: result values from registers 0 to 3
+ *
+ * This function is used to make HVC calls following SMC Calling
+ * Convention.  The content of the supplied param are copied to registers 0
+ * to 7 prior to the HVC instruction. The return values are updated with
+ * the content from register 0 to 3 on return from the HVC instruction.
+ */
+asmlinkage void arm_smccc_hvc(unsigned long a0, unsigned long a1,
+                       unsigned long a2, unsigned long a3, unsigned long a4,
+                       unsigned long a5, unsigned long a6, unsigned long a7,
+                       struct arm_smccc_res *res);
+
+#endif /*__LINUX_ARM_SMCCC_H*/
index 0169ba2e2e64b9c4bba07bf72b9c1194fe2db08a..c70e3588a48c723f4b7cd8536c0dabfc02871d5c 100644 (file)
@@ -797,6 +797,7 @@ extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t,
 extern int blk_queue_enter(struct request_queue *q, gfp_t gfp);
 extern void blk_queue_exit(struct request_queue *q);
 extern void blk_start_queue(struct request_queue *q);
+extern void blk_start_queue_async(struct request_queue *q);
 extern void blk_stop_queue(struct request_queue *q);
 extern void blk_sync_queue(struct request_queue *q);
 extern void __blk_stop_queue(struct request_queue *q);
index f589222bfa87e457aa211469c22be8341450b6d5..35b22f94d2d27d4977e30099abd3093352f2e85c 100644 (file)
@@ -19,6 +19,10 @@ extern unsigned long min_low_pfn;
  * highest page
  */
 extern unsigned long max_pfn;
+/*
+ * highest possible page
+ */
+extern unsigned long long max_possible_pfn;
 
 #ifndef CONFIG_NO_BOOTMEM
 /*
index 7784b597e9592b0ea0a32d661a0068cf9a8e2137..6013021a3b39467ffd8a2fa3d10064fe561ae2e7 100644 (file)
@@ -62,12 +62,18 @@ struct module;
  * @suspend:           suspend function for the clocksource, if necessary
  * @resume:            resume function for the clocksource, if necessary
  * @owner:             module reference, must be set by clocksource in modules
+ *
+ * Note: This struct is not used in hotpathes of the timekeeping code
+ * because the timekeeper caches the hot path fields in its own data
+ * structure, so no line cache alignment is required,
+ *
+ * The pointer to the clocksource itself is handed to the read
+ * callback. If you need extra information there you can wrap struct
+ * clocksource into your own struct. Depending on the amount of
+ * information you need you should consider to cache line align that
+ * structure.
  */
 struct clocksource {
-       /*
-        * Hotpath data, fits in a single cache line when the
-        * clocksource itself is cacheline aligned.
-        */
        cycle_t (*read)(struct clocksource *cs);
        cycle_t mask;
        u32 mult;
@@ -95,7 +101,7 @@ struct clocksource {
        cycle_t wd_last;
 #endif
        struct module *owner;
-} ____cacheline_aligned;
+};
 
 /*
  * Clock source flags bits::
index 4dac1036594f2a06418506d1a56b8e446462049e..00b042c49ccdac7af3262a399d33dacc88c83e25 100644 (file)
@@ -299,6 +299,23 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
        __u.__val;                                      \
 })
 
+/**
+ * smp_cond_acquire() - Spin wait for cond with ACQUIRE ordering
+ * @cond: boolean expression to wait for
+ *
+ * Equivalent to using smp_load_acquire() on the condition variable but employs
+ * the control dependency of the wait to reduce the barrier on many platforms.
+ *
+ * The control dependency provides a LOAD->STORE order, the additional RMB
+ * provides LOAD->LOAD order, together they provide LOAD->{LOAD,STORE} order,
+ * aka. ACQUIRE.
+ */
+#define smp_cond_acquire(cond) do {            \
+       while (!(cond))                         \
+               cpu_relax();                    \
+       smp_rmb(); /* ctrl + rmb := acquire */  \
+} while (0)
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASSEMBLY__ */
index c00dcc3026116370681a9701d36e2202c61b9107..a559eebc0e0f5b32e6214955f7c54933ab38c79f 100644 (file)
@@ -1,39 +1,48 @@
 #ifndef COMPONENT_H
 #define COMPONENT_H
 
+#include <linux/stddef.h>
+
 struct device;
 
 struct component_ops {
-       int (*bind)(struct device *, struct device *, void *);
-       void (*unbind)(struct device *, struct device *, void *);
+       int (*bind)(struct device *comp, struct device *master,
+                   void *master_data);
+       void (*unbind)(struct device *comp, struct device *master,
+                      void *master_data);
 };
 
 int component_add(struct device *, const struct component_ops *);
 void component_del(struct device *, const struct component_ops *);
 
-int component_bind_all(struct device *, void *);
-void component_unbind_all(struct device *, void *);
+int component_bind_all(struct device *master, void *master_data);
+void component_unbind_all(struct device *master, void *master_data);
 
 struct master;
 
 struct component_master_ops {
-       int (*add_components)(struct device *, struct master *);
-       int (*bind)(struct device *);
-       void (*unbind)(struct device *);
+       int (*bind)(struct device *master);
+       void (*unbind)(struct device *master);
 };
 
-int component_master_add(struct device *, const struct component_master_ops *);
 void component_master_del(struct device *,
        const struct component_master_ops *);
 
-int component_master_add_child(struct master *master,
-       int (*compare)(struct device *, void *), void *compare_data);
-
 struct component_match;
 
 int component_master_add_with_match(struct device *,
        const struct component_master_ops *, struct component_match *);
-void component_match_add(struct device *, struct component_match **,
+void component_match_add_release(struct device *master,
+       struct component_match **matchptr,
+       void (*release)(struct device *, void *),
        int (*compare)(struct device *, void *), void *compare_data);
 
+static inline void component_match_add(struct device *master,
+       struct component_match **matchptr,
+       int (*compare)(struct device *, void *), void *compare_data)
+{
+       component_match_add_release(master, matchptr, NULL, compare,
+                                   compare_data);
+}
+
 #endif
index 68b575afe5f5909f78b88f88c4dcbd086ef19720..d259274238db361a5b8d41116d03fc4e5642feda 100644 (file)
@@ -86,7 +86,7 @@ static inline void context_tracking_init(void) { }
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
 static inline void guest_enter(void)
 {
-       if (vtime_accounting_enabled())
+       if (vtime_accounting_cpu_enabled())
                vtime_guest_enter(current);
        else
                current->flags |= PF_VCPU;
@@ -100,7 +100,7 @@ static inline void guest_exit(void)
        if (context_tracking_is_enabled())
                __context_tracking_exit(CONTEXT_GUEST);
 
-       if (vtime_accounting_enabled())
+       if (vtime_accounting_cpu_enabled())
                vtime_guest_exit(current);
        else
                current->flags &= ~PF_VCPU;
index ee956c528fabf78cefcb58a67ff38aaaf621fcaf..1d34fe68f48ad3bea0c98e2eadbabae0aeb152d9 100644 (file)
@@ -22,12 +22,12 @@ struct context_tracking {
 };
 
 #ifdef CONFIG_CONTEXT_TRACKING
-extern struct static_key context_tracking_enabled;
+extern struct static_key_false context_tracking_enabled;
 DECLARE_PER_CPU(struct context_tracking, context_tracking);
 
 static inline bool context_tracking_is_enabled(void)
 {
-       return static_key_false(&context_tracking_enabled);
+       return static_branch_unlikely(&context_tracking_enabled);
 }
 
 static inline bool context_tracking_cpu_is_enabled(void)
diff --git a/include/linux/delayed_call.h b/include/linux/delayed_call.h
new file mode 100644 (file)
index 0000000..f7fa76a
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef _DELAYED_CALL_H
+#define _DELAYED_CALL_H
+
+/*
+ * Poor man's closures; I wish we could've done them sanely polymorphic,
+ * but...
+ */
+
+struct delayed_call {
+       void (*fn)(void *);
+       void *arg;
+};
+
+#define DEFINE_DELAYED_CALL(name) struct delayed_call name = {NULL, NULL}
+
+/* I really wish we had closures with sane typechecking... */
+static inline void set_delayed_call(struct delayed_call *call,
+               void (*fn)(void *), void *arg)
+{
+       call->fn = fn;
+       call->arg = arg;
+}
+
+static inline void do_delayed_call(struct delayed_call *call)
+{
+       if (call->fn)
+               call->fn(call->arg);
+}
+
+static inline void clear_delayed_call(struct delayed_call *call)
+{
+       call->fn = NULL;
+}
+#endif
index 4fe67b853de042d3fcc45910ab929fb320aab33f..9e0d78966552c102011ca84fb8e84a9f158dbf80 100644 (file)
@@ -28,12 +28,10 @@ struct device;
 extern int edac_op_state;
 extern int edac_err_assert;
 extern atomic_t edac_handlers;
-extern struct bus_type edac_subsys;
 
 extern int edac_handler_set(void);
 extern void edac_atomic_assert_error(void);
 extern struct bus_type *edac_get_sysfs_subsys(void);
-extern void edac_put_sysfs_subsys(void);
 
 enum {
        EDAC_REPORTING_ENABLED,
@@ -237,8 +235,10 @@ enum mem_type {
 #define MEM_FLAG_FB_DDR2        BIT(MEM_FB_DDR2)
 #define MEM_FLAG_RDDR2          BIT(MEM_RDDR2)
 #define MEM_FLAG_XDR            BIT(MEM_XDR)
-#define MEM_FLAG_DDR3           BIT(MEM_DDR3)
-#define MEM_FLAG_RDDR3          BIT(MEM_RDDR3)
+#define MEM_FLAG_DDR3           BIT(MEM_DDR3)
+#define MEM_FLAG_RDDR3          BIT(MEM_RDDR3)
+#define MEM_FLAG_DDR4           BIT(MEM_DDR4)
+#define MEM_FLAG_RDDR4          BIT(MEM_RDDR4)
 
 /**
  * enum edac-type - Error Detection and Correction capabilities and mode
index 4165e9ac9e36aa82735f40a790e25e0b7218c95b..5972ffe5719a4e14012328035450759c12f43bec 100644 (file)
@@ -493,6 +493,25 @@ static inline void bpf_jit_free(struct bpf_prog *fp)
 
 #define BPF_ANC                BIT(15)
 
+static inline bool bpf_needs_clear_a(const struct sock_filter *first)
+{
+       switch (first->code) {
+       case BPF_RET | BPF_K:
+       case BPF_LD | BPF_W | BPF_LEN:
+               return false;
+
+       case BPF_LD | BPF_W | BPF_ABS:
+       case BPF_LD | BPF_H | BPF_ABS:
+       case BPF_LD | BPF_B | BPF_ABS:
+               if (first->k == SKF_AD_OFF + SKF_AD_ALU_XOR_X)
+                       return true;
+               return false;
+
+       default:
+               return true;
+       }
+}
+
 static inline u16 bpf_anc_helper(const struct sock_filter *ftest)
 {
        BUG_ON(ftest->code & BPF_ANC);
index 3aa51425416148f5bec14b6faf4e6f4e81370a22..ef3cd36689f630df7bd895855f52e6d05f5df5b5 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/blk_types.h>
 #include <linux/workqueue.h>
 #include <linux/percpu-rwsem.h>
+#include <linux/delayed_call.h>
 
 #include <asm/byteorder.h>
 #include <uapi/linux/fs.h>
@@ -1633,12 +1634,11 @@ struct file_operations {
 
 struct inode_operations {
        struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
-       const char * (*follow_link) (struct dentry *, void **);
+       const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);
        int (*permission) (struct inode *, int);
        struct posix_acl * (*get_acl)(struct inode *, int);
 
        int (*readlink) (struct dentry *, char __user *,int);
-       void (*put_link) (struct inode *, void *);
 
        int (*create) (struct inode *,struct dentry *, umode_t, bool);
        int (*link) (struct dentry *,struct inode *,struct dentry *);
@@ -2736,14 +2736,14 @@ extern const struct file_operations generic_ro_fops;
 
 extern int readlink_copy(char __user *, int, const char *);
 extern int page_readlink(struct dentry *, char __user *, int);
-extern const char *page_follow_link_light(struct dentry *, void **);
-extern void page_put_link(struct inode *, void *);
+extern const char *page_get_link(struct dentry *, struct inode *,
+                                struct delayed_call *);
+extern void page_put_link(void *);
 extern int __page_symlink(struct inode *inode, const char *symname, int len,
                int nofs);
 extern int page_symlink(struct inode *inode, const char *symname, int len);
 extern const struct inode_operations page_symlink_inode_operations;
-extern void kfree_put_link(struct inode *, void *);
-extern void free_page_put_link(struct inode *, void *);
+extern void kfree_link(void *);
 extern int generic_readlink(struct dentry *, char __user *, int);
 extern void generic_fillattr(struct inode *, struct kstat *);
 int vfs_getattr_nosec(struct path *path, struct kstat *stat);
@@ -2754,7 +2754,8 @@ void __inode_sub_bytes(struct inode *inode, loff_t bytes);
 void inode_sub_bytes(struct inode *inode, loff_t bytes);
 loff_t inode_get_bytes(struct inode *inode);
 void inode_set_bytes(struct inode *inode, loff_t bytes);
-const char *simple_follow_link(struct dentry *, void **);
+const char *simple_get_link(struct dentry *, struct inode *,
+                           struct delayed_call *);
 extern const struct inode_operations simple_symlink_inode_operations;
 
 extern int iterate_dir(struct file *, struct dir_context *);
@@ -2764,8 +2765,6 @@ extern int vfs_lstat(const char __user *, struct kstat *);
 extern int vfs_fstat(unsigned int, struct kstat *);
 extern int vfs_fstatat(int , const char __user *, struct kstat *, int);
 
-extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
-                   unsigned long arg);
 extern int __generic_block_fiemap(struct inode *inode,
                                  struct fiemap_extent_info *fieinfo,
                                  loff_t start, loff_t len,
@@ -3025,5 +3024,6 @@ static inline bool dir_relax(struct inode *inode)
 }
 
 extern bool path_noexec(const struct path *path);
+extern void inode_nohighmem(struct inode *inode);
 
 #endif /* _LINUX_FS_H */
diff --git a/include/linux/fsl/edac.h b/include/linux/fsl/edac.h
new file mode 100644 (file)
index 0000000..90d64d4
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef FSL_EDAC_H
+#define FSL_EDAC_H
+
+struct mpc85xx_edac_pci_plat_data {
+       struct device_node *of_node;
+};
+
+#endif
index eae6548efbf060d9a2ec21bd716b0c0e2b6f2be7..60048c50404ee612aae6535ef8abfcf8475086d6 100644 (file)
@@ -586,6 +586,7 @@ extern int ftrace_arch_read_dyn_info(char *buf, int size);
 
 extern int skip_trace(unsigned long ip);
 extern void ftrace_module_init(struct module *mod);
+extern void ftrace_release_mod(struct module *mod);
 
 extern void ftrace_disable_daemon(void);
 extern void ftrace_enable_daemon(void);
index 685c262e0be848ca049ee041d00d389d3cc327fe..b0eb06423d5eccba6cb850078af6ffc60d97c382 100644 (file)
@@ -96,9 +96,7 @@ u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm,
                                struct address_space *mapping,
                                pgoff_t idx, unsigned long address);
 
-#ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE
 pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud);
-#endif
 
 extern int hugepages_treat_as_movable;
 extern int sysctl_hugetlb_shm_group;
index 1c1ff7e4faa4bf158166b789605107f6a65baf44..f2cb8d45513d182bef20020c775c617f8215af3a 100644 (file)
@@ -150,7 +150,7 @@ extern struct task_group root_task_group;
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
 # define INIT_VTIME(tsk)                                               \
-       .vtime_seqlock = __SEQLOCK_UNLOCKED(tsk.vtime_seqlock), \
+       .vtime_seqcount = SEQCNT_ZERO(tsk.vtime_seqcount),      \
        .vtime_snap = 0,                                \
        .vtime_snap_whence = VTIME_SYS,
 #else
index ad16809c85961e16ebc804280e4a78d66cf77634..cb30edbfe9fcd010b217aa385073d54fa71105c4 100644 (file)
@@ -195,6 +195,7 @@ extern void disable_irq(unsigned int irq);
 extern void disable_percpu_irq(unsigned int irq);
 extern void enable_irq(unsigned int irq);
 extern void enable_percpu_irq(unsigned int irq, unsigned int type);
+extern bool irq_percpu_is_enabled(unsigned int irq);
 extern void irq_wake_thread(unsigned int irq, void *dev_id);
 
 /* The following three functions are for the core kernel use only. */
index bae69e5d693c3e60cea1a209fc06d2d33fdfb960..9c940263ca230f8329bd4eec997d41ffc0d514b4 100644 (file)
@@ -103,10 +103,21 @@ struct device_node;
 void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
 int gic_cpu_if_down(unsigned int gic_nr);
 
+/*
+ * Subdrivers that need some preparatory work can initialize their
+ * chips and call this to register their GICs.
+ */
+int gic_of_init(struct device_node *node, struct device_node *parent);
+
+/*
+ * Legacy platforms not converted to DT yet must use this to init
+ * their GIC
+ */
 void gic_init(unsigned int nr, int start,
              void __iomem *dist , void __iomem *cpu);
 
-int gicv2m_of_init(struct device_node *node, struct irq_domain *parent);
+int gicv2m_init(struct fwnode_handle *parent_handle,
+               struct irq_domain *parent);
 
 void gic_send_sgi(unsigned int cpu_id, unsigned int irq);
 int gic_get_cpu_id(unsigned int cpu);
index a587a33363c724a10ae12b471658ed2d1800e827..dcca77c4b9d2dca2790544bbcda2cfdb15fac842 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _LINUX_IRQDESC_H
 #define _LINUX_IRQDESC_H
 
+#include <linux/rcupdate.h>
+
 /*
  * Core internal functions to deal with irq descriptors
  */
@@ -40,6 +42,7 @@ struct pt_regs;
  *                     IRQF_NO_SUSPEND set
  * @force_resume_depth:        number of irqactions on a irq descriptor with
  *                     IRQF_FORCE_RESUME set
+ * @rcu:               rcu head for delayed free
  * @dir:               /proc/irq/ procfs entry
  * @name:              flow handler name for /proc/interrupts output
  */
@@ -81,6 +84,9 @@ struct irq_desc {
 #endif
 #ifdef CONFIG_PROC_FS
        struct proc_dir_entry   *dir;
+#endif
+#ifdef CONFIG_SPARSE_IRQ
+       struct rcu_head         rcu;
 #endif
        int                     parent_irq;
        struct module           *owner;
index d5e5c5bef28c45e29bff88b175d581c0595b73f9..f64622ad02c196185be2eb79269e782d5772fcd0 100644 (file)
@@ -211,6 +211,11 @@ static inline struct fwnode_handle *of_node_to_fwnode(struct device_node *node)
        return node ? &node->fwnode : NULL;
 }
 
+static inline bool is_fwnode_irqchip(struct fwnode_handle *fwnode)
+{
+       return fwnode && fwnode->type == FWNODE_IRQCHIP;
+}
+
 static inline struct irq_domain *irq_find_matching_host(struct device_node *node,
                                                        enum irq_domain_bus_token bus_token)
 {
@@ -367,6 +372,9 @@ static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
        return __irq_domain_alloc_irqs(domain, -1, nr_irqs, node, arg, false);
 }
 
+extern int irq_domain_alloc_irqs_recursive(struct irq_domain *domain,
+                                          unsigned int irq_base,
+                                          unsigned int nr_irqs, void *arg);
 extern int irq_domain_set_hwirq_and_chip(struct irq_domain *domain,
                                         unsigned int virq,
                                         irq_hw_number_t hwirq,
@@ -410,6 +418,11 @@ static inline bool irq_domain_is_hierarchy(struct irq_domain *domain)
 static inline void irq_dispose_mapping(unsigned int virq) { }
 static inline void irq_domain_activate_irq(struct irq_data *data) { }
 static inline void irq_domain_deactivate_irq(struct irq_data *data) { }
+static inline struct irq_domain *irq_find_matching_fwnode(
+       struct fwnode_handle *fwnode, enum irq_domain_bus_token bus_token)
+{
+       return NULL;
+}
 #endif /* !CONFIG_IRQ_DOMAIN */
 
 #endif /* _LINUX_IRQDOMAIN_H */
index 350dfb08aee36bdce54c8ecf683dd7afed7b46ab..7311c3294e25f22a610209a63115c3d0778ecd0b 100644 (file)
@@ -255,6 +255,7 @@ extern long (*panic_blink)(int state);
 __printf(1, 2)
 void panic(const char *fmt, ...)
        __noreturn __cold;
+void nmi_panic_self_stop(struct pt_regs *);
 extern void oops_enter(void);
 extern void oops_exit(void);
 void print_oops_end_marker(void);
@@ -445,6 +446,33 @@ extern int sysctl_panic_on_stackoverflow;
 
 extern bool crash_kexec_post_notifiers;
 
+/*
+ * panic_cpu is used for synchronizing panic() and crash_kexec() execution. It
+ * holds a CPU number which is executing panic() currently. A value of
+ * PANIC_CPU_INVALID means no CPU has entered panic() or crash_kexec().
+ */
+extern atomic_t panic_cpu;
+#define PANIC_CPU_INVALID      -1
+
+/*
+ * A variant of panic() called from NMI context. We return if we've already
+ * panicked on this CPU. If another CPU already panicked, loop in
+ * nmi_panic_self_stop() which can provide architecture dependent code such
+ * as saving register state for crash dump.
+ */
+#define nmi_panic(regs, fmt, ...)                                      \
+do {                                                                   \
+       int old_cpu, cpu;                                               \
+                                                                       \
+       cpu = raw_smp_processor_id();                                   \
+       old_cpu = atomic_cmpxchg(&panic_cpu, PANIC_CPU_INVALID, cpu);   \
+                                                                       \
+       if (old_cpu == PANIC_CPU_INVALID)                               \
+               panic(fmt, ##__VA_ARGS__);                              \
+       else if (old_cpu != cpu)                                        \
+               nmi_panic_self_stop(regs);                              \
+} while (0)
+
 /*
  * Only to be used by arch init code. If the user over-wrote the default
  * CONFIG_PANIC_TIMEOUT, honor it.
index d140b1e9faa71791264d6439bd8429810fff3ddd..7b68d2788a56da4e21cb71c9780bb11470ca0064 100644 (file)
@@ -237,6 +237,7 @@ extern int kexec_purgatory_get_set_symbol(struct kimage *image,
                                          unsigned int size, bool get_value);
 extern void *kexec_purgatory_get_symbol_addr(struct kimage *image,
                                             const char *name);
+extern void __crash_kexec(struct pt_regs *);
 extern void crash_kexec(struct pt_regs *);
 int kexec_should_crash(struct task_struct *);
 void crash_save_cpu(struct pt_regs *regs, int cpu);
@@ -332,6 +333,7 @@ int __weak arch_kexec_apply_relocations(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
 #else /* !CONFIG_KEXEC_CORE */
 struct pt_regs;
 struct task_struct;
+static inline void __crash_kexec(struct pt_regs *regs) { }
 static inline void crash_kexec(struct pt_regs *regs) { }
 static inline int kexec_should_crash(struct task_struct *p) { return 0; }
 #define kexec_in_progress false
index c923350ca20a5a53453576f360e52498de232abe..f707f74055c3bde9766b8e801a59e9ee5242e4fb 100644 (file)
@@ -111,38 +111,13 @@ static inline bool is_error_page(struct page *page)
 }
 
 /*
- * vcpu->requests bit members
+ * Architecture-independent vcpu->requests bit members
+ * Bits 4-7 are reserved for more arch-independent bits.
  */
 #define KVM_REQ_TLB_FLUSH          0
-#define KVM_REQ_MIGRATE_TIMER      1
-#define KVM_REQ_REPORT_TPR_ACCESS  2
-#define KVM_REQ_MMU_RELOAD         3
-#define KVM_REQ_TRIPLE_FAULT       4
-#define KVM_REQ_PENDING_TIMER      5
-#define KVM_REQ_UNHALT             6
-#define KVM_REQ_MMU_SYNC           7
-#define KVM_REQ_CLOCK_UPDATE       8
-#define KVM_REQ_KICK               9
-#define KVM_REQ_DEACTIVATE_FPU    10
-#define KVM_REQ_EVENT             11
-#define KVM_REQ_APF_HALT          12
-#define KVM_REQ_STEAL_UPDATE      13
-#define KVM_REQ_NMI               14
-#define KVM_REQ_PMU               15
-#define KVM_REQ_PMI               16
-#define KVM_REQ_WATCHDOG          17
-#define KVM_REQ_MASTERCLOCK_UPDATE 18
-#define KVM_REQ_MCLOCK_INPROGRESS 19
-#define KVM_REQ_EPR_EXIT          20
-#define KVM_REQ_SCAN_IOAPIC       21
-#define KVM_REQ_GLOBAL_CLOCK_UPDATE 22
-#define KVM_REQ_ENABLE_IBS        23
-#define KVM_REQ_DISABLE_IBS       24
-#define KVM_REQ_APIC_PAGE_RELOAD  25
-#define KVM_REQ_SMI               26
-#define KVM_REQ_HV_CRASH          27
-#define KVM_REQ_IOAPIC_EOI_EXIT   28
-#define KVM_REQ_HV_RESET          29
+#define KVM_REQ_MMU_RELOAD         1
+#define KVM_REQ_PENDING_TIMER      2
+#define KVM_REQ_UNHALT             3
 
 #define KVM_USERSPACE_IRQ_SOURCE_ID            0
 #define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID       1
@@ -318,6 +293,11 @@ struct kvm_s390_adapter_int {
        u32 adapter_id;
 };
 
+struct kvm_hv_sint {
+       u32 vcpu;
+       u32 sint;
+};
+
 struct kvm_kernel_irq_routing_entry {
        u32 gsi;
        u32 type;
@@ -331,6 +311,7 @@ struct kvm_kernel_irq_routing_entry {
                } irqchip;
                struct msi_msg msi;
                struct kvm_s390_adapter_int adapter;
+               struct kvm_hv_sint hv_sint;
        };
        struct hlist_node link;
 };
@@ -439,10 +420,13 @@ struct kvm {
 
 /* The guest did something we don't support. */
 #define vcpu_unimpl(vcpu, fmt, ...)                                    \
-       kvm_pr_unimpl("vcpu%i " fmt, (vcpu)->vcpu_id, ## __VA_ARGS__)
+       kvm_pr_unimpl("vcpu%i, guest rIP: 0x%lx " fmt,                  \
+                       (vcpu)->vcpu_id, kvm_rip_read(vcpu), ## __VA_ARGS__)
 
 #define vcpu_debug(vcpu, fmt, ...)                                     \
        kvm_debug("vcpu%i " fmt, (vcpu)->vcpu_id, ## __VA_ARGS__)
+#define vcpu_err(vcpu, fmt, ...)                                       \
+       kvm_err("vcpu%i " fmt, (vcpu)->vcpu_id, ## __VA_ARGS__)
 
 static inline struct kvm_vcpu *kvm_get_vcpu(struct kvm *kvm, int i)
 {
@@ -465,6 +449,11 @@ static inline struct kvm_vcpu *kvm_get_vcpu_by_id(struct kvm *kvm, int id)
        struct kvm_vcpu *vcpu;
        int i;
 
+       if (id < 0 || id >= KVM_MAX_VCPUS)
+               return NULL;
+       vcpu = kvm_get_vcpu(kvm, id);
+       if (vcpu && vcpu->vcpu_id == id)
+               return vcpu;
        kvm_for_each_vcpu(i, vcpu, kvm)
                if (vcpu->vcpu_id == id)
                        return vcpu;
@@ -484,12 +473,12 @@ void vcpu_put(struct kvm_vcpu *vcpu);
 
 #ifdef __KVM_HAVE_IOAPIC
 void kvm_vcpu_request_scan_ioapic(struct kvm *kvm);
-void kvm_arch_irq_routing_update(struct kvm *kvm);
+void kvm_arch_post_irq_routing_update(struct kvm *kvm);
 #else
 static inline void kvm_vcpu_request_scan_ioapic(struct kvm *kvm)
 {
 }
-static inline void kvm_arch_irq_routing_update(struct kvm *kvm)
+static inline void kvm_arch_post_irq_routing_update(struct kvm *kvm)
 {
 }
 #endif
@@ -634,7 +623,7 @@ int kvm_gfn_to_hva_cache_init(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
 int kvm_clear_guest_page(struct kvm *kvm, gfn_t gfn, int offset, int len);
 int kvm_clear_guest(struct kvm *kvm, gpa_t gpa, unsigned long len);
 struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn);
-int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn);
+bool kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn);
 unsigned long kvm_host_page_size(struct kvm *kvm, gfn_t gfn);
 void mark_page_dirty(struct kvm *kvm, gfn_t gfn);
 
@@ -668,8 +657,6 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu);
 
 void kvm_flush_remote_tlbs(struct kvm *kvm);
 void kvm_reload_remote_mmus(struct kvm *kvm);
-void kvm_make_mclock_inprogress_request(struct kvm *kvm);
-void kvm_make_scan_ioapic_request(struct kvm *kvm);
 bool kvm_make_all_cpus_request(struct kvm *kvm, unsigned int req);
 
 long kvm_arch_dev_ioctl(struct file *filp,
@@ -990,11 +977,6 @@ static inline bool kvm_is_error_gpa(struct kvm *kvm, gpa_t gpa)
        return kvm_is_error_hva(hva);
 }
 
-static inline void kvm_migrate_timers(struct kvm_vcpu *vcpu)
-{
-       set_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests);
-}
-
 enum kvm_stat_kind {
        KVM_STAT_VM,
        KVM_STAT_VCPU,
@@ -1004,7 +986,6 @@ struct kvm_stats_debugfs_item {
        const char *name;
        int offset;
        enum kvm_stat_kind kind;
-       struct dentry *dentry;
 };
 extern struct kvm_stats_debugfs_item debugfs_entries[];
 extern struct dentry *kvm_debugfs_dir;
@@ -1091,6 +1072,7 @@ static inline void kvm_irq_routing_update(struct kvm *kvm)
 {
 }
 #endif
+void kvm_arch_irq_routing_update(struct kvm *kvm);
 
 static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
 {
index 00a97bb905db03a007450351441c823b8fa19112..35e568f04b1e7b94a6322c05d48583b43af8618c 100644 (file)
@@ -4,10 +4,8 @@
 #include <uapi/linux/kvm_para.h>
 
 
-static inline int kvm_para_has_feature(unsigned int feature)
+static inline bool kvm_para_has_feature(unsigned int feature)
 {
-       if (kvm_arch_para_features() & (1UL << feature))
-               return 1;
-       return 0;
+       return !!(kvm_arch_para_features() & (1UL << feature));
 }
 #endif /* __LINUX_KVM_PARA_H */
index fa359c79c825e666789ec1ce65392b6ff184d93c..bc1476fda96eb3206995b270e32cb54a49305eea 100644 (file)
@@ -44,9 +44,9 @@ struct led_classdev {
 #define LED_BLINK_ONESHOT      (1 << 17)
 #define LED_BLINK_ONESHOT_STOP (1 << 18)
 #define LED_BLINK_INVERT       (1 << 19)
-#define LED_SYSFS_DISABLE      (1 << 20)
-#define SET_BRIGHTNESS_ASYNC   (1 << 21)
-#define SET_BRIGHTNESS_SYNC    (1 << 22)
+#define LED_BLINK_BRIGHTNESS_CHANGE (1 << 20)
+#define LED_BLINK_DISABLE      (1 << 21)
+#define LED_SYSFS_DISABLE      (1 << 22)
 #define LED_DEV_CAP_FLASH      (1 << 23)
 
        /* Set LED brightness level */
@@ -57,8 +57,8 @@ struct led_classdev {
         * Set LED brightness level immediately - it can block the caller for
         * the time required for accessing a LED device register.
         */
-       int             (*brightness_set_sync)(struct led_classdev *led_cdev,
-                                       enum led_brightness brightness);
+       int (*brightness_set_blocking)(struct led_classdev *led_cdev,
+                                      enum led_brightness brightness);
        /* Get LED brightness level */
        enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);
 
@@ -156,10 +156,25 @@ extern void led_blink_set_oneshot(struct led_classdev *led_cdev,
  *
  * Set an LED's brightness, and, if necessary, cancel the
  * software blink timer that implements blinking when the
- * hardware doesn't.
+ * hardware doesn't. This function is guaranteed not to sleep.
  */
 extern void led_set_brightness(struct led_classdev *led_cdev,
                               enum led_brightness brightness);
+
+/**
+ * led_set_brightness_sync - set LED brightness synchronously
+ * @led_cdev: the LED to set
+ * @brightness: the brightness to set it to
+ *
+ * Set an LED's brightness immediately. This function will block
+ * the caller for the time required for accessing device registers,
+ * and it can sleep.
+ *
+ * Returns: 0 on success or negative error value on failure
+ */
+extern int led_set_brightness_sync(struct led_classdev *led_cdev,
+                                  enum led_brightness value);
+
 /**
  * led_update_brightness - update LED brightness
  * @led_cdev: the LED to query
@@ -231,6 +246,8 @@ ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
 /* Registration functions for complex triggers */
 extern int led_trigger_register(struct led_trigger *trigger);
 extern void led_trigger_unregister(struct led_trigger *trigger);
+extern int devm_led_trigger_register(struct device *dev,
+                                    struct led_trigger *trigger);
 
 extern void led_trigger_register_simple(const char *name,
                                struct led_trigger **trigger);
index 600c1e0626a5ff6c91df3a0b2f2fcf0ef485fedf..851821bfd55321dce527f4b32e03d1534994678a 100644 (file)
@@ -205,6 +205,7 @@ enum {
        ATA_LFLAG_NO_LPM        = (1 << 8), /* disable LPM on this link */
        ATA_LFLAG_RST_ONCE      = (1 << 9), /* limit recovery to one reset */
        ATA_LFLAG_CHANGED       = (1 << 10), /* LPM state changed on this link */
+       ATA_LFLAG_NO_DB_DELAY   = (1 << 11), /* no debounce delay on link resume */
 
        /* struct ata_port flags */
        ATA_FLAG_SLAVE_POSS     = (1 << 0), /* host supports slave dev */
index 993395a2e55c5483c890b40e216193d95c85bd64..5356f4d661a721ba0446b1183e2a834f3bf3b56f 100644 (file)
@@ -24,7 +24,7 @@
 
 static inline void INIT_LIST_HEAD(struct list_head *list)
 {
-       list->next = list;
+       WRITE_ONCE(list->next, list);
        list->prev = list;
 }
 
@@ -42,7 +42,7 @@ static inline void __list_add(struct list_head *new,
        next->prev = new;
        new->next = next;
        new->prev = prev;
-       prev->next = new;
+       WRITE_ONCE(prev->next, new);
 }
 #else
 extern void __list_add(struct list_head *new,
@@ -186,7 +186,7 @@ static inline int list_is_last(const struct list_head *list,
  */
 static inline int list_empty(const struct list_head *head)
 {
-       return head->next == head;
+       return READ_ONCE(head->next) == head;
 }
 
 /**
@@ -608,7 +608,7 @@ static inline int hlist_unhashed(const struct hlist_node *h)
 
 static inline int hlist_empty(const struct hlist_head *h)
 {
-       return !h->first;
+       return !READ_ONCE(h->first);
 }
 
 static inline void __hlist_del(struct hlist_node *n)
@@ -642,7 +642,7 @@ static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
        n->next = first;
        if (first)
                first->pprev = &n->next;
-       h->first = n;
+       WRITE_ONCE(h->first, n);
        n->pprev = &h->first;
 }
 
@@ -653,14 +653,14 @@ static inline void hlist_add_before(struct hlist_node *n,
        n->pprev = next->pprev;
        n->next = next;
        next->pprev = &n->next;
-       *(n->pprev) = n;
+       WRITE_ONCE(*(n->pprev), n);
 }
 
 static inline void hlist_add_behind(struct hlist_node *n,
                                    struct hlist_node *prev)
 {
        n->next = prev->next;
-       prev->next = n;
+       WRITE_ONCE(prev->next, n);
        n->pprev = &prev->next;
 
        if (n->next)
index 8132214e8efd2930ff752fcc4c37da7d23b9643f..ee7229a6c06ae5e0f130056c8fadc80d0b733601 100644 (file)
@@ -70,7 +70,7 @@ static inline void hlist_bl_set_first(struct hlist_bl_head *h,
 
 static inline int hlist_bl_empty(const struct hlist_bl_head *h)
 {
-       return !((unsigned long)h->first & ~LIST_BL_LOCKMASK);
+       return !((unsigned long)READ_ONCE(h->first) & ~LIST_BL_LOCKMASK);
 }
 
 static inline void hlist_bl_add_head(struct hlist_bl_node *n,
index 444d2b1313bda37647b1660e4582202a7e3b66e4..b01fe100908430708df0df5162594b497ffdad62 100644 (file)
@@ -57,7 +57,7 @@ static inline int hlist_nulls_unhashed(const struct hlist_nulls_node *h)
 
 static inline int hlist_nulls_empty(const struct hlist_nulls_head *h)
 {
-       return is_a_nulls(h->first);
+       return is_a_nulls(READ_ONCE(h->first));
 }
 
 static inline void hlist_nulls_add_head(struct hlist_nulls_node *n,
index 24daf8fc4d7c71e4c36ed0063849c01a3b31d022..fec66f86eeffedbcfd8c86d6ec8f313b6859932c 100644 (file)
@@ -25,6 +25,7 @@ enum {
        MEMBLOCK_NONE           = 0x0,  /* No special request */
        MEMBLOCK_HOTPLUG        = 0x1,  /* hotpluggable region */
        MEMBLOCK_MIRROR         = 0x2,  /* mirrored region */
+       MEMBLOCK_NOMAP          = 0x4,  /* don't add to kernel direct mapping */
 };
 
 struct memblock_region {
@@ -82,6 +83,7 @@ bool memblock_overlaps_region(struct memblock_type *type,
 int memblock_mark_hotplug(phys_addr_t base, phys_addr_t size);
 int memblock_clear_hotplug(phys_addr_t base, phys_addr_t size);
 int memblock_mark_mirror(phys_addr_t base, phys_addr_t size);
+int memblock_mark_nomap(phys_addr_t base, phys_addr_t size);
 ulong choose_memblock_flags(void);
 
 /* Low level functions */
@@ -184,6 +186,11 @@ static inline bool memblock_is_mirror(struct memblock_region *m)
        return m->flags & MEMBLOCK_MIRROR;
 }
 
+static inline bool memblock_is_nomap(struct memblock_region *m)
+{
+       return m->flags & MEMBLOCK_NOMAP;
+}
+
 #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
 int memblock_search_pfn_nid(unsigned long pfn, unsigned long *start_pfn,
                            unsigned long  *end_pfn);
@@ -319,6 +326,7 @@ phys_addr_t memblock_start_of_DRAM(void);
 phys_addr_t memblock_end_of_DRAM(void);
 void memblock_enforce_memory_limit(phys_addr_t memory_limit);
 int memblock_is_memory(phys_addr_t addr);
+int memblock_is_map_memory(phys_addr_t addr);
 int memblock_is_region_memory(phys_addr_t base, phys_addr_t size);
 int memblock_is_reserved(phys_addr_t addr);
 bool memblock_is_region_reserved(phys_addr_t base, phys_addr_t size);
index 579b50ca2e026b783f48759b099ff51ca5d219ba..7a09e7f1f984bfdb83c4075bd9d71951285af5e7 100644 (file)
@@ -715,7 +715,6 @@ struct wm8350_led_platform_data {
 
 struct wm8350_led {
        struct platform_device *pdev;
-       struct mutex mutex;
        struct work_struct work;
        spinlock_t value_lock;
        enum led_brightness value;
index f67b2ec18e6d87c8df27b314f7320e49163850f5..89df7abedd67298d00df558af49de438cccf8439 100644 (file)
@@ -172,7 +172,7 @@ struct dw_mci {
        /* For edmac */
        struct dw_mci_dma_slave *dms;
        /* Registers's physical base address */
-       void                    *phy_regs;
+       resource_size_t         phy_regs;
 
        u32                     cmd_status;
        u32                     data_status;
@@ -235,16 +235,10 @@ struct dw_mci_dma_ops {
 };
 
 /* IP Quirks/flags. */
-/* DTO fix for command transmission with IDMAC configured */
-#define DW_MCI_QUIRK_IDMAC_DTO                 BIT(0)
-/* delay needed between retries on some 2.11a implementations */
-#define DW_MCI_QUIRK_RETRY_DELAY               BIT(1)
-/* High Speed Capable - Supports HS cards (up to 50MHz) */
-#define DW_MCI_QUIRK_HIGHSPEED                 BIT(2)
 /* Unreliable card detection */
-#define DW_MCI_QUIRK_BROKEN_CARD_DETECTION     BIT(3)
+#define DW_MCI_QUIRK_BROKEN_CARD_DETECTION     BIT(0)
 /* Timer for broken data transfer over scheme */
-#define DW_MCI_QUIRK_BROKEN_DTO                        BIT(4)
+#define DW_MCI_QUIRK_BROKEN_DTO                        BIT(1)
 
 struct dma_pdata;
 
index 8673ffe3d86ef83fc657cde31a43058b94840f61..8dd4d290ab0d8608b9596c18da8db1096715badb 100644 (file)
@@ -212,7 +212,9 @@ struct mmc_host {
        u32                     ocr_avail_sdio; /* SDIO-specific OCR */
        u32                     ocr_avail_sd;   /* SD-specific OCR */
        u32                     ocr_avail_mmc;  /* MMC-specific OCR */
+#ifdef CONFIG_PM_SLEEP
        struct notifier_block   pm_notify;
+#endif
        u32                     max_current_330;
        u32                     max_current_300;
        u32                     max_current_180;
@@ -259,7 +261,6 @@ struct mmc_host {
 #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_RUNTIME_RESUME (1 << 20)       /* Resume at runtime_resume. */
 #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 */
@@ -289,6 +290,7 @@ struct mmc_host {
 #define MMC_CAP2_HSX00_1_2V    (MMC_CAP2_HS200_1_2V_SDR | MMC_CAP2_HS400_1_2V)
 #define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
 #define MMC_CAP2_NO_WRITE_PROTECT (1 << 18)    /* No physical write protect pin, assume that card is always read-write */
+#define MMC_CAP2_NO_SDIO       (1 << 19)       /* Do not send SDIO commands during initialization */
 
        mmc_pm_flag_t           pm_caps;        /* supported pm features */
 
@@ -434,8 +436,6 @@ static inline int mmc_regulator_set_vqmmc(struct mmc_host *mmc,
 
 int mmc_regulator_get_supply(struct mmc_host *mmc);
 
-int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *);
-
 static inline int mmc_card_is_removable(struct mmc_host *host)
 {
        return !(host->caps & MMC_CAP_NONREMOVABLE);
index f71a25e5fd25b574bceaf9b397b62e0913419067..1c6342ab8c0e92be0991f1e4c1b976c7f8f5f386 100644 (file)
@@ -174,6 +174,7 @@ struct msi_controller {
 #include <asm/msi.h>
 
 struct irq_domain;
+struct irq_domain_ops;
 struct irq_chip;
 struct device_node;
 struct fwnode_handle;
@@ -279,6 +280,23 @@ struct irq_domain *platform_msi_create_irq_domain(struct fwnode_handle *fwnode,
 int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
                                   irq_write_msi_msg_t write_msi_msg);
 void platform_msi_domain_free_irqs(struct device *dev);
+
+/* When an MSI domain is used as an intermediate domain */
+int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev,
+                           int nvec, msi_alloc_info_t *args);
+int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev,
+                            int virq, int nvec, msi_alloc_info_t *args);
+struct irq_domain *
+platform_msi_create_device_domain(struct device *dev,
+                                 unsigned int nvec,
+                                 irq_write_msi_msg_t write_msi_msg,
+                                 const struct irq_domain_ops *ops,
+                                 void *host_data);
+int platform_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
+                             unsigned int nr_irqs);
+void platform_msi_domain_free(struct irq_domain *domain, unsigned int virq,
+                             unsigned int nvec);
+void *platform_msi_get_host_data(struct irq_domain *domain);
 #endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
 
 #ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
index c8723b62c4cd286aa7b6b382507dbb25cd975ab1..bc742dac7d3a10da925776e9fc4a0ca283a2eda6 100644 (file)
@@ -25,7 +25,7 @@
 #define SNOR_MFR_MACRONIX      CFI_MFR_MACRONIX
 #define SNOR_MFR_SPANSION      CFI_MFR_AMD
 #define SNOR_MFR_SST           CFI_MFR_SST
-#define SNOR_MFR_WINBOND       0xef
+#define SNOR_MFR_WINBOND       0xef /* Also used by some Spansion */
 
 /*
  * Note on opcode nomenclature: some opcodes have a format like
index c0e961474a527058c8d1ac2aa72070c9b15e3db5..37a3d2981352940c0797e9a9e90e3c388cfb9c83 100644 (file)
@@ -359,6 +359,7 @@ extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode);
 extern int nfs_revalidate_inode_rcu(struct nfs_server *server, struct inode *inode);
 extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
 extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
+extern int nfs_revalidate_mapping_rcu(struct inode *inode);
 extern int nfs_revalidate_mapping_protected(struct inode *inode, struct address_space *mapping);
 extern int nfs_setattr(struct dentry *, struct iattr *);
 extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr, struct nfs_fattr *);
index 6ae25aae88fd1254f40227341ca20b73a2e08ce2..d86378c226fbe64585140e9362f8bf1ac6ff8a5c 100644 (file)
@@ -1946,6 +1946,16 @@ static inline struct irq_domain *
 pci_host_bridge_of_msi_domain(struct pci_bus *bus) { return NULL; }
 #endif  /* CONFIG_OF */
 
+#ifdef CONFIG_ACPI
+struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus);
+
+void
+pci_msi_register_fwnode_provider(struct fwnode_handle *(*fn)(struct device *));
+#else
+static inline struct irq_domain *
+pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; }
+#endif
+
 #ifdef CONFIG_EEH
 static inline struct eeh_dev *pci_dev_to_eeh_dev(struct pci_dev *pdev)
 {
index 12c9b485beb718241f0346a261462d82939e266b..84f542df7ff5cca0932f02b6629f8229244c2d1a 100644 (file)
@@ -116,7 +116,7 @@ void percpu_ref_reinit(struct percpu_ref *ref);
  */
 static inline void percpu_ref_kill(struct percpu_ref *ref)
 {
-       return percpu_ref_kill_and_confirm(ref, NULL);
+       percpu_ref_kill_and_confirm(ref, NULL);
 }
 
 /*
index caebf2a758dc0e573d7e5dc76b916dc7cb639ea3..4bc6dafb703eaa6ec3d0f1d6deff3cbb82a82f06 100644 (file)
 #define PERCPU_MODULE_RESERVE          0
 #endif
 
-#ifndef PERCPU_ENOUGH_ROOM
-#define PERCPU_ENOUGH_ROOM                                             \
-       (ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES) +      \
-        PERCPU_MODULE_RESERVE)
-#endif
-
 /* minimum unit size, also is the maximum supported allocation size */
 #define PCPU_MIN_UNIT_SIZE             PFN_ALIGN(32 << 10)
 
index bfa673bb822d43146cbf475fe72a04615f921b95..83b5e34c6580345fb47b648fb98fc8892583d8b9 100644 (file)
@@ -111,8 +111,6 @@ struct arm_pmu {
 
 #define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))
 
-int armpmu_register(struct arm_pmu *armpmu, int type);
-
 u64 armpmu_event_update(struct perf_event *event);
 
 int armpmu_event_set_period(struct perf_event *event);
diff --git a/include/linux/platform_data/camera-mx2.h b/include/linux/platform_data/camera-mx2.h
deleted file mode 100644 (file)
index 7ded6f1..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * mx2-cam.h - i.MX27/i.MX25 camera driver header file
- *
- * Copyright (C) 2003, Intel Corporation
- * Copyright (C) 2008, Sascha Hauer <s.hauer@pengutronix.de>
- * Copyright (C) 2010, Baruch Siach <baruch@tkos.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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef __MACH_MX2_CAM_H_
-#define __MACH_MX2_CAM_H_
-
-#define MX2_CAMERA_EXT_VSYNC           (1 << 1)
-#define MX2_CAMERA_CCIR                        (1 << 2)
-#define MX2_CAMERA_CCIR_INTERLACE      (1 << 3)
-#define MX2_CAMERA_HSYNC_HIGH          (1 << 4)
-#define MX2_CAMERA_GATED_CLOCK         (1 << 5)
-#define MX2_CAMERA_INV_DATA            (1 << 6)
-#define MX2_CAMERA_PCLK_SAMPLE_RISING  (1 << 7)
-
-/**
- * struct mx2_camera_platform_data - optional platform data for mx2_camera
- * @flags: any combination of MX2_CAMERA_*
- * @clk: clock rate of the csi block / 2
- */
-struct mx2_camera_platform_data {
-       unsigned long flags;
-       unsigned long clk;
-};
-
-#endif /* __MACH_MX2_CAM_H_ */
diff --git a/include/linux/platform_data/camera-mx3.h b/include/linux/platform_data/camera-mx3.h
deleted file mode 100644 (file)
index a910dad..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * mx3_camera.h - i.MX3x camera driver header file
- *
- * Copyright (C) 2008, Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef _MX3_CAMERA_H_
-#define _MX3_CAMERA_H_
-
-#include <linux/device.h>
-
-#define MX3_CAMERA_CLK_SRC     1
-#define MX3_CAMERA_EXT_VSYNC   2
-#define MX3_CAMERA_DP          4
-#define MX3_CAMERA_PCP         8
-#define MX3_CAMERA_HSP         0x10
-#define MX3_CAMERA_VSP         0x20
-#define MX3_CAMERA_DATAWIDTH_4 0x40
-#define MX3_CAMERA_DATAWIDTH_8 0x80
-#define MX3_CAMERA_DATAWIDTH_10        0x100
-#define MX3_CAMERA_DATAWIDTH_15        0x200
-
-#define MX3_CAMERA_DATAWIDTH_MASK (MX3_CAMERA_DATAWIDTH_4 | MX3_CAMERA_DATAWIDTH_8 | \
-                                  MX3_CAMERA_DATAWIDTH_10 | MX3_CAMERA_DATAWIDTH_15)
-
-struct v4l2_async_subdev;
-
-/**
- * struct mx3_camera_pdata - i.MX3x camera platform data
- * @flags:     MX3_CAMERA_* flags
- * @mclk_10khz:        master clock frequency in 10kHz units
- * @dma_dev:   IPU DMA device to match against in channel allocation
- */
-struct mx3_camera_pdata {
-       unsigned long flags;
-       unsigned long mclk_10khz;
-       struct device *dma_dev;
-       struct v4l2_async_subdev **asd; /* Flat array, arranged in groups */
-       int *asd_sizes;                 /* 0-terminated array of asd group sizes */
-};
-
-#endif
diff --git a/include/linux/platform_data/camera-pxa.h b/include/linux/platform_data/camera-pxa.h
deleted file mode 100644 (file)
index 6709b1c..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-    camera.h - PXA camera driver header file
-
-    Copyright (C) 2003, Intel Corporation
-    Copyright (C) 2008, Guennadi Liakhovetski <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 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 __ASM_ARCH_CAMERA_H_
-#define __ASM_ARCH_CAMERA_H_
-
-#define PXA_CAMERA_MASTER      1
-#define PXA_CAMERA_DATAWIDTH_4 2
-#define PXA_CAMERA_DATAWIDTH_5 4
-#define PXA_CAMERA_DATAWIDTH_8 8
-#define PXA_CAMERA_DATAWIDTH_9 0x10
-#define PXA_CAMERA_DATAWIDTH_10        0x20
-#define PXA_CAMERA_PCLK_EN     0x40
-#define PXA_CAMERA_MCLK_EN     0x80
-#define PXA_CAMERA_PCP         0x100
-#define PXA_CAMERA_HSP         0x200
-#define PXA_CAMERA_VSP         0x400
-
-struct pxacamera_platform_data {
-       unsigned long flags;
-       unsigned long mclk_10khz;
-};
-
-extern void pxa_set_camera_info(struct pxacamera_platform_data *);
-
-#endif /* __ASM_ARCH_CAMERA_H_ */
diff --git a/include/linux/platform_data/camera-rcar.h b/include/linux/platform_data/camera-rcar.h
deleted file mode 100644 (file)
index dfc83c5..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Platform data for Renesas R-Car VIN soc-camera driver
- *
- * Copyright (C) 2011-2013 Renesas Solutions Corp.
- * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#ifndef __CAMERA_RCAR_H_
-#define __CAMERA_RCAR_H_
-
-#define RCAR_VIN_HSYNC_ACTIVE_LOW      (1 << 0)
-#define RCAR_VIN_VSYNC_ACTIVE_LOW      (1 << 1)
-#define RCAR_VIN_BT601                 (1 << 2)
-#define RCAR_VIN_BT656                 (1 << 3)
-
-struct rcar_vin_platform_data {
-       unsigned int flags;
-};
-
-#endif /* __CAMERA_RCAR_H_ */
diff --git a/include/linux/platform_data/coda.h b/include/linux/platform_data/coda.h
deleted file mode 100644 (file)
index 6ad4410..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2013 Philipp Zabel, 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.
- */
-#ifndef PLATFORM_CODA_H
-#define PLATFORM_CODA_H
-
-struct device;
-
-struct coda_platform_data {
-       struct device *iram_dev;
-};
-
-#endif
diff --git a/include/linux/platform_data/irq-renesas-intc-irqpin.h b/include/linux/platform_data/irq-renesas-intc-irqpin.h
deleted file mode 100644 (file)
index e4cb911..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Renesas INTC External IRQ Pin Driver
- *
- *  Copyright (C) 2013 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#ifndef __IRQ_RENESAS_INTC_IRQPIN_H__
-#define __IRQ_RENESAS_INTC_IRQPIN_H__
-
-struct renesas_intc_irqpin_config {
-       unsigned int sense_bitfield_width;
-       unsigned int irq_base;
-       bool control_parent;
-};
-
-#endif /* __IRQ_RENESAS_INTC_IRQPIN_H__ */
diff --git a/include/linux/platform_data/media/camera-mx2.h b/include/linux/platform_data/media/camera-mx2.h
new file mode 100644 (file)
index 0000000..7ded6f1
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * mx2-cam.h - i.MX27/i.MX25 camera driver header file
+ *
+ * Copyright (C) 2003, Intel Corporation
+ * Copyright (C) 2008, Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2010, Baruch Siach <baruch@tkos.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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __MACH_MX2_CAM_H_
+#define __MACH_MX2_CAM_H_
+
+#define MX2_CAMERA_EXT_VSYNC           (1 << 1)
+#define MX2_CAMERA_CCIR                        (1 << 2)
+#define MX2_CAMERA_CCIR_INTERLACE      (1 << 3)
+#define MX2_CAMERA_HSYNC_HIGH          (1 << 4)
+#define MX2_CAMERA_GATED_CLOCK         (1 << 5)
+#define MX2_CAMERA_INV_DATA            (1 << 6)
+#define MX2_CAMERA_PCLK_SAMPLE_RISING  (1 << 7)
+
+/**
+ * struct mx2_camera_platform_data - optional platform data for mx2_camera
+ * @flags: any combination of MX2_CAMERA_*
+ * @clk: clock rate of the csi block / 2
+ */
+struct mx2_camera_platform_data {
+       unsigned long flags;
+       unsigned long clk;
+};
+
+#endif /* __MACH_MX2_CAM_H_ */
diff --git a/include/linux/platform_data/media/camera-mx3.h b/include/linux/platform_data/media/camera-mx3.h
new file mode 100644 (file)
index 0000000..a910dad
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * mx3_camera.h - i.MX3x camera driver header file
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MX3_CAMERA_H_
+#define _MX3_CAMERA_H_
+
+#include <linux/device.h>
+
+#define MX3_CAMERA_CLK_SRC     1
+#define MX3_CAMERA_EXT_VSYNC   2
+#define MX3_CAMERA_DP          4
+#define MX3_CAMERA_PCP         8
+#define MX3_CAMERA_HSP         0x10
+#define MX3_CAMERA_VSP         0x20
+#define MX3_CAMERA_DATAWIDTH_4 0x40
+#define MX3_CAMERA_DATAWIDTH_8 0x80
+#define MX3_CAMERA_DATAWIDTH_10        0x100
+#define MX3_CAMERA_DATAWIDTH_15        0x200
+
+#define MX3_CAMERA_DATAWIDTH_MASK (MX3_CAMERA_DATAWIDTH_4 | MX3_CAMERA_DATAWIDTH_8 | \
+                                  MX3_CAMERA_DATAWIDTH_10 | MX3_CAMERA_DATAWIDTH_15)
+
+struct v4l2_async_subdev;
+
+/**
+ * struct mx3_camera_pdata - i.MX3x camera platform data
+ * @flags:     MX3_CAMERA_* flags
+ * @mclk_10khz:        master clock frequency in 10kHz units
+ * @dma_dev:   IPU DMA device to match against in channel allocation
+ */
+struct mx3_camera_pdata {
+       unsigned long flags;
+       unsigned long mclk_10khz;
+       struct device *dma_dev;
+       struct v4l2_async_subdev **asd; /* Flat array, arranged in groups */
+       int *asd_sizes;                 /* 0-terminated array of asd group sizes */
+};
+
+#endif
diff --git a/include/linux/platform_data/media/camera-pxa.h b/include/linux/platform_data/media/camera-pxa.h
new file mode 100644 (file)
index 0000000..6709b1c
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+    camera.h - PXA camera driver header file
+
+    Copyright (C) 2003, Intel Corporation
+    Copyright (C) 2008, Guennadi Liakhovetski <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 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 __ASM_ARCH_CAMERA_H_
+#define __ASM_ARCH_CAMERA_H_
+
+#define PXA_CAMERA_MASTER      1
+#define PXA_CAMERA_DATAWIDTH_4 2
+#define PXA_CAMERA_DATAWIDTH_5 4
+#define PXA_CAMERA_DATAWIDTH_8 8
+#define PXA_CAMERA_DATAWIDTH_9 0x10
+#define PXA_CAMERA_DATAWIDTH_10        0x20
+#define PXA_CAMERA_PCLK_EN     0x40
+#define PXA_CAMERA_MCLK_EN     0x80
+#define PXA_CAMERA_PCP         0x100
+#define PXA_CAMERA_HSP         0x200
+#define PXA_CAMERA_VSP         0x400
+
+struct pxacamera_platform_data {
+       unsigned long flags;
+       unsigned long mclk_10khz;
+};
+
+extern void pxa_set_camera_info(struct pxacamera_platform_data *);
+
+#endif /* __ASM_ARCH_CAMERA_H_ */
diff --git a/include/linux/platform_data/media/coda.h b/include/linux/platform_data/media/coda.h
new file mode 100644 (file)
index 0000000..6ad4410
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2013 Philipp Zabel, 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.
+ */
+#ifndef PLATFORM_CODA_H
+#define PLATFORM_CODA_H
+
+struct device;
+
+struct coda_platform_data {
+       struct device *iram_dev;
+};
+
+#endif
diff --git a/include/linux/platform_data/media/gpio-ir-recv.h b/include/linux/platform_data/media/gpio-ir-recv.h
new file mode 100644 (file)
index 0000000..0c298f5
--- /dev/null
@@ -0,0 +1,23 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __GPIO_IR_RECV_H__
+#define __GPIO_IR_RECV_H__
+
+struct gpio_ir_recv_platform_data {
+       int             gpio_nr;
+       bool            active_low;
+       u64             allowed_protos;
+       const char      *map_name;
+};
+
+#endif /* __GPIO_IR_RECV_H__ */
diff --git a/include/linux/platform_data/media/ir-rx51.h b/include/linux/platform_data/media/ir-rx51.h
new file mode 100644 (file)
index 0000000..104aa89
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _LIRC_RX51_H
+#define _LIRC_RX51_H
+
+struct lirc_rx51_platform_data {
+       int pwm_timer;
+
+       int(*set_max_mpu_wakeup_lat)(struct device *dev, long t);
+};
+
+#endif
diff --git a/include/linux/platform_data/media/mmp-camera.h b/include/linux/platform_data/media/mmp-camera.h
new file mode 100644 (file)
index 0000000..7611963
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Information for the Marvell Armada MMP camera
+ */
+
+struct mmp_camera_platform_data {
+       struct platform_device *i2c_device;
+       int sensor_power_gpio;
+       int sensor_reset_gpio;
+};
diff --git a/include/linux/platform_data/media/omap1_camera.h b/include/linux/platform_data/media/omap1_camera.h
new file mode 100644 (file)
index 0000000..819767c
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Header for V4L2 SoC Camera driver for OMAP1 Camera Interface
+ *
+ * Copyright (C) 2010, Janusz Krzysztofik <jkrzyszt@tis.icnet.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.
+ */
+
+#ifndef __MEDIA_OMAP1_CAMERA_H_
+#define __MEDIA_OMAP1_CAMERA_H_
+
+#include <linux/bitops.h>
+
+#define OMAP1_CAMERA_IOSIZE            0x1c
+
+enum omap1_cam_vb_mode {
+       OMAP1_CAM_DMA_CONTIG = 0,
+       OMAP1_CAM_DMA_SG,
+};
+
+#define OMAP1_CAMERA_MIN_BUF_COUNT(x)  ((x) == OMAP1_CAM_DMA_CONTIG ? 3 : 2)
+
+struct omap1_cam_platform_data {
+       unsigned long   camexclk_khz;
+       unsigned long   lclk_khz_max;
+       unsigned long   flags;
+};
+
+#define OMAP1_CAMERA_LCLK_RISING       BIT(0)
+#define OMAP1_CAMERA_RST_LOW           BIT(1)
+#define OMAP1_CAMERA_RST_HIGH          BIT(2)
+
+#endif /* __MEDIA_OMAP1_CAMERA_H_ */
diff --git a/include/linux/platform_data/media/omap4iss.h b/include/linux/platform_data/media/omap4iss.h
new file mode 100644 (file)
index 0000000..0d7620d
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef ARCH_ARM_PLAT_OMAP4_ISS_H
+#define ARCH_ARM_PLAT_OMAP4_ISS_H
+
+#include <linux/i2c.h>
+
+struct iss_device;
+
+enum iss_interface_type {
+       ISS_INTERFACE_CSI2A_PHY1,
+       ISS_INTERFACE_CSI2B_PHY2,
+};
+
+/**
+ * struct iss_csiphy_lane: CSI2 lane position and polarity
+ * @pos: position of the lane
+ * @pol: polarity of the lane
+ */
+struct iss_csiphy_lane {
+       u8 pos;
+       u8 pol;
+};
+
+#define ISS_CSIPHY1_NUM_DATA_LANES     4
+#define ISS_CSIPHY2_NUM_DATA_LANES     1
+
+/**
+ * struct iss_csiphy_lanes_cfg - CSI2 lane configuration
+ * @data: Configuration of one or two data lanes
+ * @clk: Clock lane configuration
+ */
+struct iss_csiphy_lanes_cfg {
+       struct iss_csiphy_lane data[ISS_CSIPHY1_NUM_DATA_LANES];
+       struct iss_csiphy_lane clk;
+};
+
+/**
+ * struct iss_csi2_platform_data - CSI2 interface platform data
+ * @crc: Enable the cyclic redundancy check
+ * @vpclk_div: Video port output clock control
+ */
+struct iss_csi2_platform_data {
+       unsigned crc:1;
+       unsigned vpclk_div:2;
+       struct iss_csiphy_lanes_cfg lanecfg;
+};
+
+struct iss_subdev_i2c_board_info {
+       struct i2c_board_info *board_info;
+       int i2c_adapter_id;
+};
+
+struct iss_v4l2_subdevs_group {
+       struct iss_subdev_i2c_board_info *subdevs;
+       enum iss_interface_type interface;
+       union {
+               struct iss_csi2_platform_data csi2;
+       } bus; /* gcc < 4.6.0 chokes on anonymous union initializers */
+};
+
+struct iss_platform_data {
+       struct iss_v4l2_subdevs_group *subdevs;
+       void (*set_constraints)(struct iss_device *iss, bool enable);
+};
+
+#endif
diff --git a/include/linux/platform_data/media/s5p_hdmi.h b/include/linux/platform_data/media/s5p_hdmi.h
new file mode 100644 (file)
index 0000000..bb9cacb
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Driver header for S5P HDMI chip.
+ *
+ * Copyright (c) 2011 Samsung Electronics, Co. Ltd
+ * Contact: Tomasz Stanislawski <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef S5P_HDMI_H
+#define S5P_HDMI_H
+
+struct i2c_board_info;
+
+/**
+ * @hdmiphy_bus: controller id for HDMIPHY bus
+ * @hdmiphy_info: template for HDMIPHY I2C device
+ * @mhl_bus: controller id for MHL control bus
+ * @mhl_info: template for MHL I2C device
+ * @hpd_gpio: GPIO for Hot-Plug-Detect pin
+ *
+ * NULL pointer for *_info fields indicates that
+ * the corresponding chip is not present
+ */
+struct s5p_hdmi_platform_data {
+       int hdmiphy_bus;
+       struct i2c_board_info *hdmiphy_info;
+       int mhl_bus;
+       struct i2c_board_info *mhl_info;
+       int hpd_gpio;
+};
+
+#endif /* S5P_HDMI_H */
diff --git a/include/linux/platform_data/media/si4713.h b/include/linux/platform_data/media/si4713.h
new file mode 100644 (file)
index 0000000..932668a
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * include/linux/platform_data/media/si4713.h
+ *
+ * Board related data definitions for Si4713 i2c device driver.
+ *
+ * Copyright (c) 2009 Nokia Corporation
+ * Contact: Eduardo Valentin <eduardo.valentin@nokia.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.
+ *
+ */
+
+#ifndef SI4713_H
+#define SI4713_H
+
+/* The SI4713 I2C sensor chip has a fixed slave address of 0xc6 or 0x22. */
+#define SI4713_I2C_ADDR_BUSEN_HIGH     0x63
+#define SI4713_I2C_ADDR_BUSEN_LOW      0x11
+
+/*
+ * Platform dependent definition
+ */
+struct si4713_platform_data {
+       bool is_platform_device;
+};
+
+/*
+ * Structure to query for Received Noise Level (RNL).
+ */
+struct si4713_rnl {
+       __u32 index;            /* modulator index */
+       __u32 frequency;        /* frequency to peform rnl measurement */
+       __s32 rnl;              /* result of measurement in dBuV */
+       __u32 reserved[4];      /* drivers and apps must init this to 0 */
+};
+
+/*
+ * This is the ioctl number to query for rnl. Users must pass a
+ * struct si4713_rnl pointer specifying desired frequency in 'frequency' field
+ * following driver capabilities (i.e V4L2_TUNER_CAP_LOW).
+ * Driver must return measured value in the same struture, filling 'rnl' field.
+ */
+#define SI4713_IOC_MEASURE_RNL _IOWR('V', BASE_VIDIOC_PRIVATE + 0, \
+                                               struct si4713_rnl)
+
+#endif /* ifndef SI4713_H*/
diff --git a/include/linux/platform_data/media/sii9234.h b/include/linux/platform_data/media/sii9234.h
new file mode 100644 (file)
index 0000000..6a4a809
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Driver header for SII9234 MHL converter chip.
+ *
+ * Copyright (c) 2011 Samsung Electronics, Co. Ltd
+ * Contact: Tomasz Stanislawski <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef SII9234_H
+#define SII9234_H
+
+/**
+ * @gpio_n_reset: GPIO driving nRESET pin
+ */
+
+struct sii9234_platform_data {
+       int gpio_n_reset;
+};
+
+#endif /* SII9234_H */
diff --git a/include/linux/platform_data/media/soc_camera_platform.h b/include/linux/platform_data/media/soc_camera_platform.h
new file mode 100644 (file)
index 0000000..1e5065d
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Generic Platform Camera Driver Header
+ *
+ * Copyright (C) 2008 Magnus Damm
+ *
+ * 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 __SOC_CAMERA_H__
+#define __SOC_CAMERA_H__
+
+#include <linux/videodev2.h>
+#include <media/soc_camera.h>
+#include <media/v4l2-mediabus.h>
+
+struct device;
+
+struct soc_camera_platform_info {
+       const char *format_name;
+       unsigned long format_depth;
+       struct v4l2_mbus_framefmt format;
+       unsigned long mbus_param;
+       enum v4l2_mbus_type mbus_type;
+       struct soc_camera_device *icd;
+       int (*set_capture)(struct soc_camera_platform_info *info, int enable);
+};
+
+static inline void soc_camera_platform_release(struct platform_device **pdev)
+{
+       *pdev = NULL;
+}
+
+static inline int soc_camera_platform_add(struct soc_camera_device *icd,
+                                         struct platform_device **pdev,
+                                         struct soc_camera_link *plink,
+                                         void (*release)(struct device *dev),
+                                         int id)
+{
+       struct soc_camera_subdev_desc *ssdd =
+               (struct soc_camera_subdev_desc *)plink;
+       struct soc_camera_platform_info *info = ssdd->drv_priv;
+       int ret;
+
+       if (&icd->sdesc->subdev_desc != ssdd)
+               return -ENODEV;
+
+       if (*pdev)
+               return -EBUSY;
+
+       *pdev = platform_device_alloc("soc_camera_platform", id);
+       if (!*pdev)
+               return -ENOMEM;
+
+       info->icd = icd;
+
+       (*pdev)->dev.platform_data = info;
+       (*pdev)->dev.release = release;
+
+       ret = platform_device_add(*pdev);
+       if (ret < 0) {
+               platform_device_put(*pdev);
+               *pdev = NULL;
+               info->icd = NULL;
+       }
+
+       return ret;
+}
+
+static inline void soc_camera_platform_del(const struct soc_camera_device *icd,
+                                          struct platform_device *pdev,
+                                          const struct soc_camera_link *plink)
+{
+       const struct soc_camera_subdev_desc *ssdd =
+               (const struct soc_camera_subdev_desc *)plink;
+       if (&icd->sdesc->subdev_desc != ssdd || !pdev)
+               return;
+
+       platform_device_unregister(pdev);
+}
+
+#endif /* __SOC_CAMERA_H__ */
diff --git a/include/linux/platform_data/media/timb_radio.h b/include/linux/platform_data/media/timb_radio.h
new file mode 100644 (file)
index 0000000..a40a6a3
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * timb_radio.h Platform struct for the Timberdale radio driver
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the 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 _TIMB_RADIO_
+#define _TIMB_RADIO_ 1
+
+#include <linux/i2c.h>
+
+struct timb_radio_platform_data {
+       int i2c_adapter; /* I2C adapter where the tuner and dsp are attached */
+       struct i2c_board_info *tuner;
+       struct i2c_board_info *dsp;
+};
+
+#endif
diff --git a/include/linux/platform_data/media/timb_video.h b/include/linux/platform_data/media/timb_video.h
new file mode 100644 (file)
index 0000000..70ae439
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * timb_video.h Platform struct for the Timberdale video driver
+ * Copyright (c) 2009-2010 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the 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 _TIMB_VIDEO_
+#define _TIMB_VIDEO_ 1
+
+#include <linux/i2c.h>
+
+struct timb_video_platform_data {
+       int dma_channel;
+       int i2c_adapter; /* The I2C adapter where the encoder is attached */
+       struct {
+               const char *module_name;
+               struct i2c_board_info *info;
+       } encoder;
+};
+
+#endif
diff --git a/include/linux/platform_data/mmc-mvsdio.h b/include/linux/platform_data/mmc-mvsdio.h
deleted file mode 100644 (file)
index d02704c..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef __MMC_MVSDIO_H
-#define __MMC_MVSDIO_H
-
-#include <linux/mbus.h>
-
-struct mvsdio_platform_data {
-       unsigned int clock;
-       int gpio_card_detect;
-       int gpio_write_protect;
-};
-
-#endif
index dc777be5f2e13229fd5e8be9c45634cd70c44d6e..6abd019c76f8eff7d92cd71aa83c9e6d8b2ab471 100644 (file)
@@ -51,6 +51,7 @@ extern void arch_setup_pdev_archdata(struct platform_device *);
 extern struct resource *platform_get_resource(struct platform_device *,
                                              unsigned int, unsigned int);
 extern int platform_get_irq(struct platform_device *, unsigned int);
+extern int platform_irq_count(struct platform_device *);
 extern struct resource *platform_get_resource_byname(struct platform_device *,
                                                     unsigned int,
                                                     const char *);
index 6f14ee2958220b03afcb8c41a8fc2cdcad9ea940..e5e8ec40278dd7f463d59298ce45eb3a86e99b16 100644 (file)
@@ -9,16 +9,12 @@
 #ifndef _POSIX_ACL_XATTR_H
 #define _POSIX_ACL_XATTR_H
 
+#include <uapi/linux/xattr.h>
 #include <linux/posix_acl.h>
 
-/* Extended attribute names */
-#define POSIX_ACL_XATTR_ACCESS "system.posix_acl_access"
-#define POSIX_ACL_XATTR_DEFAULT        "system.posix_acl_default"
-
 /* Supported ACL a_version fields */
 #define POSIX_ACL_XATTR_VERSION        0x0002
 
-
 /* An undefined entry e_id value */
 #define ACL_UNDEFINED_ID       (-1)
 
index 5ed540986019b910ddee9645aff3605d13cf4b3b..14ec1652daf4863c30d471298402611a2da2137a 100644 (file)
@@ -179,32 +179,31 @@ static inline void list_replace_rcu(struct list_head *old,
 }
 
 /**
- * list_splice_init_rcu - splice an RCU-protected list into an existing list.
+ * __list_splice_init_rcu - join an RCU-protected list into an existing list.
  * @list:      the RCU-protected list to splice
- * @head:      the place in the list to splice the first list into
+ * @prev:      points to the last element of the existing list
+ * @next:      points to the first element of the existing list
  * @sync:      function to sync: synchronize_rcu(), synchronize_sched(), ...
  *
- * @head can be RCU-read traversed concurrently with this function.
+ * The list pointed to by @prev and @next can be RCU-read traversed
+ * concurrently with this function.
  *
  * Note that this function blocks.
  *
- * Important note: the caller must take whatever action is necessary to
- *     prevent any other updates to @head.  In principle, it is possible
- *     to modify the list as soon as sync() begins execution.
- *     If this sort of thing becomes necessary, an alternative version
- *     based on call_rcu() could be created.  But only if -really-
- *     needed -- there is no shortage of RCU API members.
+ * Important note: the caller must take whatever action is necessary to prevent
+ * any other updates to the existing list.  In principle, it is possible to
+ * modify the list as soon as sync() begins execution. If this sort of thing
+ * becomes necessary, an alternative version based on call_rcu() could be
+ * created.  But only if -really- needed -- there is no shortage of RCU API
+ * members.
  */
-static inline void list_splice_init_rcu(struct list_head *list,
-                                       struct list_head *head,
-                                       void (*sync)(void))
+static inline void __list_splice_init_rcu(struct list_head *list,
+                                         struct list_head *prev,
+                                         struct list_head *next,
+                                         void (*sync)(void))
 {
        struct list_head *first = list->next;
        struct list_head *last = list->prev;
-       struct list_head *at = head->next;
-
-       if (list_empty(list))
-               return;
 
        /*
         * "first" and "last" tracking list, so initialize it.  RCU readers
@@ -231,10 +230,40 @@ static inline void list_splice_init_rcu(struct list_head *list,
         * this function.
         */
 
-       last->next = at;
-       rcu_assign_pointer(list_next_rcu(head), first);
-       first->prev = head;
-       at->prev = last;
+       last->next = next;
+       rcu_assign_pointer(list_next_rcu(prev), first);
+       first->prev = prev;
+       next->prev = last;
+}
+
+/**
+ * list_splice_init_rcu - splice an RCU-protected list into an existing list,
+ *                        designed for stacks.
+ * @list:      the RCU-protected list to splice
+ * @head:      the place in the existing list to splice the first list into
+ * @sync:      function to sync: synchronize_rcu(), synchronize_sched(), ...
+ */
+static inline void list_splice_init_rcu(struct list_head *list,
+                                       struct list_head *head,
+                                       void (*sync)(void))
+{
+       if (!list_empty(list))
+               __list_splice_init_rcu(list, head, head->next, sync);
+}
+
+/**
+ * list_splice_tail_init_rcu - splice an RCU-protected list into an existing
+ *                             list, designed for queues.
+ * @list:      the RCU-protected list to splice
+ * @head:      the place in the existing list to splice the first list into
+ * @sync:      function to sync: synchronize_rcu(), synchronize_sched(), ...
+ */
+static inline void list_splice_tail_init_rcu(struct list_head *list,
+                                            struct list_head *head,
+                                            void (*sync)(void))
+{
+       if (!list_empty(list))
+               __list_splice_init_rcu(list, head->prev, head, sync);
 }
 
 /**
@@ -304,6 +333,42 @@ static inline void list_splice_init_rcu(struct list_head *list,
                &pos->member != (head); \
                pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
 
+/**
+ * list_entry_lockless - get the struct for this entry
+ * @ptr:        the &struct list_head pointer.
+ * @type:       the type of the struct this is embedded in.
+ * @member:     the name of the list_head within the struct.
+ *
+ * This primitive may safely run concurrently with the _rcu list-mutation
+ * primitives such as list_add_rcu(), but requires some implicit RCU
+ * read-side guarding.  One example is running within a special
+ * exception-time environment where preemption is disabled and where
+ * lockdep cannot be invoked (in which case updaters must use RCU-sched,
+ * as in synchronize_sched(), call_rcu_sched(), and friends).  Another
+ * example is when items are added to the list, but never deleted.
+ */
+#define list_entry_lockless(ptr, type, member) \
+       container_of((typeof(ptr))lockless_dereference(ptr), type, member)
+
+/**
+ * list_for_each_entry_lockless - iterate over rcu list of given type
+ * @pos:       the type * to use as a loop cursor.
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ *
+ * This primitive may safely run concurrently with the _rcu list-mutation
+ * primitives such as list_add_rcu(), but requires some implicit RCU
+ * read-side guarding.  One example is running within a special
+ * exception-time environment where preemption is disabled and where
+ * lockdep cannot be invoked (in which case updaters must use RCU-sched,
+ * as in synchronize_sched(), call_rcu_sched(), and friends).  Another
+ * example is when items are added to the list, but never deleted.
+ */
+#define list_for_each_entry_lockless(pos, head, member) \
+       for (pos = list_entry_lockless((head)->next, typeof(*pos), member); \
+            &pos->member != (head); \
+            pos = list_entry_lockless(pos->member.next, typeof(*pos), member))
+
 /**
  * list_for_each_entry_continue_rcu - continue iteration over list of given type
  * @pos:       the type * to use as a loop cursor.
index a0189ba67fde721a824cc7c8db4b1f015197059e..14e6f47ee16fe49774894f7e9107d4357b2ce0a7 100644 (file)
 
 #include <asm/barrier.h>
 
+#ifndef CONFIG_TINY_RCU
 extern int rcu_expedited; /* for sysctl */
+extern int rcu_normal;    /* also for sysctl */
+#endif /* #ifndef CONFIG_TINY_RCU */
 
 #ifdef CONFIG_TINY_RCU
 /* Tiny RCU doesn't expedite, as its purpose in life is instead to be tiny. */
+static inline bool rcu_gp_is_normal(void)  /* Internal RCU use. */
+{
+       return true;
+}
 static inline bool rcu_gp_is_expedited(void)  /* Internal RCU use. */
 {
        return false;
@@ -65,6 +72,7 @@ static inline void rcu_unexpedite_gp(void)
 {
 }
 #else /* #ifdef CONFIG_TINY_RCU */
+bool rcu_gp_is_normal(void);     /* Internal RCU use. */
 bool rcu_gp_is_expedited(void);  /* Internal RCU use. */
 void rcu_expedite_gp(void);
 void rcu_unexpedite_gp(void);
@@ -321,7 +329,6 @@ static inline int rcu_preempt_depth(void)
 
 /* Internal to kernel */
 void rcu_init(void);
-void rcu_end_inkernel_boot(void);
 void rcu_sched_qs(void);
 void rcu_bh_qs(void);
 void rcu_check_callbacks(int user);
@@ -329,6 +336,12 @@ struct notifier_block;
 int rcu_cpu_notify(struct notifier_block *self,
                   unsigned long action, void *hcpu);
 
+#ifndef CONFIG_TINY_RCU
+void rcu_end_inkernel_boot(void);
+#else /* #ifndef CONFIG_TINY_RCU */
+static inline void rcu_end_inkernel_boot(void) { }
+#endif /* #ifndef CONFIG_TINY_RCU */
+
 #ifdef CONFIG_RCU_STALL_COMMON
 void rcu_sysrq_start(void);
 void rcu_sysrq_end(void);
@@ -379,9 +392,9 @@ static inline void rcu_init_nohz(void)
  */
 #define RCU_NONIDLE(a) \
        do { \
-               rcu_irq_enter(); \
+               rcu_irq_enter_irqson(); \
                do { a; } while (0); \
-               rcu_irq_exit(); \
+               rcu_irq_exit_irqson(); \
        } while (0)
 
 /*
@@ -741,7 +754,7 @@ static inline void rcu_preempt_sleep_check(void)
  * The tracing infrastructure traces RCU (we want that), but unfortunately
  * some of the RCU checks causes tracing to lock up the system.
  *
- * The tracing version of rcu_dereference_raw() must not call
+ * The no-tracing version of rcu_dereference_raw() must not call
  * rcu_read_lock_held().
  */
 #define rcu_dereference_raw_notrace(p) __rcu_dereference_check((p), 1, __rcu)
index 4c1aaf9cce7b3ac767c69d7849715d69089a9b48..64809aea661cee43646c4803247604cc40f16d6c 100644 (file)
@@ -181,6 +181,14 @@ static inline void rcu_irq_enter(void)
 {
 }
 
+static inline void rcu_irq_exit_irqson(void)
+{
+}
+
+static inline void rcu_irq_enter_irqson(void)
+{
+}
+
 static inline void rcu_irq_exit(void)
 {
 }
index 60d15a080d7c3dcde45cf458df5632dfc5b36ac2..ad1eda9fa4daea077998d253dc604c18c3d444c6 100644 (file)
@@ -37,7 +37,7 @@ void rcu_cpu_stall_reset(void);
 /*
  * Note a virtualization-based context switch.  This is simply a
  * wrapper around rcu_note_context_switch(), which allows TINY_RCU
- * to save a few bytes.
+ * to save a few bytes. The caller must have disabled interrupts.
  */
 static inline void rcu_virt_note_context_switch(int cpu)
 {
@@ -97,6 +97,8 @@ void rcu_idle_enter(void);
 void rcu_idle_exit(void);
 void rcu_irq_enter(void);
 void rcu_irq_exit(void);
+void rcu_irq_enter_irqson(void);
+void rcu_irq_exit_irqson(void);
 
 void exit_rcu(void);
 
index d68bb402120e2c1a6d640720ef384663ceaefebe..18394343f4891a42dc986e4a17e9c9ebb0b747ee 100644 (file)
@@ -788,10 +788,16 @@ int regmap_fields_update_bits(struct regmap_field *field,  unsigned int id,
  *
  * @reg_offset: Offset of the status/mask register within the bank
  * @mask:       Mask used to flag/control the register.
+ * @type_reg_offset: Offset register for the irq type setting.
+ * @type_rising_mask: Mask bit to configure RISING type irq.
+ * @type_falling_mask: Mask bit to configure FALLING type irq.
  */
 struct regmap_irq {
        unsigned int reg_offset;
        unsigned int mask;
+       unsigned int type_reg_offset;
+       unsigned int type_rising_mask;
+       unsigned int type_falling_mask;
 };
 
 #define REGMAP_IRQ_REG(_irq, _off, _mask)              \
@@ -811,18 +817,23 @@ struct regmap_irq {
  * @ack_base:    Base ack address. If zero then the chip is clear on read.
  *               Using zero value is possible with @use_ack bit.
  * @wake_base:   Base address for wake enables.  If zero unsupported.
+ * @type_base:   Base address for irq type.  If zero unsupported.
  * @irq_reg_stride:  Stride to use for chips where registers are not contiguous.
  * @init_ack_masked: Ack all masked interrupts once during initalization.
  * @mask_invert: Inverted mask register: cleared bits are masked out.
  * @use_ack:     Use @ack register even if it is zero.
  * @ack_invert:  Inverted ack register: cleared bits for ack.
  * @wake_invert: Inverted wake register: cleared bits are wake enabled.
+ * @type_invert: Invert the type flags.
  * @runtime_pm:  Hold a runtime PM lock on the device when accessing it.
  *
  * @num_regs:    Number of registers in each control bank.
  * @irqs:        Descriptors for individual IRQs.  Interrupt numbers are
  *               assigned based on the index in the array of the interrupt.
  * @num_irqs:    Number of descriptors.
+ * @num_type_reg:    Number of type registers.
+ * @type_reg_stride: Stride to use for chips where type registers are not
+ *                     contiguous.
  */
 struct regmap_irq_chip {
        const char *name;
@@ -832,6 +843,7 @@ struct regmap_irq_chip {
        unsigned int unmask_base;
        unsigned int ack_base;
        unsigned int wake_base;
+       unsigned int type_base;
        unsigned int irq_reg_stride;
        bool init_ack_masked:1;
        bool mask_invert:1;
@@ -839,11 +851,15 @@ struct regmap_irq_chip {
        bool ack_invert:1;
        bool wake_invert:1;
        bool runtime_pm:1;
+       bool type_invert:1;
 
        int num_regs;
 
        const struct regmap_irq *irqs;
        int num_irqs;
+
+       int num_type_reg;
+       unsigned int type_reg_stride;
 };
 
 struct regmap_irq_chip_data;
@@ -1021,7 +1037,7 @@ static inline void regmap_async_complete(struct regmap *map)
 }
 
 static inline int regmap_register_patch(struct regmap *map,
-                                       const struct reg_default *regs,
+                                       const struct reg_sequence *regs,
                                        int num_regs)
 {
        WARN_ONCE(1, "regmap API is disabled");
index edad7a43edea141b3ada89f7f12edac2add7b68e..4bae8ab3b89391f7d8d1566f56d3666d5d19058d 100644 (file)
@@ -177,9 +177,9 @@ extern void get_iowait_load(unsigned long *nr_waiters, unsigned long *load);
 extern void calc_global_load(unsigned long ticks);
 
 #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON)
-extern void update_cpu_load_nohz(void);
+extern void update_cpu_load_nohz(int active);
 #else
-static inline void update_cpu_load_nohz(void) { }
+static inline void update_cpu_load_nohz(int active) { }
 #endif
 
 extern unsigned long get_parent_ip(unsigned long addr);
@@ -377,6 +377,7 @@ extern void scheduler_tick(void);
 extern void sched_show_task(struct task_struct *p);
 
 #ifdef CONFIG_LOCKUP_DETECTOR
+extern void touch_softlockup_watchdog_sched(void);
 extern void touch_softlockup_watchdog(void);
 extern void touch_softlockup_watchdog_sync(void);
 extern void touch_all_softlockup_watchdogs(void);
@@ -387,6 +388,9 @@ extern unsigned int  softlockup_panic;
 extern unsigned int  hardlockup_panic;
 void lockup_detector_init(void);
 #else
+static inline void touch_softlockup_watchdog_sched(void)
+{
+}
 static inline void touch_softlockup_watchdog(void)
 {
 }
@@ -1268,8 +1272,13 @@ struct sched_entity {
 #endif
 
 #ifdef CONFIG_SMP
-       /* Per entity load average tracking */
-       struct sched_avg        avg;
+       /*
+        * Per entity load average tracking.
+        *
+        * Put into separate cache line so it does not
+        * collide with read-mostly values above.
+        */
+       struct sched_avg        avg ____cacheline_aligned_in_smp;
 #endif
 };
 
@@ -1455,14 +1464,15 @@ struct task_struct {
        /* Used for emulating ABI behavior of previous Linux versions */
        unsigned int personality;
 
-       unsigned in_execve:1;   /* Tell the LSMs that the process is doing an
-                                * execve */
-       unsigned in_iowait:1;
-
-       /* Revert to default priority/policy when forking */
+       /* scheduler bits, serialized by scheduler locks */
        unsigned sched_reset_on_fork:1;
        unsigned sched_contributes_to_load:1;
        unsigned sched_migrated:1;
+       unsigned :0; /* force alignment to the next boundary */
+
+       /* unserialized, strictly 'current' */
+       unsigned in_execve:1; /* bit to tell LSMs we're in execve */
+       unsigned in_iowait:1;
 #ifdef CONFIG_MEMCG
        unsigned memcg_may_oom:1;
 #endif
@@ -1519,11 +1529,14 @@ struct task_struct {
        cputime_t gtime;
        struct prev_cputime prev_cputime;
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
-       seqlock_t vtime_seqlock;
+       seqcount_t vtime_seqcount;
        unsigned long long vtime_snap;
        enum {
-               VTIME_SLEEPING = 0,
+               /* Task is sleeping or running in a CPU with VTIME inactive */
+               VTIME_INACTIVE = 0,
+               /* Task runs in userspace in a CPU with VTIME active */
                VTIME_USER,
+               /* Task runs in kernelspace in a CPU with VTIME active */
                VTIME_SYS,
        } vtime_snap_whence;
 #endif
@@ -2002,7 +2015,8 @@ static inline int pid_alive(const struct task_struct *p)
 }
 
 /**
- * is_global_init - check if a task structure is init
+ * is_global_init - check if a task structure is init. Since init
+ * is free to have sub-threads we need to check tgid.
  * @tsk: Task structure to be checked.
  *
  * Check if a task structure is the first user space task the kernel created.
@@ -2011,7 +2025,7 @@ static inline int pid_alive(const struct task_struct *p)
  */
 static inline int is_global_init(struct task_struct *tsk)
 {
-       return tsk->pid == 1;
+       return task_tgid_nr(tsk) == 1;
 }
 
 extern struct pid *cad_pid;
index efa931c5cef145e354fd290cf0794bccb7446247..411b52e424e1b2178b961bbec2081c3a0e58affd 100644 (file)
 
 #ifdef CONFIG_GENERIC_SCHED_CLOCK
 extern void sched_clock_postinit(void);
-#else
-static inline void sched_clock_postinit(void) { }
-#endif
 
 extern void sched_clock_register(u64 (*read)(void), int bits,
                                 unsigned long rate);
+#else
+static inline void sched_clock_postinit(void) { }
+
+static inline void sched_clock_register(u64 (*read)(void), int bits,
+                                       unsigned long rate)
+{
+       ;
+}
+#endif
 
 #endif
index 0e1b1540597a47253b6a2e5cc3ef1709d4a42992..3cc9632dcc2a5b6e58259fcec14ce07ca87a4618 100644 (file)
@@ -29,7 +29,7 @@ struct cpu_stop_work {
 
 int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg);
 int stop_two_cpus(unsigned int cpu1, unsigned int cpu2, cpu_stop_fn_t fn, void *arg);
-void stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
+bool stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
                         struct cpu_stop_work *work_buf);
 int stop_cpus(const struct cpumask *cpumask, cpu_stop_fn_t fn, void *arg);
 int try_stop_cpus(const struct cpumask *cpumask, cpu_stop_fn_t fn, void *arg);
@@ -65,7 +65,7 @@ static void stop_one_cpu_nowait_workfn(struct work_struct *work)
        preempt_enable();
 }
 
-static inline void stop_one_cpu_nowait(unsigned int cpu,
+static inline bool stop_one_cpu_nowait(unsigned int cpu,
                                       cpu_stop_fn_t fn, void *arg,
                                       struct cpu_stop_work *work_buf)
 {
@@ -74,7 +74,10 @@ static inline void stop_one_cpu_nowait(unsigned int cpu,
                work_buf->fn = fn;
                work_buf->arg = arg;
                schedule_work(&work_buf->work);
+               return true;
        }
+
+       return false;
 }
 
 static inline int stop_cpus(const struct cpumask *cpumask,
index beebe3a02d43f5c527633cbd12af690c02e8288d..297f09f23896d2db41cd90a0cad37746e6ed77aa 100644 (file)
@@ -125,6 +125,32 @@ static inline bool timeval_valid(const struct timeval *tv)
 
 extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
 
+/*
+ * Validates if a timespec/timeval used to inject a time offset is valid.
+ * Offsets can be postive or negative. The value of the timeval/timespec
+ * is the sum of its fields, but *NOTE*: the field tv_usec/tv_nsec must
+ * always be non-negative.
+ */
+static inline bool timeval_inject_offset_valid(const struct timeval *tv)
+{
+       /* We don't check the tv_sec as it can be positive or negative */
+
+       /* Can't have more microseconds then a second */
+       if (tv->tv_usec < 0 || tv->tv_usec >= USEC_PER_SEC)
+               return false;
+       return true;
+}
+
+static inline bool timespec_inject_offset_valid(const struct timespec *ts)
+{
+       /* We don't check the tv_sec as it can be positive or negative */
+
+       /* Can't have more nanoseconds then a second */
+       if (ts->tv_nsec < 0 || ts->tv_nsec >= NSEC_PER_SEC)
+               return false;
+       return true;
+}
+
 #define CURRENT_TIME           (current_kernel_time())
 #define CURRENT_TIME_SEC       ((struct timespec) { get_seconds(), 0 })
 
diff --git a/include/linux/tracepoint-defs.h b/include/linux/tracepoint-defs.h
new file mode 100644 (file)
index 0000000..e1ee97c
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef TRACEPOINT_DEFS_H
+#define TRACEPOINT_DEFS_H 1
+
+/*
+ * File can be included directly by headers who only want to access
+ * tracepoint->key to guard out of line trace calls. Otherwise
+ * linux/tracepoint.h should be used.
+ */
+
+#include <linux/atomic.h>
+#include <linux/static_key.h>
+
+struct tracepoint_func {
+       void *func;
+       void *data;
+       int prio;
+};
+
+struct tracepoint {
+       const char *name;               /* Tracepoint name */
+       struct static_key key;
+       void (*regfunc)(void);
+       void (*unregfunc)(void);
+       struct tracepoint_func __rcu *funcs;
+};
+
+#endif
index 696a339c592c831942a8fcdc9b2e5ea963599747..78e8397a1800334f329637baa152f3ed6c79718a 100644 (file)
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/rcupdate.h>
-#include <linux/static_key.h>
+#include <linux/tracepoint-defs.h>
 
 struct module;
 struct tracepoint;
 struct notifier_block;
 
-struct tracepoint_func {
-       void *func;
-       void *data;
-       int prio;
-};
-
-struct tracepoint {
-       const char *name;               /* Tracepoint name */
-       struct static_key key;
-       void (*regfunc)(void);
-       void (*unregfunc)(void);
-       struct tracepoint_func __rcu *funcs;
-};
-
 struct trace_enum_map {
        const char              *system;
        const char              *enum_string;
@@ -171,8 +157,8 @@ extern void syscall_unregfunc(void);
                                TP_PROTO(data_proto),                   \
                                TP_ARGS(data_args),                     \
                                TP_CONDITION(cond),                     \
-                               rcu_irq_enter(),                        \
-                               rcu_irq_exit());                        \
+                               rcu_irq_enter_irqson(),                 \
+                               rcu_irq_exit_irqson());                 \
        }
 #else
 #define __DECLARE_TRACE_RCU(name, proto, args, cond, data_proto, data_args)
index 1f6526c76ee84f4068707bd0ecae16aaa25c0759..3a375d07d0dc0284441133228af266956ed94f89 100644 (file)
@@ -138,6 +138,7 @@ struct cdc_ncm_ctx {
 };
 
 u8 cdc_ncm_select_altsetting(struct usb_interface *intf);
+int cdc_ncm_change_mtu(struct net_device *net, int new_mtu);
 int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags);
 void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf);
 struct sk_buff *cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign);
index 73ea2fb0473185cc752232d18e80e566a6f57e97..16c0ed6c50a7f6ad67319c49108deabcba977a42 100644 (file)
@@ -46,7 +46,7 @@
  * All kernel-specific stuff were moved to media/v4l2-dev.h, so
  * no #if __KERNEL tests are allowed here
  *
- *     See http://linuxtv.org for more info
+ *     See https://linuxtv.org for more info
  *
  *     Author: Bill Dirks <bill@thedirks.org>
  *             Justin Schoeman
index 5dbc8b0ee567a751cf8c60872ae692fccb6a86ab..3e5d9075960f6c756ead3c60013f84f873206932 100644 (file)
@@ -176,11 +176,11 @@ extern void zone_statistics(struct zone *, struct zone *, gfp_t gfp);
 #define sub_zone_page_state(__z, __i, __d) mod_zone_page_state(__z, __i, -(__d))
 
 #ifdef CONFIG_SMP
-void __mod_zone_page_state(struct zone *, enum zone_stat_item item, int);
+void __mod_zone_page_state(struct zone *, enum zone_stat_item item, long);
 void __inc_zone_page_state(struct page *, enum zone_stat_item);
 void __dec_zone_page_state(struct page *, enum zone_stat_item);
 
-void mod_zone_page_state(struct zone *, enum zone_stat_item, int);
+void mod_zone_page_state(struct zone *, enum zone_stat_item, long);
 void inc_zone_page_state(struct page *, enum zone_stat_item);
 void dec_zone_page_state(struct page *, enum zone_stat_item);
 
@@ -205,7 +205,7 @@ void set_pgdat_percpu_threshold(pg_data_t *pgdat,
  * The functions directly modify the zone and global counters.
  */
 static inline void __mod_zone_page_state(struct zone *zone,
-                       enum zone_stat_item item, int delta)
+                       enum zone_stat_item item, long delta)
 {
        zone_page_state_add(delta, zone, item);
 }
index c5165fd256f9d25162d648e53e1e73d95a740caf..fa2196990f84b2db9d77883b0bb7d7f329d0cc8e 100644 (file)
 struct task_struct;
 
 /*
- * vtime_accounting_enabled() definitions/declarations
+ * vtime_accounting_cpu_enabled() definitions/declarations
  */
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
-static inline bool vtime_accounting_enabled(void) { return true; }
+static inline bool vtime_accounting_cpu_enabled(void) { return true; }
 #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
+/*
+ * Checks if vtime is enabled on some CPU. Cputime readers want to be careful
+ * in that case and compute the tickless cputime.
+ * For now vtime state is tied to context tracking. We might want to decouple
+ * those later if necessary.
+ */
 static inline bool vtime_accounting_enabled(void)
 {
-       if (context_tracking_is_enabled()) {
+       return context_tracking_is_enabled();
+}
+
+static inline bool vtime_accounting_cpu_enabled(void)
+{
+       if (vtime_accounting_enabled()) {
                if (context_tracking_cpu_is_enabled())
                        return true;
        }
@@ -29,7 +40,7 @@ static inline bool vtime_accounting_enabled(void)
 #endif /* CONFIG_VIRT_CPU_ACCOUNTING_GEN */
 
 #ifndef CONFIG_VIRT_CPU_ACCOUNTING
-static inline bool vtime_accounting_enabled(void) { return false; }
+static inline bool vtime_accounting_cpu_enabled(void) { return false; }
 #endif /* !CONFIG_VIRT_CPU_ACCOUNTING */
 
 
@@ -44,7 +55,7 @@ extern void vtime_task_switch(struct task_struct *prev);
 extern void vtime_common_task_switch(struct task_struct *prev);
 static inline void vtime_task_switch(struct task_struct *prev)
 {
-       if (vtime_accounting_enabled())
+       if (vtime_accounting_cpu_enabled())
                vtime_common_task_switch(prev);
 }
 #endif /* __ARCH_HAS_VTIME_TASK_SWITCH */
@@ -59,7 +70,7 @@ extern void vtime_account_irq_enter(struct task_struct *tsk);
 extern void vtime_common_account_irq_enter(struct task_struct *tsk);
 static inline void vtime_account_irq_enter(struct task_struct *tsk)
 {
-       if (vtime_accounting_enabled())
+       if (vtime_accounting_cpu_enabled())
                vtime_common_account_irq_enter(tsk);
 }
 #endif /* __ARCH_HAS_VTIME_ACCOUNT */
@@ -78,7 +89,7 @@ extern void vtime_gen_account_irq_exit(struct task_struct *tsk);
 
 static inline void vtime_account_irq_exit(struct task_struct *tsk)
 {
-       if (vtime_accounting_enabled())
+       if (vtime_accounting_cpu_enabled())
                vtime_gen_account_irq_exit(tsk);
 }
 
index 513b36f04dfd80bbe9cf40a272e8d2cd2eab452b..d2f4ec7dba7c5f589a819446f23d29d5ca742238 100644 (file)
@@ -102,6 +102,36 @@ init_waitqueue_func_entry(wait_queue_t *q, wait_queue_func_t func)
        q->func         = func;
 }
 
+/**
+ * waitqueue_active -- locklessly test for waiters on the queue
+ * @q: the waitqueue to test for waiters
+ *
+ * returns true if the wait list is not empty
+ *
+ * NOTE: this function is lockless and requires care, incorrect usage _will_
+ * lead to sporadic and non-obvious failure.
+ *
+ * Use either while holding wait_queue_head_t::lock or when used for wakeups
+ * with an extra smp_mb() like:
+ *
+ *      CPU0 - waker                    CPU1 - waiter
+ *
+ *                                      for (;;) {
+ *      @cond = true;                     prepare_to_wait(&wq, &wait, state);
+ *      smp_mb();                         // smp_mb() from set_current_state()
+ *      if (waitqueue_active(wq))         if (@cond)
+ *        wake_up(wq);                      break;
+ *                                        schedule();
+ *                                      }
+ *                                      finish_wait(&wq, &wait);
+ *
+ * Because without the explicit smp_mb() it's possible for the
+ * waitqueue_active() load to get hoisted over the @cond store such that we'll
+ * observe an empty wait list while the waiter might not observe @cond.
+ *
+ * Also note that this 'optimization' trades a spin_lock() for an smp_mb(),
+ * which (when the lock is uncontended) are of roughly equal cost.
+ */
 static inline int waitqueue_active(wait_queue_head_t *q)
 {
        return !list_empty(&q->task_list);
index 0197358f1e815ff51d51f91fe2453a778a364da4..0e32bc71245ef46b90aa21112e4d2bef42cc5950 100644 (file)
@@ -618,4 +618,10 @@ static inline int workqueue_sysfs_register(struct workqueue_struct *wq)
 { return 0; }
 #endif /* CONFIG_SYSFS */
 
+#ifdef CONFIG_WQ_WATCHDOG
+void wq_watchdog_touch(int cpu);
+#else  /* CONFIG_WQ_WATCHDOG */
+static inline void wq_watchdog_touch(int cpu) { }
+#endif /* CONFIG_WQ_WATCHDOG */
+
 #endif
index 89474b9d260cf44151b21e26ce5d64aecf62b6cb..4457541de3c9be14997fe3b4631d60a32fcdb810 100644 (file)
 struct inode;
 struct dentry;
 
+/*
+ * struct xattr_handler: When @name is set, match attributes with exactly that
+ * name.  When @prefix is set instead, match attributes with that prefix and
+ * with a non-empty suffix.
+ */
 struct xattr_handler {
+       const char *name;
        const char *prefix;
        int flags;      /* fs private flags */
-       size_t (*list)(const struct xattr_handler *, struct dentry *dentry,
-                      char *list, size_t list_size, const char *name,
-                      size_t name_len);
+       bool (*list)(struct dentry *dentry);
        int (*get)(const struct xattr_handler *, struct dentry *dentry,
                   const char *name, void *buffer, size_t size);
        int (*set)(const struct xattr_handler *, struct dentry *dentry,
@@ -53,8 +57,11 @@ int generic_setxattr(struct dentry *dentry, const char *name, const void *value,
 int generic_removexattr(struct dentry *dentry, const char *name);
 ssize_t vfs_getxattr_alloc(struct dentry *dentry, const char *name,
                           char **xattr_value, size_t size, gfp_t flags);
-int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name,
-                 const char *value, size_t size, gfp_t flags);
+
+static inline const char *xattr_prefix(const struct xattr_handler *handler)
+{
+       return handler->prefix ?: handler->name;
+}
 
 struct simple_xattrs {
        struct list_head head;
@@ -95,8 +102,7 @@ int simple_xattr_get(struct simple_xattrs *xattrs, const char *name,
                     void *buffer, size_t size);
 int simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
                     const void *value, size_t size, int flags);
-int simple_xattr_remove(struct simple_xattrs *xattrs, const char *name);
-ssize_t simple_xattr_list(struct simple_xattrs *xattrs, char *buffer,
+ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs, char *buffer,
                          size_t size);
 void simple_xattr_list_add(struct simple_xattrs *xattrs,
                           struct simple_xattr *new_xattr);
diff --git a/include/media/ad9389b.h b/include/media/ad9389b.h
deleted file mode 100644 (file)
index 5ba9af8..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Analog Devices AD9389B/AD9889B video encoder driver header
- *
- * Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef AD9389B_H
-#define AD9389B_H
-
-enum ad9389b_tmds_pll_gear {
-       AD9389B_TMDS_PLL_GEAR_AUTOMATIC,
-       AD9389B_TMDS_PLL_GEAR_SEMI_AUTOMATIC,
-};
-
-/* Platform dependent definitions */
-struct ad9389b_platform_data {
-       enum ad9389b_tmds_pll_gear tmds_pll_gear ;
-       /* Differential Data/Clock Output Drive Strength (reg. 0xa2/0xa3) */
-       u8 diff_data_drive_strength;
-       u8 diff_clk_drive_strength;
-};
-
-/* notify events */
-#define AD9389B_MONITOR_DETECT 0
-#define AD9389B_EDID_DETECT 1
-
-struct ad9389b_monitor_detect {
-       int present;
-};
-
-struct ad9389b_edid_detect {
-       int present;
-       int segment;
-};
-
-#endif
diff --git a/include/media/adp1653.h b/include/media/adp1653.h
deleted file mode 100644 (file)
index 9779c85..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * include/media/adp1653.h
- *
- * Copyright (C) 2008--2011 Nokia Corporation
- *
- * Contact: Sakari Ailus <sakari.ailus@iki.fi>
- *
- * Contributors:
- *     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.
- *
- * You 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
-#define ADP1653_H
-
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-subdev.h>
-
-#define ADP1653_NAME                           "adp1653"
-#define ADP1653_I2C_ADDR                       (0x60 >> 1)
-
-/* Register definitions */
-#define ADP1653_REG_OUT_SEL                    0x00
-#define ADP1653_REG_OUT_SEL_HPLED_TORCH_MIN    0x01
-#define ADP1653_REG_OUT_SEL_HPLED_TORCH_MAX    0x0b
-#define ADP1653_REG_OUT_SEL_HPLED_FLASH_MIN    0x0c
-#define ADP1653_REG_OUT_SEL_HPLED_FLASH_MAX    0x1f
-#define ADP1653_REG_OUT_SEL_HPLED_SHIFT                3
-#define ADP1653_REG_OUT_SEL_ILED_MAX           0x07
-#define ADP1653_REG_OUT_SEL_ILED_SHIFT         0
-
-#define ADP1653_REG_CONFIG                     0x01
-#define ADP1653_REG_CONFIG_TMR_CFG             (1 << 4)
-#define ADP1653_REG_CONFIG_TMR_SET_MAX         0x0f
-#define ADP1653_REG_CONFIG_TMR_SET_SHIFT       0
-
-#define ADP1653_REG_SW_STROBE                  0x02
-#define ADP1653_REG_SW_STROBE_SW_STROBE                (1 << 0)
-
-#define ADP1653_REG_FAULT                      0x03
-#define ADP1653_REG_FAULT_FLT_SCP              (1 << 3)
-#define ADP1653_REG_FAULT_FLT_OT               (1 << 2)
-#define ADP1653_REG_FAULT_FLT_TMR              (1 << 1)
-#define ADP1653_REG_FAULT_FLT_OV               (1 << 0)
-
-#define ADP1653_INDICATOR_INTENSITY_MIN                0
-#define ADP1653_INDICATOR_INTENSITY_STEP       2500
-#define ADP1653_INDICATOR_INTENSITY_MAX                \
-       (ADP1653_REG_OUT_SEL_ILED_MAX * ADP1653_INDICATOR_INTENSITY_STEP)
-#define ADP1653_INDICATOR_INTENSITY_uA_TO_REG(a) \
-       ((a) / ADP1653_INDICATOR_INTENSITY_STEP)
-#define ADP1653_INDICATOR_INTENSITY_REG_TO_uA(a) \
-       ((a) * ADP1653_INDICATOR_INTENSITY_STEP)
-
-#define ADP1653_FLASH_INTENSITY_BASE           35
-#define ADP1653_FLASH_INTENSITY_STEP           15
-#define ADP1653_FLASH_INTENSITY_MIN                                    \
-       (ADP1653_FLASH_INTENSITY_BASE                                   \
-        + ADP1653_REG_OUT_SEL_HPLED_FLASH_MIN * ADP1653_FLASH_INTENSITY_STEP)
-#define ADP1653_FLASH_INTENSITY_MAX                    \
-       (ADP1653_FLASH_INTENSITY_MIN +                  \
-        (ADP1653_REG_OUT_SEL_HPLED_FLASH_MAX -         \
-         ADP1653_REG_OUT_SEL_HPLED_FLASH_MIN + 1) *    \
-        ADP1653_FLASH_INTENSITY_STEP)
-
-#define ADP1653_FLASH_INTENSITY_mA_TO_REG(a)                           \
-       ((a) < ADP1653_FLASH_INTENSITY_BASE ? 0 :                       \
-        (((a) - ADP1653_FLASH_INTENSITY_BASE) / ADP1653_FLASH_INTENSITY_STEP))
-#define ADP1653_FLASH_INTENSITY_REG_TO_mA(a)           \
-       ((a) * ADP1653_FLASH_INTENSITY_STEP + ADP1653_FLASH_INTENSITY_BASE)
-
-#define ADP1653_TORCH_INTENSITY_MIN                                    \
-       (ADP1653_FLASH_INTENSITY_BASE                                   \
-        + ADP1653_REG_OUT_SEL_HPLED_TORCH_MIN * ADP1653_FLASH_INTENSITY_STEP)
-#define ADP1653_TORCH_INTENSITY_MAX                    \
-       (ADP1653_TORCH_INTENSITY_MIN +                  \
-        (ADP1653_REG_OUT_SEL_HPLED_TORCH_MAX -         \
-         ADP1653_REG_OUT_SEL_HPLED_TORCH_MIN + 1) *    \
-        ADP1653_FLASH_INTENSITY_STEP)
-
-struct adp1653_platform_data {
-       int (*power)(struct v4l2_subdev *sd, int on);
-
-       u32 max_flash_timeout;          /* flash light timeout in us */
-       u32 max_flash_intensity;        /* led intensity, flash mode, mA */
-       u32 max_torch_intensity;        /* led intensity, torch mode, mA */
-       u32 max_indicator_intensity;    /* indicator led intensity, uA */
-
-       struct gpio_desc *enable_gpio;  /* for device-tree based boot */
-};
-
-#define to_adp1653_flash(sd)   container_of(sd, struct adp1653_flash, subdev)
-
-struct adp1653_flash {
-       struct v4l2_subdev subdev;
-       struct adp1653_platform_data *platform_data;
-
-       struct v4l2_ctrl_handler ctrls;
-       struct v4l2_ctrl *led_mode;
-       struct v4l2_ctrl *flash_timeout;
-       struct v4l2_ctrl *flash_intensity;
-       struct v4l2_ctrl *torch_intensity;
-       struct v4l2_ctrl *indicator_intensity;
-
-       struct mutex power_lock;
-       int power_count;
-       int fault;
-};
-
-#endif /* ADP1653_H */
diff --git a/include/media/adv7183.h b/include/media/adv7183.h
deleted file mode 100644 (file)
index c5c2d37..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * adv7183.h - definition for adv7183 inputs and outputs
- *
- * Copyright (c) 2011 Analog Devices Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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 _ADV7183_H_
-#define _ADV7183_H_
-
-/* ADV7183 HW inputs */
-#define ADV7183_COMPOSITE0  0  /* CVBS in on AIN1 */
-#define ADV7183_COMPOSITE1  1  /* CVBS in on AIN2 */
-#define ADV7183_COMPOSITE2  2  /* CVBS in on AIN3 */
-#define ADV7183_COMPOSITE3  3  /* CVBS in on AIN4 */
-#define ADV7183_COMPOSITE4  4  /* CVBS in on AIN5 */
-#define ADV7183_COMPOSITE5  5  /* CVBS in on AIN6 */
-#define ADV7183_COMPOSITE6  6  /* CVBS in on AIN7 */
-#define ADV7183_COMPOSITE7  7  /* CVBS in on AIN8 */
-#define ADV7183_COMPOSITE8  8  /* CVBS in on AIN9 */
-#define ADV7183_COMPOSITE9  9  /* CVBS in on AIN10 */
-#define ADV7183_COMPOSITE10 10 /* CVBS in on AIN11 */
-
-#define ADV7183_SVIDEO0     11 /* Y on AIN1, C on AIN4 */
-#define ADV7183_SVIDEO1     12 /* Y on AIN2, C on AIN5 */
-#define ADV7183_SVIDEO2     13 /* Y on AIN3, C on AIN6 */
-
-#define ADV7183_COMPONENT0  14 /* Y on AIN1, Pr on AIN4, Pb on AIN5 */
-#define ADV7183_COMPONENT1  15 /* Y on AIN2, Pr on AIN3, Pb on AIN6 */
-
-/* ADV7183 HW outputs */
-#define ADV7183_8BIT_OUT    0
-#define ADV7183_16BIT_OUT   1
-
-#endif
diff --git a/include/media/adv7343.h b/include/media/adv7343.h
deleted file mode 100644 (file)
index e4142b1..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * ADV7343 header file
- *
- * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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.
- */
-
-#ifndef ADV7343_H
-#define ADV7343_H
-
-#define ADV7343_COMPOSITE_ID   (0)
-#define ADV7343_COMPONENT_ID   (1)
-#define ADV7343_SVIDEO_ID      (2)
-
-/**
- * adv7343_power_mode - power mode configuration.
- * @sleep_mode: on enable the current consumption is reduced to micro ampere
- *             level. All DACs and the internal PLL circuit are disabled.
- *             Registers can be read from and written in sleep mode.
- * @pll_control: PLL and oversampling control. This control allows internal
- *              PLL 1 circuit to be powered down and the oversampling to be
- *              switched off.
- * @dac: array to configure power on/off DAC's 1..6
- *
- * Power mode register (Register 0x0), for more info refer REGISTER MAP ACCESS
- * section of datasheet[1], table 17 page no 30.
- *
- * [1] http://www.analog.com/static/imported-files/data_sheets/ADV7342_7343.pdf
- */
-struct adv7343_power_mode {
-       bool sleep_mode;
-       bool pll_control;
-       u32 dac[6];
-};
-
-/**
- * struct adv7343_sd_config - SD Only Output Configuration.
- * @sd_dac_out: array configuring SD DAC Outputs 1 and 2
- */
-struct adv7343_sd_config {
-       /* SD only Output Configuration */
-       u32 sd_dac_out[2];
-};
-
-/**
- * struct adv7343_platform_data - Platform data values and access functions.
- * @mode_config: Configuration for power mode.
- * @sd_config: SD Only Configuration.
- */
-struct adv7343_platform_data {
-       struct adv7343_power_mode mode_config;
-       struct adv7343_sd_config sd_config;
-};
-
-#endif                         /* End of #ifndef ADV7343_H */
diff --git a/include/media/adv7393.h b/include/media/adv7393.h
deleted file mode 100644 (file)
index b28edf3..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * ADV7393 header file
- *
- * Copyright (C) 2010-2012 ADVANSEE - http://www.advansee.com/
- * Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
- *
- * Based on ADV7343 driver,
- *
- * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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.
- */
-
-#ifndef ADV7393_H
-#define ADV7393_H
-
-#define ADV7393_COMPOSITE_ID   (0)
-#define ADV7393_COMPONENT_ID   (1)
-#define ADV7393_SVIDEO_ID      (2)
-
-#endif                         /* End of #ifndef ADV7393_H */
diff --git a/include/media/adv7511.h b/include/media/adv7511.h
deleted file mode 100644 (file)
index d83b91d..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Analog Devices ADV7511 HDMI Transmitter Device Driver
- *
- * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef ADV7511_H
-#define ADV7511_H
-
-/* notify events */
-#define ADV7511_MONITOR_DETECT 0
-#define ADV7511_EDID_DETECT 1
-
-
-struct adv7511_monitor_detect {
-       int present;
-};
-
-struct adv7511_edid_detect {
-       int present;
-       int segment;
-};
-
-struct adv7511_cec_arg {
-       void *arg;
-       u32 f_flags;
-};
-
-struct adv7511_platform_data {
-       u8 i2c_edid;
-       u8 i2c_cec;
-       u8 i2c_pktmem;
-       u32 cec_clk;
-};
-
-#endif
diff --git a/include/media/adv7604.h b/include/media/adv7604.h
deleted file mode 100644 (file)
index a913859..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * adv7604 - Analog Devices ADV7604 video decoder driver
- *
- * Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#ifndef _ADV7604_
-#define _ADV7604_
-
-#include <linux/types.h>
-
-/* Analog input muxing modes (AFE register 0x02, [2:0]) */
-enum adv7604_ain_sel {
-       ADV7604_AIN1_2_3_NC_SYNC_1_2 = 0,
-       ADV7604_AIN4_5_6_NC_SYNC_2_1 = 1,
-       ADV7604_AIN7_8_9_NC_SYNC_3_1 = 2,
-       ADV7604_AIN10_11_12_NC_SYNC_4_1 = 3,
-       ADV7604_AIN9_4_5_6_SYNC_2_1 = 4,
-};
-
-/*
- * Bus rotation and reordering. This is used to specify component reordering on
- * the board and describes the components order on the bus when the ADV7604
- * outputs RGB.
- */
-enum adv7604_bus_order {
-       ADV7604_BUS_ORDER_RGB,          /* No operation */
-       ADV7604_BUS_ORDER_GRB,          /* Swap 1-2     */
-       ADV7604_BUS_ORDER_RBG,          /* Swap 2-3     */
-       ADV7604_BUS_ORDER_BGR,          /* Swap 1-3     */
-       ADV7604_BUS_ORDER_BRG,          /* Rotate right */
-       ADV7604_BUS_ORDER_GBR,          /* Rotate left  */
-};
-
-/* Input Color Space (IO register 0x02, [7:4]) */
-enum adv76xx_inp_color_space {
-       ADV76XX_INP_COLOR_SPACE_LIM_RGB = 0,
-       ADV76XX_INP_COLOR_SPACE_FULL_RGB = 1,
-       ADV76XX_INP_COLOR_SPACE_LIM_YCbCr_601 = 2,
-       ADV76XX_INP_COLOR_SPACE_LIM_YCbCr_709 = 3,
-       ADV76XX_INP_COLOR_SPACE_XVYCC_601 = 4,
-       ADV76XX_INP_COLOR_SPACE_XVYCC_709 = 5,
-       ADV76XX_INP_COLOR_SPACE_FULL_YCbCr_601 = 6,
-       ADV76XX_INP_COLOR_SPACE_FULL_YCbCr_709 = 7,
-       ADV76XX_INP_COLOR_SPACE_AUTO = 0xf,
-};
-
-/* Select output format (IO register 0x03, [4:2]) */
-enum adv7604_op_format_mode_sel {
-       ADV7604_OP_FORMAT_MODE0 = 0x00,
-       ADV7604_OP_FORMAT_MODE1 = 0x04,
-       ADV7604_OP_FORMAT_MODE2 = 0x08,
-};
-
-enum adv76xx_drive_strength {
-       ADV76XX_DR_STR_MEDIUM_LOW = 1,
-       ADV76XX_DR_STR_MEDIUM_HIGH = 2,
-       ADV76XX_DR_STR_HIGH = 3,
-};
-
-/* INT1 Configuration (IO register 0x40, [1:0]) */
-enum adv76xx_int1_config {
-       ADV76XX_INT1_CONFIG_OPEN_DRAIN,
-       ADV76XX_INT1_CONFIG_ACTIVE_LOW,
-       ADV76XX_INT1_CONFIG_ACTIVE_HIGH,
-       ADV76XX_INT1_CONFIG_DISABLED,
-};
-
-enum adv76xx_page {
-       ADV76XX_PAGE_IO,
-       ADV7604_PAGE_AVLINK,
-       ADV76XX_PAGE_CEC,
-       ADV76XX_PAGE_INFOFRAME,
-       ADV7604_PAGE_ESDP,
-       ADV7604_PAGE_DPP,
-       ADV76XX_PAGE_AFE,
-       ADV76XX_PAGE_REP,
-       ADV76XX_PAGE_EDID,
-       ADV76XX_PAGE_HDMI,
-       ADV76XX_PAGE_TEST,
-       ADV76XX_PAGE_CP,
-       ADV7604_PAGE_VDP,
-       ADV76XX_PAGE_MAX,
-};
-
-/* Platform dependent definition */
-struct adv76xx_platform_data {
-       /* DIS_PWRDNB: 1 if the PWRDNB pin is unused and unconnected */
-       unsigned disable_pwrdnb:1;
-
-       /* DIS_CABLE_DET_RST: 1 if the 5V pins are unused and unconnected */
-       unsigned disable_cable_det_rst:1;
-
-       int default_input;
-
-       /* Analog input muxing mode */
-       enum adv7604_ain_sel ain_sel;
-
-       /* Bus rotation and reordering */
-       enum adv7604_bus_order bus_order;
-
-       /* Select output format mode */
-       enum adv7604_op_format_mode_sel op_format_mode_sel;
-
-       /* Configuration of the INT1 pin */
-       enum adv76xx_int1_config int1_config;
-
-       /* IO register 0x02 */
-       unsigned alt_gamma:1;
-       unsigned op_656_range:1;
-       unsigned alt_data_sat:1;
-
-       /* IO register 0x05 */
-       unsigned blank_data:1;
-       unsigned insert_av_codes:1;
-       unsigned replicate_av_codes:1;
-
-       /* IO register 0x06 */
-       unsigned inv_vs_pol:1;
-       unsigned inv_hs_pol:1;
-       unsigned inv_llc_pol:1;
-
-       /* IO register 0x14 */
-       enum adv76xx_drive_strength dr_str_data;
-       enum adv76xx_drive_strength dr_str_clk;
-       enum adv76xx_drive_strength dr_str_sync;
-
-       /* IO register 0x30 */
-       unsigned output_bus_lsb_to_msb:1;
-
-       /* Free run */
-       unsigned hdmi_free_run_mode;
-
-       /* i2c addresses: 0 == use default */
-       u8 i2c_addresses[ADV76XX_PAGE_MAX];
-};
-
-enum adv76xx_pad {
-       ADV76XX_PAD_HDMI_PORT_A = 0,
-       ADV7604_PAD_HDMI_PORT_B = 1,
-       ADV7604_PAD_HDMI_PORT_C = 2,
-       ADV7604_PAD_HDMI_PORT_D = 3,
-       ADV7604_PAD_VGA_RGB = 4,
-       ADV7604_PAD_VGA_COMP = 5,
-       /* The source pad is either 1 (ADV7611) or 6 (ADV7604) */
-       ADV7604_PAD_SOURCE = 6,
-       ADV7611_PAD_SOURCE = 1,
-       ADV76XX_PAD_MAX = 7,
-};
-
-#define V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE  (V4L2_CID_DV_CLASS_BASE + 0x1000)
-#define V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL  (V4L2_CID_DV_CLASS_BASE + 0x1001)
-#define V4L2_CID_ADV_RX_FREE_RUN_COLOR         (V4L2_CID_DV_CLASS_BASE + 0x1002)
-
-/* notify events */
-#define ADV76XX_HOTPLUG                1
-
-#endif
diff --git a/include/media/adv7842.h b/include/media/adv7842.h
deleted file mode 100644 (file)
index bc24970..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * adv7842 - Analog Devices ADV7842 video decoder driver
- *
- * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#ifndef _ADV7842_
-#define _ADV7842_
-
-/* Analog input muxing modes (AFE register 0x02, [2:0]) */
-enum adv7842_ain_sel {
-       ADV7842_AIN1_2_3_NC_SYNC_1_2 = 0,
-       ADV7842_AIN4_5_6_NC_SYNC_2_1 = 1,
-       ADV7842_AIN7_8_9_NC_SYNC_3_1 = 2,
-       ADV7842_AIN10_11_12_NC_SYNC_4_1 = 3,
-       ADV7842_AIN9_4_5_6_SYNC_2_1 = 4,
-};
-
-/*
- * Bus rotation and reordering. This is used to specify component reordering on
- * the board and describes the components order on the bus when the ADV7842
- * outputs RGB.
- */
-enum adv7842_bus_order {
-       ADV7842_BUS_ORDER_RGB,          /* No operation */
-       ADV7842_BUS_ORDER_GRB,          /* Swap 1-2     */
-       ADV7842_BUS_ORDER_RBG,          /* Swap 2-3     */
-       ADV7842_BUS_ORDER_BGR,          /* Swap 1-3     */
-       ADV7842_BUS_ORDER_BRG,          /* Rotate right */
-       ADV7842_BUS_ORDER_GBR,          /* Rotate left  */
-};
-
-/* Input Color Space (IO register 0x02, [7:4]) */
-enum adv7842_inp_color_space {
-       ADV7842_INP_COLOR_SPACE_LIM_RGB = 0,
-       ADV7842_INP_COLOR_SPACE_FULL_RGB = 1,
-       ADV7842_INP_COLOR_SPACE_LIM_YCbCr_601 = 2,
-       ADV7842_INP_COLOR_SPACE_LIM_YCbCr_709 = 3,
-       ADV7842_INP_COLOR_SPACE_XVYCC_601 = 4,
-       ADV7842_INP_COLOR_SPACE_XVYCC_709 = 5,
-       ADV7842_INP_COLOR_SPACE_FULL_YCbCr_601 = 6,
-       ADV7842_INP_COLOR_SPACE_FULL_YCbCr_709 = 7,
-       ADV7842_INP_COLOR_SPACE_AUTO = 0xf,
-};
-
-/* Select output format (IO register 0x03, [4:2]) */
-enum adv7842_op_format_mode_sel {
-       ADV7842_OP_FORMAT_MODE0 = 0x00,
-       ADV7842_OP_FORMAT_MODE1 = 0x04,
-       ADV7842_OP_FORMAT_MODE2 = 0x08,
-};
-
-/* Mode of operation */
-enum adv7842_mode {
-       ADV7842_MODE_SDP,
-       ADV7842_MODE_COMP,
-       ADV7842_MODE_RGB,
-       ADV7842_MODE_HDMI
-};
-
-/* Video standard select (IO register 0x00, [5:0]) */
-enum adv7842_vid_std_select {
-       /* SDP */
-       ADV7842_SDP_VID_STD_CVBS_SD_4x1 = 0x01,
-       ADV7842_SDP_VID_STD_YC_SD4_x1 = 0x09,
-       /* RGB */
-       ADV7842_RGB_VID_STD_AUTO_GRAPH_MODE = 0x07,
-       /* HDMI GR */
-       ADV7842_HDMI_GR_VID_STD_AUTO_GRAPH_MODE = 0x02,
-       /* HDMI COMP */
-       ADV7842_HDMI_COMP_VID_STD_HD_1250P = 0x1e,
-};
-
-enum adv7842_select_input {
-       ADV7842_SELECT_HDMI_PORT_A,
-       ADV7842_SELECT_HDMI_PORT_B,
-       ADV7842_SELECT_VGA_RGB,
-       ADV7842_SELECT_VGA_COMP,
-       ADV7842_SELECT_SDP_CVBS,
-       ADV7842_SELECT_SDP_YC,
-};
-
-enum adv7842_drive_strength {
-       ADV7842_DR_STR_LOW = 0,
-       ADV7842_DR_STR_MEDIUM_LOW = 1,
-       ADV7842_DR_STR_MEDIUM_HIGH = 2,
-       ADV7842_DR_STR_HIGH = 3,
-};
-
-struct adv7842_sdp_csc_coeff {
-       bool manual;
-       u16 scaling;
-       u16 A1;
-       u16 A2;
-       u16 A3;
-       u16 A4;
-       u16 B1;
-       u16 B2;
-       u16 B3;
-       u16 B4;
-       u16 C1;
-       u16 C2;
-       u16 C3;
-       u16 C4;
-};
-
-struct adv7842_sdp_io_sync_adjustment {
-       bool adjust;
-       u16 hs_beg;
-       u16 hs_width;
-       u16 de_beg;
-       u16 de_end;
-       u8 vs_beg_o;
-       u8 vs_beg_e;
-       u8 vs_end_o;
-       u8 vs_end_e;
-       u8 de_v_beg_o;
-       u8 de_v_beg_e;
-       u8 de_v_end_o;
-       u8 de_v_end_e;
-};
-
-/* Platform dependent definition */
-struct adv7842_platform_data {
-       /* chip reset during probe */
-       unsigned chip_reset:1;
-
-       /* DIS_PWRDNB: 1 if the PWRDNB pin is unused and unconnected */
-       unsigned disable_pwrdnb:1;
-
-       /* DIS_CABLE_DET_RST: 1 if the 5V pins are unused and unconnected */
-       unsigned disable_cable_det_rst:1;
-
-       /* Analog input muxing mode */
-       enum adv7842_ain_sel ain_sel;
-
-       /* Bus rotation and reordering */
-       enum adv7842_bus_order bus_order;
-
-       /* Select output format mode */
-       enum adv7842_op_format_mode_sel op_format_mode_sel;
-
-       /* Default mode */
-       enum adv7842_mode mode;
-
-       /* Default input */
-       unsigned input;
-
-       /* Video standard */
-       enum adv7842_vid_std_select vid_std_select;
-
-       /* IO register 0x02 */
-       unsigned alt_gamma:1;
-       unsigned op_656_range:1;
-       unsigned alt_data_sat:1;
-
-       /* IO register 0x05 */
-       unsigned blank_data:1;
-       unsigned insert_av_codes:1;
-       unsigned replicate_av_codes:1;
-
-       /* IO register 0x30 */
-       unsigned output_bus_lsb_to_msb:1;
-
-       /* IO register 0x14 */
-       enum adv7842_drive_strength dr_str_data;
-       enum adv7842_drive_strength dr_str_clk;
-       enum adv7842_drive_strength dr_str_sync;
-
-       /*
-        * IO register 0x19: Adjustment to the LLC DLL phase in
-        * increments of 1/32 of a clock period.
-        */
-       unsigned llc_dll_phase:5;
-
-       /* External RAM for 3-D comb or frame synchronizer */
-       unsigned sd_ram_size; /* ram size in MB */
-       unsigned sd_ram_ddr:1; /* ddr or sdr sdram */
-
-       /* HDMI free run, CP-reg 0xBA */
-       unsigned hdmi_free_run_enable:1;
-       /* 0 = Mode 0: run when there is no TMDS clock
-          1 = Mode 1: run when there is no TMDS clock or the
-              video resolution does not match programmed one. */
-       unsigned hdmi_free_run_mode:1;
-
-       /* SDP free run, CP-reg 0xDD */
-       unsigned sdp_free_run_auto:1;
-       unsigned sdp_free_run_man_col_en:1;
-       unsigned sdp_free_run_cbar_en:1;
-       unsigned sdp_free_run_force:1;
-
-       /* HPA manual (0) or auto (1), affects HDMI register 0x69 */
-       unsigned hpa_auto:1;
-
-       struct adv7842_sdp_csc_coeff sdp_csc_coeff;
-
-       struct adv7842_sdp_io_sync_adjustment sdp_io_sync_625;
-       struct adv7842_sdp_io_sync_adjustment sdp_io_sync_525;
-
-       /* i2c addresses */
-       u8 i2c_sdp_io;
-       u8 i2c_sdp;
-       u8 i2c_cp;
-       u8 i2c_vdp;
-       u8 i2c_afe;
-       u8 i2c_hdmi;
-       u8 i2c_repeater;
-       u8 i2c_edid;
-       u8 i2c_infoframe;
-       u8 i2c_cec;
-       u8 i2c_avlink;
-};
-
-#define V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE  (V4L2_CID_DV_CLASS_BASE + 0x1000)
-#define V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL  (V4L2_CID_DV_CLASS_BASE + 0x1001)
-#define V4L2_CID_ADV_RX_FREE_RUN_COLOR         (V4L2_CID_DV_CLASS_BASE + 0x1002)
-
-/* custom ioctl, used to test the external RAM that's used by the
- * deinterlacer. */
-#define ADV7842_CMD_RAM_TEST _IO('V', BASE_VIDIOC_PRIVATE)
-
-#define ADV7842_EDID_PORT_A   0
-#define ADV7842_EDID_PORT_B   1
-#define ADV7842_EDID_PORT_VGA 2
-#define ADV7842_PAD_SOURCE    3
-
-#endif
diff --git a/include/media/ak881x.h b/include/media/ak881x.h
deleted file mode 100644 (file)
index b7f2add..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Header for AK8813 / AK8814 TV-ecoders from Asahi Kasei Microsystems Co., Ltd. (AKM)
- *
- * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.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.
- */
-
-#ifndef AK881X_H
-#define AK881X_H
-
-#define AK881X_IF_MODE_MASK    (3 << 0)
-#define AK881X_IF_MODE_BT656   (0 << 0)
-#define AK881X_IF_MODE_MASTER  (1 << 0)
-#define AK881X_IF_MODE_SLAVE   (2 << 0)
-#define AK881X_FIELD           (1 << 2)
-#define AK881X_COMPONENT       (1 << 3)
-
-struct ak881x_pdata {
-       unsigned long flags;
-};
-
-#endif
diff --git a/include/media/as3645a.h b/include/media/as3645a.h
deleted file mode 100644 (file)
index 5075496..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * include/media/as3645a.h
- *
- * Copyright (C) 2008-2011 Nokia Corporation
- *
- * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __AS3645A_H__
-#define __AS3645A_H__
-
-#include <media/v4l2-subdev.h>
-
-#define AS3645A_NAME                           "as3645a"
-#define AS3645A_I2C_ADDR                       (0x60 >> 1) /* W:0x60, R:0x61 */
-
-#define AS3645A_FLASH_TIMEOUT_MIN              100000  /* us */
-#define AS3645A_FLASH_TIMEOUT_MAX              850000
-#define AS3645A_FLASH_TIMEOUT_STEP             50000
-
-#define AS3645A_FLASH_INTENSITY_MIN            200     /* mA */
-#define AS3645A_FLASH_INTENSITY_MAX_1LED       500
-#define AS3645A_FLASH_INTENSITY_MAX_2LEDS      400
-#define AS3645A_FLASH_INTENSITY_STEP           20
-
-#define AS3645A_TORCH_INTENSITY_MIN            20      /* mA */
-#define AS3645A_TORCH_INTENSITY_MAX            160
-#define AS3645A_TORCH_INTENSITY_STEP           20
-
-#define AS3645A_INDICATOR_INTENSITY_MIN                0       /* uA */
-#define AS3645A_INDICATOR_INTENSITY_MAX                10000
-#define AS3645A_INDICATOR_INTENSITY_STEP       2500
-
-/*
- * as3645a_platform_data - Flash controller platform data
- * @set_power: Set power callback
- * @vref:      VREF offset (0=0V, 1=+0.3V, 2=-0.3V, 3=+0.6V)
- * @peak:      Inductor peak current limit (0=1.25A, 1=1.5A, 2=1.75A, 3=2.0A)
- * @ext_strobe:        True if external flash strobe can be used
- * @flash_max_current: Max flash current (mA, <= AS3645A_FLASH_INTENSITY_MAX)
- * @torch_max_current: Max torch current (mA, >= AS3645A_TORCH_INTENSITY_MAX)
- * @timeout_max:       Max flash timeout (us, <= AS3645A_FLASH_TIMEOUT_MAX)
- */
-struct as3645a_platform_data {
-       int (*set_power)(struct v4l2_subdev *subdev, int on);
-       unsigned int vref;
-       unsigned int peak;
-       bool ext_strobe;
-
-       /* Flash and torch currents and timeout limits */
-       unsigned int flash_max_current;
-       unsigned int torch_max_current;
-       unsigned int timeout_max;
-};
-
-#endif /* __AS3645A_H__ */
diff --git a/include/media/bt819.h b/include/media/bt819.h
deleted file mode 100644 (file)
index 8025f4b..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-    bt819.h - bt819 notifications
-
-    Copyright (C) 2009 Hans Verkuil (hverkuil@xs4all.nl)
-
-    This program is 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 _BT819_H_
-#define _BT819_H_
-
-#include <linux/ioctl.h>
-
-/* v4l2_device notifications. */
-
-/* Needed to reset the FIFO buffer when changing the input
-   or the video standard.
-
-   Note: these ioctls that internal to the kernel and are never called
-   from userspace. */
-#define BT819_FIFO_RESET_LOW   _IO('b', 0)
-#define BT819_FIFO_RESET_HIGH  _IO('b', 1)
-
-#endif
diff --git a/include/media/cs5345.h b/include/media/cs5345.h
deleted file mode 100644 (file)
index 6ccae24..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-    cs5345.h - definition for cs5345 inputs and outputs
-
-    Copyright (C) 2007 Hans Verkuil (hverkuil@xs4all.nl)
-
-    This program is 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 _CS5345_H_
-#define _CS5345_H_
-
-/* CS5345 HW inputs */
-#define CS5345_IN_MIC 0
-#define CS5345_IN_1   1
-#define CS5345_IN_2   2
-#define CS5345_IN_3   3
-#define CS5345_IN_4   4
-#define CS5345_IN_5   5
-#define CS5345_IN_6   6
-
-#define CS5345_MCLK_1   0x00
-#define CS5345_MCLK_1_5 0x10
-#define CS5345_MCLK_2   0x20
-#define CS5345_MCLK_3   0x30
-#define CS5345_MCLK_4   0x40
-
-#endif
diff --git a/include/media/cs53l32a.h b/include/media/cs53l32a.h
deleted file mode 100644 (file)
index bf76197..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-    cs53l32a.h - definition for cs53l32a inputs and outputs
-
-    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
-
-    This program is 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 _CS53L32A_H_
-#define _CS53L32A_H_
-
-/* There are 2 physical inputs, but the second input can be
-   placed in two modes, the first mode bypasses the PGA (gain),
-   the second goes through the PGA. Hence there are three
-   possible inputs to choose from. */
-
-/* CS53L32A HW inputs */
-#define CS53L32A_IN0 0
-#define CS53L32A_IN1 1
-#define CS53L32A_IN2 2
-
-#endif
diff --git a/include/media/cx2341x.h b/include/media/cx2341x.h
deleted file mode 100644 (file)
index 9635eeb..0000000
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
-    cx23415/6/8 header containing common defines.
-
-    This program is 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
- */
-
-#ifndef CX2341X_H
-#define CX2341X_H
-
-#include <media/v4l2-ctrls.h>
-
-enum cx2341x_port {
-       CX2341X_PORT_MEMORY    = 0,
-       CX2341X_PORT_STREAMING = 1,
-       CX2341X_PORT_SERIAL    = 2
-};
-
-enum cx2341x_cap {
-       CX2341X_CAP_HAS_SLICED_VBI = 1 << 0,
-       CX2341X_CAP_HAS_TS         = 1 << 1,
-       CX2341X_CAP_HAS_AC3        = 1 << 2,
-};
-
-struct cx2341x_mpeg_params {
-       /* misc */
-       u32 capabilities;
-       enum cx2341x_port port;
-       u16 width;
-       u16 height;
-       u16 is_50hz;
-
-       /* stream */
-       enum v4l2_mpeg_stream_type stream_type;
-       enum v4l2_mpeg_stream_vbi_fmt stream_vbi_fmt;
-       u16 stream_insert_nav_packets;
-
-       /* audio */
-       enum v4l2_mpeg_audio_sampling_freq audio_sampling_freq;
-       enum v4l2_mpeg_audio_encoding audio_encoding;
-       enum v4l2_mpeg_audio_l2_bitrate audio_l2_bitrate;
-       enum v4l2_mpeg_audio_ac3_bitrate audio_ac3_bitrate;
-       enum v4l2_mpeg_audio_mode audio_mode;
-       enum v4l2_mpeg_audio_mode_extension audio_mode_extension;
-       enum v4l2_mpeg_audio_emphasis audio_emphasis;
-       enum v4l2_mpeg_audio_crc audio_crc;
-       u32 audio_properties;
-       u16 audio_mute;
-
-       /* video */
-       enum v4l2_mpeg_video_encoding video_encoding;
-       enum v4l2_mpeg_video_aspect video_aspect;
-       u16 video_b_frames;
-       u16 video_gop_size;
-       u16 video_gop_closure;
-       enum v4l2_mpeg_video_bitrate_mode video_bitrate_mode;
-       u32 video_bitrate;
-       u32 video_bitrate_peak;
-       u16 video_temporal_decimation;
-       u16 video_mute;
-       u32 video_mute_yuv;
-
-       /* encoding filters */
-       enum v4l2_mpeg_cx2341x_video_spatial_filter_mode video_spatial_filter_mode;
-       u16 video_spatial_filter;
-       enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type video_luma_spatial_filter_type;
-       enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type video_chroma_spatial_filter_type;
-       enum v4l2_mpeg_cx2341x_video_temporal_filter_mode video_temporal_filter_mode;
-       u16 video_temporal_filter;
-       enum v4l2_mpeg_cx2341x_video_median_filter_type video_median_filter_type;
-       u16 video_luma_median_filter_top;
-       u16 video_luma_median_filter_bottom;
-       u16 video_chroma_median_filter_top;
-       u16 video_chroma_median_filter_bottom;
-};
-
-#define CX2341X_MBOX_MAX_DATA 16
-
-extern const u32 cx2341x_mpeg_ctrls[];
-typedef int (*cx2341x_mbox_func)(void *priv, u32 cmd, int in, int out,
-               u32 data[CX2341X_MBOX_MAX_DATA]);
-int cx2341x_update(void *priv, cx2341x_mbox_func func,
-               const struct cx2341x_mpeg_params *old,
-               const struct cx2341x_mpeg_params *new);
-int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
-               struct v4l2_queryctrl *qctrl);
-const char * const *cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id);
-int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
-               struct v4l2_ext_controls *ctrls, unsigned int cmd);
-void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p);
-void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix);
-
-struct cx2341x_handler;
-
-struct cx2341x_handler_ops {
-       /* needed for the video clock freq */
-       int (*s_audio_sampling_freq)(struct cx2341x_handler *hdl, u32 val);
-       /* needed for dualwatch */
-       int (*s_audio_mode)(struct cx2341x_handler *hdl, u32 val);
-       /* needed for setting up the video resolution */
-       int (*s_video_encoding)(struct cx2341x_handler *hdl, u32 val);
-       /* needed for setting up the sliced vbi insertion data structures */
-       int (*s_stream_vbi_fmt)(struct cx2341x_handler *hdl, u32 val);
-};
-
-struct cx2341x_handler {
-       u32 capabilities;
-       enum cx2341x_port port;
-       u16 width;
-       u16 height;
-       u16 is_50hz;
-       u32 audio_properties;
-
-       struct v4l2_ctrl_handler hdl;
-       void *priv;
-       cx2341x_mbox_func func;
-       const struct cx2341x_handler_ops *ops;
-
-       struct v4l2_ctrl *stream_vbi_fmt;
-
-       struct {
-               /* audio cluster */
-               struct v4l2_ctrl *audio_sampling_freq;
-               struct v4l2_ctrl *audio_encoding;
-               struct v4l2_ctrl *audio_l2_bitrate;
-               struct v4l2_ctrl *audio_mode;
-               struct v4l2_ctrl *audio_mode_extension;
-               struct v4l2_ctrl *audio_emphasis;
-               struct v4l2_ctrl *audio_crc;
-               struct v4l2_ctrl *audio_ac3_bitrate;
-       };
-
-       struct {
-               /* video gop cluster */
-               struct v4l2_ctrl *video_b_frames;
-               struct v4l2_ctrl *video_gop_size;
-       };
-
-       struct {
-               /* stream type cluster */
-               struct v4l2_ctrl *stream_type;
-               struct v4l2_ctrl *video_encoding;
-               struct v4l2_ctrl *video_bitrate_mode;
-               struct v4l2_ctrl *video_bitrate;
-               struct v4l2_ctrl *video_bitrate_peak;
-       };
-
-       struct {
-               /* video mute cluster */
-               struct v4l2_ctrl *video_mute;
-               struct v4l2_ctrl *video_mute_yuv;
-       };
-
-       struct {
-               /* video filter mode cluster */
-               struct v4l2_ctrl *video_spatial_filter_mode;
-               struct v4l2_ctrl *video_temporal_filter_mode;
-               struct v4l2_ctrl *video_median_filter_type;
-       };
-
-       struct {
-               /* video filter type cluster */
-               struct v4l2_ctrl *video_luma_spatial_filter_type;
-               struct v4l2_ctrl *video_chroma_spatial_filter_type;
-       };
-
-       struct  {
-               /* video filter cluster */
-               struct v4l2_ctrl *video_spatial_filter;
-               struct v4l2_ctrl *video_temporal_filter;
-       };
-
-       struct {
-               /* video median cluster */
-               struct v4l2_ctrl *video_luma_median_filter_top;
-               struct v4l2_ctrl *video_luma_median_filter_bottom;
-               struct v4l2_ctrl *video_chroma_median_filter_top;
-               struct v4l2_ctrl *video_chroma_median_filter_bottom;
-       };
-};
-
-int cx2341x_handler_init(struct cx2341x_handler *cxhdl,
-                        unsigned nr_of_controls_hint);
-void cx2341x_handler_set_50hz(struct cx2341x_handler *cxhdl, int is_50hz);
-int cx2341x_handler_setup(struct cx2341x_handler *cxhdl);
-void cx2341x_handler_set_busy(struct cx2341x_handler *cxhdl, int busy);
-
-/* Firmware names */
-#define CX2341X_FIRM_ENC_FILENAME "v4l-cx2341x-enc.fw"
-/* Decoder firmware for the cx23415 only */
-#define CX2341X_FIRM_DEC_FILENAME "v4l-cx2341x-dec.fw"
-
-/* Firmware API commands */
-
-/* MPEG decoder API, specific to the cx23415 */
-#define CX2341X_DEC_PING_FW                    0x00
-#define CX2341X_DEC_START_PLAYBACK             0x01
-#define CX2341X_DEC_STOP_PLAYBACK              0x02
-#define CX2341X_DEC_SET_PLAYBACK_SPEED                 0x03
-#define CX2341X_DEC_STEP_VIDEO                         0x05
-#define CX2341X_DEC_SET_DMA_BLOCK_SIZE                 0x08
-#define CX2341X_DEC_GET_XFER_INFO              0x09
-#define CX2341X_DEC_GET_DMA_STATUS             0x0a
-#define CX2341X_DEC_SCHED_DMA_FROM_HOST                0x0b
-#define CX2341X_DEC_PAUSE_PLAYBACK             0x0d
-#define CX2341X_DEC_HALT_FW                    0x0e
-#define CX2341X_DEC_SET_STANDARD               0x10
-#define CX2341X_DEC_GET_VERSION                        0x11
-#define CX2341X_DEC_SET_STREAM_INPUT           0x14
-#define CX2341X_DEC_GET_TIMING_INFO            0x15
-#define CX2341X_DEC_SET_AUDIO_MODE             0x16
-#define CX2341X_DEC_SET_EVENT_NOTIFICATION     0x17
-#define CX2341X_DEC_SET_DISPLAY_BUFFERS                0x18
-#define CX2341X_DEC_EXTRACT_VBI                0x19
-#define CX2341X_DEC_SET_DECODER_SOURCE                 0x1a
-#define CX2341X_DEC_SET_PREBUFFERING           0x1e
-
-/* MPEG encoder API */
-#define CX2341X_ENC_PING_FW                    0x80
-#define CX2341X_ENC_START_CAPTURE              0x81
-#define CX2341X_ENC_STOP_CAPTURE               0x82
-#define CX2341X_ENC_SET_AUDIO_ID               0x89
-#define CX2341X_ENC_SET_VIDEO_ID               0x8b
-#define CX2341X_ENC_SET_PCR_ID                         0x8d
-#define CX2341X_ENC_SET_FRAME_RATE             0x8f
-#define CX2341X_ENC_SET_FRAME_SIZE             0x91
-#define CX2341X_ENC_SET_BIT_RATE               0x95
-#define CX2341X_ENC_SET_GOP_PROPERTIES                 0x97
-#define CX2341X_ENC_SET_ASPECT_RATIO           0x99
-#define CX2341X_ENC_SET_DNR_FILTER_MODE        0x9b
-#define CX2341X_ENC_SET_DNR_FILTER_PROPS       0x9d
-#define CX2341X_ENC_SET_CORING_LEVELS          0x9f
-#define CX2341X_ENC_SET_SPATIAL_FILTER_TYPE    0xa1
-#define CX2341X_ENC_SET_VBI_LINE               0xb7
-#define CX2341X_ENC_SET_STREAM_TYPE            0xb9
-#define CX2341X_ENC_SET_OUTPUT_PORT            0xbb
-#define CX2341X_ENC_SET_AUDIO_PROPERTIES       0xbd
-#define CX2341X_ENC_HALT_FW                    0xc3
-#define CX2341X_ENC_GET_VERSION                        0xc4
-#define CX2341X_ENC_SET_GOP_CLOSURE            0xc5
-#define CX2341X_ENC_GET_SEQ_END                0xc6
-#define CX2341X_ENC_SET_PGM_INDEX_INFO                 0xc7
-#define CX2341X_ENC_SET_VBI_CONFIG             0xc8
-#define CX2341X_ENC_SET_DMA_BLOCK_SIZE                 0xc9
-#define CX2341X_ENC_GET_PREV_DMA_INFO_MB_10    0xca
-#define CX2341X_ENC_GET_PREV_DMA_INFO_MB_9     0xcb
-#define CX2341X_ENC_SCHED_DMA_TO_HOST          0xcc
-#define CX2341X_ENC_INITIALIZE_INPUT           0xcd
-#define CX2341X_ENC_SET_FRAME_DROP_RATE        0xd0
-#define CX2341X_ENC_PAUSE_ENCODER              0xd2
-#define CX2341X_ENC_REFRESH_INPUT              0xd3
-#define CX2341X_ENC_SET_COPYRIGHT              0xd4
-#define CX2341X_ENC_SET_EVENT_NOTIFICATION     0xd5
-#define CX2341X_ENC_SET_NUM_VSYNC_LINES        0xd6
-#define CX2341X_ENC_SET_PLACEHOLDER            0xd7
-#define CX2341X_ENC_MUTE_VIDEO                         0xd9
-#define CX2341X_ENC_MUTE_AUDIO                         0xda
-#define CX2341X_ENC_SET_VERT_CROP_LINE         0xdb
-#define CX2341X_ENC_MISC                       0xdc
-
-/* OSD API, specific to the cx23415 */
-#define CX2341X_OSD_GET_FRAMEBUFFER            0x41
-#define CX2341X_OSD_GET_PIXEL_FORMAT           0x42
-#define CX2341X_OSD_SET_PIXEL_FORMAT           0x43
-#define CX2341X_OSD_GET_STATE                  0x44
-#define CX2341X_OSD_SET_STATE                  0x45
-#define CX2341X_OSD_GET_OSD_COORDS             0x46
-#define CX2341X_OSD_SET_OSD_COORDS             0x47
-#define CX2341X_OSD_GET_SCREEN_COORDS          0x48
-#define CX2341X_OSD_SET_SCREEN_COORDS          0x49
-#define CX2341X_OSD_GET_GLOBAL_ALPHA           0x4a
-#define CX2341X_OSD_SET_GLOBAL_ALPHA           0x4b
-#define CX2341X_OSD_SET_BLEND_COORDS           0x4c
-#define CX2341X_OSD_GET_FLICKER_STATE          0x4f
-#define CX2341X_OSD_SET_FLICKER_STATE          0x50
-#define CX2341X_OSD_BLT_COPY                   0x52
-#define CX2341X_OSD_BLT_FILL                   0x53
-#define CX2341X_OSD_BLT_TEXT                   0x54
-#define CX2341X_OSD_SET_FRAMEBUFFER_WINDOW     0x56
-#define CX2341X_OSD_SET_CHROMA_KEY             0x60
-#define CX2341X_OSD_GET_ALPHA_CONTENT_INDEX    0x61
-#define CX2341X_OSD_SET_ALPHA_CONTENT_INDEX    0x62
-
-#endif /* CX2341X_H */
diff --git a/include/media/cx25840.h b/include/media/cx25840.h
deleted file mode 100644 (file)
index 783c5bd..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
-    cx25840.h - definition for cx25840/1/2/3 inputs
-
-    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
-
-    This program is 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 _CX25840_H_
-#define _CX25840_H_
-
-/* Note that the cx25840 driver requires that the bridge driver calls the
-   v4l2_subdev's init operation in order to load the driver's firmware.
-   Without this the audio standard detection will fail and you will
-   only get mono.
-
-   Since loading the firmware is often problematic when the driver is
-   compiled into the kernel I recommend postponing calling this function
-   until the first open of the video device. Another reason for
-   postponing it is that loading this firmware takes a long time (seconds)
-   due to the slow i2c bus speed. So it will speed up the boot process if
-   you can avoid loading the fw as long as the video device isn't used. */
-
-enum cx25840_video_input {
-       /* Composite video inputs In1-In8 */
-       CX25840_COMPOSITE1 = 1,
-       CX25840_COMPOSITE2,
-       CX25840_COMPOSITE3,
-       CX25840_COMPOSITE4,
-       CX25840_COMPOSITE5,
-       CX25840_COMPOSITE6,
-       CX25840_COMPOSITE7,
-       CX25840_COMPOSITE8,
-
-       /* S-Video inputs consist of one luma input (In1-In8) ORed with one
-          chroma input (In5-In8) */
-       CX25840_SVIDEO_LUMA1 = 0x10,
-       CX25840_SVIDEO_LUMA2 = 0x20,
-       CX25840_SVIDEO_LUMA3 = 0x30,
-       CX25840_SVIDEO_LUMA4 = 0x40,
-       CX25840_SVIDEO_LUMA5 = 0x50,
-       CX25840_SVIDEO_LUMA6 = 0x60,
-       CX25840_SVIDEO_LUMA7 = 0x70,
-       CX25840_SVIDEO_LUMA8 = 0x80,
-       CX25840_SVIDEO_CHROMA4 = 0x400,
-       CX25840_SVIDEO_CHROMA5 = 0x500,
-       CX25840_SVIDEO_CHROMA6 = 0x600,
-       CX25840_SVIDEO_CHROMA7 = 0x700,
-       CX25840_SVIDEO_CHROMA8 = 0x800,
-
-       /* S-Video aliases for common luma/chroma combinations */
-       CX25840_SVIDEO1 = 0x510,
-       CX25840_SVIDEO2 = 0x620,
-       CX25840_SVIDEO3 = 0x730,
-       CX25840_SVIDEO4 = 0x840,
-
-       /* Allow frames to specify specific input configurations */
-       CX25840_VIN1_CH1  = 0x80000000,
-       CX25840_VIN2_CH1  = 0x80000001,
-       CX25840_VIN3_CH1  = 0x80000002,
-       CX25840_VIN4_CH1  = 0x80000003,
-       CX25840_VIN5_CH1  = 0x80000004,
-       CX25840_VIN6_CH1  = 0x80000005,
-       CX25840_VIN7_CH1  = 0x80000006,
-       CX25840_VIN8_CH1  = 0x80000007,
-       CX25840_VIN4_CH2  = 0x80000000,
-       CX25840_VIN5_CH2  = 0x80000010,
-       CX25840_VIN6_CH2  = 0x80000020,
-       CX25840_NONE_CH2  = 0x80000030,
-       CX25840_VIN7_CH3  = 0x80000000,
-       CX25840_VIN8_CH3  = 0x80000040,
-       CX25840_NONE0_CH3 = 0x80000080,
-       CX25840_NONE1_CH3 = 0x800000c0,
-       CX25840_SVIDEO_ON = 0x80000100,
-       CX25840_COMPONENT_ON = 0x80000200,
-       CX25840_DIF_ON = 0x80000400,
-};
-
-enum cx25840_audio_input {
-       /* Audio inputs: serial or In4-In8 */
-       CX25840_AUDIO_SERIAL,
-       CX25840_AUDIO4 = 4,
-       CX25840_AUDIO5,
-       CX25840_AUDIO6,
-       CX25840_AUDIO7,
-       CX25840_AUDIO8,
-};
-
-enum cx25840_io_pin {
-       CX25840_PIN_DVALID_PRGM0 = 0,
-       CX25840_PIN_FIELD_PRGM1,
-       CX25840_PIN_HRESET_PRGM2,
-       CX25840_PIN_VRESET_HCTL_PRGM3,
-       CX25840_PIN_IRQ_N_PRGM4,
-       CX25840_PIN_IR_TX_PRGM6,
-       CX25840_PIN_IR_RX_PRGM5,
-       CX25840_PIN_GPIO0_PRGM8,
-       CX25840_PIN_GPIO1_PRGM9,
-       CX25840_PIN_SA_SDIN,            /* Alternate GP Input only */
-       CX25840_PIN_SA_SDOUT,           /* Alternate GP Input only */
-       CX25840_PIN_PLL_CLK_PRGM7,
-       CX25840_PIN_CHIP_SEL_VIPCLK,    /* Output only */
-};
-
-enum cx25840_io_pad {
-       /* Output pads */
-       CX25840_PAD_DEFAULT = 0,
-       CX25840_PAD_ACTIVE,
-       CX25840_PAD_VACTIVE,
-       CX25840_PAD_CBFLAG,
-       CX25840_PAD_VID_DATA_EXT0,
-       CX25840_PAD_VID_DATA_EXT1,
-       CX25840_PAD_GPO0,
-       CX25840_PAD_GPO1,
-       CX25840_PAD_GPO2,
-       CX25840_PAD_GPO3,
-       CX25840_PAD_IRQ_N,
-       CX25840_PAD_AC_SYNC,
-       CX25840_PAD_AC_SDOUT,
-       CX25840_PAD_PLL_CLK,
-       CX25840_PAD_VRESET,
-       CX25840_PAD_RESERVED,
-       /* Pads for PLL_CLK output only */
-       CX25840_PAD_XTI_X5_DLL,
-       CX25840_PAD_AUX_PLL,
-       CX25840_PAD_VID_PLL,
-       CX25840_PAD_XTI,
-       /* Input Pads */
-       CX25840_PAD_GPI0,
-       CX25840_PAD_GPI1,
-       CX25840_PAD_GPI2,
-       CX25840_PAD_GPI3,
-};
-
-enum cx25840_io_pin_strength {
-       CX25840_PIN_DRIVE_MEDIUM = 0,
-       CX25840_PIN_DRIVE_SLOW,
-       CX25840_PIN_DRIVE_FAST,
-};
-
-enum cx23885_io_pin {
-       CX23885_PIN_IR_RX_GPIO19,
-       CX23885_PIN_IR_TX_GPIO20,
-       CX23885_PIN_I2S_SDAT_GPIO21,
-       CX23885_PIN_I2S_WCLK_GPIO22,
-       CX23885_PIN_I2S_BCLK_GPIO23,
-       CX23885_PIN_IRQ_N_GPIO16,
-};
-
-enum cx23885_io_pad {
-       CX23885_PAD_IR_RX,
-       CX23885_PAD_GPIO19,
-       CX23885_PAD_IR_TX,
-       CX23885_PAD_GPIO20,
-       CX23885_PAD_I2S_SDAT,
-       CX23885_PAD_GPIO21,
-       CX23885_PAD_I2S_WCLK,
-       CX23885_PAD_GPIO22,
-       CX23885_PAD_I2S_BCLK,
-       CX23885_PAD_GPIO23,
-       CX23885_PAD_IRQ_N,
-       CX23885_PAD_GPIO16,
-};
-
-/* pvr150_workaround activates a workaround for a hardware bug that is
-   present in Hauppauge PVR-150 (and possibly PVR-500) cards that have
-   certain NTSC tuners (tveeprom tuner model numbers 85, 99 and 112). The
-   audio autodetect fails on some channels for these models and the workaround
-   is to select the audio standard explicitly. Many thanks to Hauppauge for
-   providing this information.
-   This platform data only needs to be supplied by the ivtv driver. */
-struct cx25840_platform_data {
-       int pvr150_workaround;
-};
-
-#endif
diff --git a/include/media/drv-intf/cx2341x.h b/include/media/drv-intf/cx2341x.h
new file mode 100644 (file)
index 0000000..9635eeb
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+    cx23415/6/8 header containing common defines.
+
+    This program is 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
+ */
+
+#ifndef CX2341X_H
+#define CX2341X_H
+
+#include <media/v4l2-ctrls.h>
+
+enum cx2341x_port {
+       CX2341X_PORT_MEMORY    = 0,
+       CX2341X_PORT_STREAMING = 1,
+       CX2341X_PORT_SERIAL    = 2
+};
+
+enum cx2341x_cap {
+       CX2341X_CAP_HAS_SLICED_VBI = 1 << 0,
+       CX2341X_CAP_HAS_TS         = 1 << 1,
+       CX2341X_CAP_HAS_AC3        = 1 << 2,
+};
+
+struct cx2341x_mpeg_params {
+       /* misc */
+       u32 capabilities;
+       enum cx2341x_port port;
+       u16 width;
+       u16 height;
+       u16 is_50hz;
+
+       /* stream */
+       enum v4l2_mpeg_stream_type stream_type;
+       enum v4l2_mpeg_stream_vbi_fmt stream_vbi_fmt;
+       u16 stream_insert_nav_packets;
+
+       /* audio */
+       enum v4l2_mpeg_audio_sampling_freq audio_sampling_freq;
+       enum v4l2_mpeg_audio_encoding audio_encoding;
+       enum v4l2_mpeg_audio_l2_bitrate audio_l2_bitrate;
+       enum v4l2_mpeg_audio_ac3_bitrate audio_ac3_bitrate;
+       enum v4l2_mpeg_audio_mode audio_mode;
+       enum v4l2_mpeg_audio_mode_extension audio_mode_extension;
+       enum v4l2_mpeg_audio_emphasis audio_emphasis;
+       enum v4l2_mpeg_audio_crc audio_crc;
+       u32 audio_properties;
+       u16 audio_mute;
+
+       /* video */
+       enum v4l2_mpeg_video_encoding video_encoding;
+       enum v4l2_mpeg_video_aspect video_aspect;
+       u16 video_b_frames;
+       u16 video_gop_size;
+       u16 video_gop_closure;
+       enum v4l2_mpeg_video_bitrate_mode video_bitrate_mode;
+       u32 video_bitrate;
+       u32 video_bitrate_peak;
+       u16 video_temporal_decimation;
+       u16 video_mute;
+       u32 video_mute_yuv;
+
+       /* encoding filters */
+       enum v4l2_mpeg_cx2341x_video_spatial_filter_mode video_spatial_filter_mode;
+       u16 video_spatial_filter;
+       enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type video_luma_spatial_filter_type;
+       enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type video_chroma_spatial_filter_type;
+       enum v4l2_mpeg_cx2341x_video_temporal_filter_mode video_temporal_filter_mode;
+       u16 video_temporal_filter;
+       enum v4l2_mpeg_cx2341x_video_median_filter_type video_median_filter_type;
+       u16 video_luma_median_filter_top;
+       u16 video_luma_median_filter_bottom;
+       u16 video_chroma_median_filter_top;
+       u16 video_chroma_median_filter_bottom;
+};
+
+#define CX2341X_MBOX_MAX_DATA 16
+
+extern const u32 cx2341x_mpeg_ctrls[];
+typedef int (*cx2341x_mbox_func)(void *priv, u32 cmd, int in, int out,
+               u32 data[CX2341X_MBOX_MAX_DATA]);
+int cx2341x_update(void *priv, cx2341x_mbox_func func,
+               const struct cx2341x_mpeg_params *old,
+               const struct cx2341x_mpeg_params *new);
+int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
+               struct v4l2_queryctrl *qctrl);
+const char * const *cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id);
+int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
+               struct v4l2_ext_controls *ctrls, unsigned int cmd);
+void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p);
+void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix);
+
+struct cx2341x_handler;
+
+struct cx2341x_handler_ops {
+       /* needed for the video clock freq */
+       int (*s_audio_sampling_freq)(struct cx2341x_handler *hdl, u32 val);
+       /* needed for dualwatch */
+       int (*s_audio_mode)(struct cx2341x_handler *hdl, u32 val);
+       /* needed for setting up the video resolution */
+       int (*s_video_encoding)(struct cx2341x_handler *hdl, u32 val);
+       /* needed for setting up the sliced vbi insertion data structures */
+       int (*s_stream_vbi_fmt)(struct cx2341x_handler *hdl, u32 val);
+};
+
+struct cx2341x_handler {
+       u32 capabilities;
+       enum cx2341x_port port;
+       u16 width;
+       u16 height;
+       u16 is_50hz;
+       u32 audio_properties;
+
+       struct v4l2_ctrl_handler hdl;
+       void *priv;
+       cx2341x_mbox_func func;
+       const struct cx2341x_handler_ops *ops;
+
+       struct v4l2_ctrl *stream_vbi_fmt;
+
+       struct {
+               /* audio cluster */
+               struct v4l2_ctrl *audio_sampling_freq;
+               struct v4l2_ctrl *audio_encoding;
+               struct v4l2_ctrl *audio_l2_bitrate;
+               struct v4l2_ctrl *audio_mode;
+               struct v4l2_ctrl *audio_mode_extension;
+               struct v4l2_ctrl *audio_emphasis;
+               struct v4l2_ctrl *audio_crc;
+               struct v4l2_ctrl *audio_ac3_bitrate;
+       };
+
+       struct {
+               /* video gop cluster */
+               struct v4l2_ctrl *video_b_frames;
+               struct v4l2_ctrl *video_gop_size;
+       };
+
+       struct {
+               /* stream type cluster */
+               struct v4l2_ctrl *stream_type;
+               struct v4l2_ctrl *video_encoding;
+               struct v4l2_ctrl *video_bitrate_mode;
+               struct v4l2_ctrl *video_bitrate;
+               struct v4l2_ctrl *video_bitrate_peak;
+       };
+
+       struct {
+               /* video mute cluster */
+               struct v4l2_ctrl *video_mute;
+               struct v4l2_ctrl *video_mute_yuv;
+       };
+
+       struct {
+               /* video filter mode cluster */
+               struct v4l2_ctrl *video_spatial_filter_mode;
+               struct v4l2_ctrl *video_temporal_filter_mode;
+               struct v4l2_ctrl *video_median_filter_type;
+       };
+
+       struct {
+               /* video filter type cluster */
+               struct v4l2_ctrl *video_luma_spatial_filter_type;
+               struct v4l2_ctrl *video_chroma_spatial_filter_type;
+       };
+
+       struct  {
+               /* video filter cluster */
+               struct v4l2_ctrl *video_spatial_filter;
+               struct v4l2_ctrl *video_temporal_filter;
+       };
+
+       struct {
+               /* video median cluster */
+               struct v4l2_ctrl *video_luma_median_filter_top;
+               struct v4l2_ctrl *video_luma_median_filter_bottom;
+               struct v4l2_ctrl *video_chroma_median_filter_top;
+               struct v4l2_ctrl *video_chroma_median_filter_bottom;
+       };
+};
+
+int cx2341x_handler_init(struct cx2341x_handler *cxhdl,
+                        unsigned nr_of_controls_hint);
+void cx2341x_handler_set_50hz(struct cx2341x_handler *cxhdl, int is_50hz);
+int cx2341x_handler_setup(struct cx2341x_handler *cxhdl);
+void cx2341x_handler_set_busy(struct cx2341x_handler *cxhdl, int busy);
+
+/* Firmware names */
+#define CX2341X_FIRM_ENC_FILENAME "v4l-cx2341x-enc.fw"
+/* Decoder firmware for the cx23415 only */
+#define CX2341X_FIRM_DEC_FILENAME "v4l-cx2341x-dec.fw"
+
+/* Firmware API commands */
+
+/* MPEG decoder API, specific to the cx23415 */
+#define CX2341X_DEC_PING_FW                    0x00
+#define CX2341X_DEC_START_PLAYBACK             0x01
+#define CX2341X_DEC_STOP_PLAYBACK              0x02
+#define CX2341X_DEC_SET_PLAYBACK_SPEED                 0x03
+#define CX2341X_DEC_STEP_VIDEO                         0x05
+#define CX2341X_DEC_SET_DMA_BLOCK_SIZE                 0x08
+#define CX2341X_DEC_GET_XFER_INFO              0x09
+#define CX2341X_DEC_GET_DMA_STATUS             0x0a
+#define CX2341X_DEC_SCHED_DMA_FROM_HOST                0x0b
+#define CX2341X_DEC_PAUSE_PLAYBACK             0x0d
+#define CX2341X_DEC_HALT_FW                    0x0e
+#define CX2341X_DEC_SET_STANDARD               0x10
+#define CX2341X_DEC_GET_VERSION                        0x11
+#define CX2341X_DEC_SET_STREAM_INPUT           0x14
+#define CX2341X_DEC_GET_TIMING_INFO            0x15
+#define CX2341X_DEC_SET_AUDIO_MODE             0x16
+#define CX2341X_DEC_SET_EVENT_NOTIFICATION     0x17
+#define CX2341X_DEC_SET_DISPLAY_BUFFERS                0x18
+#define CX2341X_DEC_EXTRACT_VBI                0x19
+#define CX2341X_DEC_SET_DECODER_SOURCE                 0x1a
+#define CX2341X_DEC_SET_PREBUFFERING           0x1e
+
+/* MPEG encoder API */
+#define CX2341X_ENC_PING_FW                    0x80
+#define CX2341X_ENC_START_CAPTURE              0x81
+#define CX2341X_ENC_STOP_CAPTURE               0x82
+#define CX2341X_ENC_SET_AUDIO_ID               0x89
+#define CX2341X_ENC_SET_VIDEO_ID               0x8b
+#define CX2341X_ENC_SET_PCR_ID                         0x8d
+#define CX2341X_ENC_SET_FRAME_RATE             0x8f
+#define CX2341X_ENC_SET_FRAME_SIZE             0x91
+#define CX2341X_ENC_SET_BIT_RATE               0x95
+#define CX2341X_ENC_SET_GOP_PROPERTIES                 0x97
+#define CX2341X_ENC_SET_ASPECT_RATIO           0x99
+#define CX2341X_ENC_SET_DNR_FILTER_MODE        0x9b
+#define CX2341X_ENC_SET_DNR_FILTER_PROPS       0x9d
+#define CX2341X_ENC_SET_CORING_LEVELS          0x9f
+#define CX2341X_ENC_SET_SPATIAL_FILTER_TYPE    0xa1
+#define CX2341X_ENC_SET_VBI_LINE               0xb7
+#define CX2341X_ENC_SET_STREAM_TYPE            0xb9
+#define CX2341X_ENC_SET_OUTPUT_PORT            0xbb
+#define CX2341X_ENC_SET_AUDIO_PROPERTIES       0xbd
+#define CX2341X_ENC_HALT_FW                    0xc3
+#define CX2341X_ENC_GET_VERSION                        0xc4
+#define CX2341X_ENC_SET_GOP_CLOSURE            0xc5
+#define CX2341X_ENC_GET_SEQ_END                0xc6
+#define CX2341X_ENC_SET_PGM_INDEX_INFO                 0xc7
+#define CX2341X_ENC_SET_VBI_CONFIG             0xc8
+#define CX2341X_ENC_SET_DMA_BLOCK_SIZE                 0xc9
+#define CX2341X_ENC_GET_PREV_DMA_INFO_MB_10    0xca
+#define CX2341X_ENC_GET_PREV_DMA_INFO_MB_9     0xcb
+#define CX2341X_ENC_SCHED_DMA_TO_HOST          0xcc
+#define CX2341X_ENC_INITIALIZE_INPUT           0xcd
+#define CX2341X_ENC_SET_FRAME_DROP_RATE        0xd0
+#define CX2341X_ENC_PAUSE_ENCODER              0xd2
+#define CX2341X_ENC_REFRESH_INPUT              0xd3
+#define CX2341X_ENC_SET_COPYRIGHT              0xd4
+#define CX2341X_ENC_SET_EVENT_NOTIFICATION     0xd5
+#define CX2341X_ENC_SET_NUM_VSYNC_LINES        0xd6
+#define CX2341X_ENC_SET_PLACEHOLDER            0xd7
+#define CX2341X_ENC_MUTE_VIDEO                         0xd9
+#define CX2341X_ENC_MUTE_AUDIO                         0xda
+#define CX2341X_ENC_SET_VERT_CROP_LINE         0xdb
+#define CX2341X_ENC_MISC                       0xdc
+
+/* OSD API, specific to the cx23415 */
+#define CX2341X_OSD_GET_FRAMEBUFFER            0x41
+#define CX2341X_OSD_GET_PIXEL_FORMAT           0x42
+#define CX2341X_OSD_SET_PIXEL_FORMAT           0x43
+#define CX2341X_OSD_GET_STATE                  0x44
+#define CX2341X_OSD_SET_STATE                  0x45
+#define CX2341X_OSD_GET_OSD_COORDS             0x46
+#define CX2341X_OSD_SET_OSD_COORDS             0x47
+#define CX2341X_OSD_GET_SCREEN_COORDS          0x48
+#define CX2341X_OSD_SET_SCREEN_COORDS          0x49
+#define CX2341X_OSD_GET_GLOBAL_ALPHA           0x4a
+#define CX2341X_OSD_SET_GLOBAL_ALPHA           0x4b
+#define CX2341X_OSD_SET_BLEND_COORDS           0x4c
+#define CX2341X_OSD_GET_FLICKER_STATE          0x4f
+#define CX2341X_OSD_SET_FLICKER_STATE          0x50
+#define CX2341X_OSD_BLT_COPY                   0x52
+#define CX2341X_OSD_BLT_FILL                   0x53
+#define CX2341X_OSD_BLT_TEXT                   0x54
+#define CX2341X_OSD_SET_FRAMEBUFFER_WINDOW     0x56
+#define CX2341X_OSD_SET_CHROMA_KEY             0x60
+#define CX2341X_OSD_GET_ALPHA_CONTENT_INDEX    0x61
+#define CX2341X_OSD_SET_ALPHA_CONTENT_INDEX    0x62
+
+#endif /* CX2341X_H */
diff --git a/include/media/drv-intf/cx25840.h b/include/media/drv-intf/cx25840.h
new file mode 100644 (file)
index 0000000..783c5bd
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+    cx25840.h - definition for cx25840/1/2/3 inputs
+
+    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
+
+    This program is 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 _CX25840_H_
+#define _CX25840_H_
+
+/* Note that the cx25840 driver requires that the bridge driver calls the
+   v4l2_subdev's init operation in order to load the driver's firmware.
+   Without this the audio standard detection will fail and you will
+   only get mono.
+
+   Since loading the firmware is often problematic when the driver is
+   compiled into the kernel I recommend postponing calling this function
+   until the first open of the video device. Another reason for
+   postponing it is that loading this firmware takes a long time (seconds)
+   due to the slow i2c bus speed. So it will speed up the boot process if
+   you can avoid loading the fw as long as the video device isn't used. */
+
+enum cx25840_video_input {
+       /* Composite video inputs In1-In8 */
+       CX25840_COMPOSITE1 = 1,
+       CX25840_COMPOSITE2,
+       CX25840_COMPOSITE3,
+       CX25840_COMPOSITE4,
+       CX25840_COMPOSITE5,
+       CX25840_COMPOSITE6,
+       CX25840_COMPOSITE7,
+       CX25840_COMPOSITE8,
+
+       /* S-Video inputs consist of one luma input (In1-In8) ORed with one
+          chroma input (In5-In8) */
+       CX25840_SVIDEO_LUMA1 = 0x10,
+       CX25840_SVIDEO_LUMA2 = 0x20,
+       CX25840_SVIDEO_LUMA3 = 0x30,
+       CX25840_SVIDEO_LUMA4 = 0x40,
+       CX25840_SVIDEO_LUMA5 = 0x50,
+       CX25840_SVIDEO_LUMA6 = 0x60,
+       CX25840_SVIDEO_LUMA7 = 0x70,
+       CX25840_SVIDEO_LUMA8 = 0x80,
+       CX25840_SVIDEO_CHROMA4 = 0x400,
+       CX25840_SVIDEO_CHROMA5 = 0x500,
+       CX25840_SVIDEO_CHROMA6 = 0x600,
+       CX25840_SVIDEO_CHROMA7 = 0x700,
+       CX25840_SVIDEO_CHROMA8 = 0x800,
+
+       /* S-Video aliases for common luma/chroma combinations */
+       CX25840_SVIDEO1 = 0x510,
+       CX25840_SVIDEO2 = 0x620,
+       CX25840_SVIDEO3 = 0x730,
+       CX25840_SVIDEO4 = 0x840,
+
+       /* Allow frames to specify specific input configurations */
+       CX25840_VIN1_CH1  = 0x80000000,
+       CX25840_VIN2_CH1  = 0x80000001,
+       CX25840_VIN3_CH1  = 0x80000002,
+       CX25840_VIN4_CH1  = 0x80000003,
+       CX25840_VIN5_CH1  = 0x80000004,
+       CX25840_VIN6_CH1  = 0x80000005,
+       CX25840_VIN7_CH1  = 0x80000006,
+       CX25840_VIN8_CH1  = 0x80000007,
+       CX25840_VIN4_CH2  = 0x80000000,
+       CX25840_VIN5_CH2  = 0x80000010,
+       CX25840_VIN6_CH2  = 0x80000020,
+       CX25840_NONE_CH2  = 0x80000030,
+       CX25840_VIN7_CH3  = 0x80000000,
+       CX25840_VIN8_CH3  = 0x80000040,
+       CX25840_NONE0_CH3 = 0x80000080,
+       CX25840_NONE1_CH3 = 0x800000c0,
+       CX25840_SVIDEO_ON = 0x80000100,
+       CX25840_COMPONENT_ON = 0x80000200,
+       CX25840_DIF_ON = 0x80000400,
+};
+
+enum cx25840_audio_input {
+       /* Audio inputs: serial or In4-In8 */
+       CX25840_AUDIO_SERIAL,
+       CX25840_AUDIO4 = 4,
+       CX25840_AUDIO5,
+       CX25840_AUDIO6,
+       CX25840_AUDIO7,
+       CX25840_AUDIO8,
+};
+
+enum cx25840_io_pin {
+       CX25840_PIN_DVALID_PRGM0 = 0,
+       CX25840_PIN_FIELD_PRGM1,
+       CX25840_PIN_HRESET_PRGM2,
+       CX25840_PIN_VRESET_HCTL_PRGM3,
+       CX25840_PIN_IRQ_N_PRGM4,
+       CX25840_PIN_IR_TX_PRGM6,
+       CX25840_PIN_IR_RX_PRGM5,
+       CX25840_PIN_GPIO0_PRGM8,
+       CX25840_PIN_GPIO1_PRGM9,
+       CX25840_PIN_SA_SDIN,            /* Alternate GP Input only */
+       CX25840_PIN_SA_SDOUT,           /* Alternate GP Input only */
+       CX25840_PIN_PLL_CLK_PRGM7,
+       CX25840_PIN_CHIP_SEL_VIPCLK,    /* Output only */
+};
+
+enum cx25840_io_pad {
+       /* Output pads */
+       CX25840_PAD_DEFAULT = 0,
+       CX25840_PAD_ACTIVE,
+       CX25840_PAD_VACTIVE,
+       CX25840_PAD_CBFLAG,
+       CX25840_PAD_VID_DATA_EXT0,
+       CX25840_PAD_VID_DATA_EXT1,
+       CX25840_PAD_GPO0,
+       CX25840_PAD_GPO1,
+       CX25840_PAD_GPO2,
+       CX25840_PAD_GPO3,
+       CX25840_PAD_IRQ_N,
+       CX25840_PAD_AC_SYNC,
+       CX25840_PAD_AC_SDOUT,
+       CX25840_PAD_PLL_CLK,
+       CX25840_PAD_VRESET,
+       CX25840_PAD_RESERVED,
+       /* Pads for PLL_CLK output only */
+       CX25840_PAD_XTI_X5_DLL,
+       CX25840_PAD_AUX_PLL,
+       CX25840_PAD_VID_PLL,
+       CX25840_PAD_XTI,
+       /* Input Pads */
+       CX25840_PAD_GPI0,
+       CX25840_PAD_GPI1,
+       CX25840_PAD_GPI2,
+       CX25840_PAD_GPI3,
+};
+
+enum cx25840_io_pin_strength {
+       CX25840_PIN_DRIVE_MEDIUM = 0,
+       CX25840_PIN_DRIVE_SLOW,
+       CX25840_PIN_DRIVE_FAST,
+};
+
+enum cx23885_io_pin {
+       CX23885_PIN_IR_RX_GPIO19,
+       CX23885_PIN_IR_TX_GPIO20,
+       CX23885_PIN_I2S_SDAT_GPIO21,
+       CX23885_PIN_I2S_WCLK_GPIO22,
+       CX23885_PIN_I2S_BCLK_GPIO23,
+       CX23885_PIN_IRQ_N_GPIO16,
+};
+
+enum cx23885_io_pad {
+       CX23885_PAD_IR_RX,
+       CX23885_PAD_GPIO19,
+       CX23885_PAD_IR_TX,
+       CX23885_PAD_GPIO20,
+       CX23885_PAD_I2S_SDAT,
+       CX23885_PAD_GPIO21,
+       CX23885_PAD_I2S_WCLK,
+       CX23885_PAD_GPIO22,
+       CX23885_PAD_I2S_BCLK,
+       CX23885_PAD_GPIO23,
+       CX23885_PAD_IRQ_N,
+       CX23885_PAD_GPIO16,
+};
+
+/* pvr150_workaround activates a workaround for a hardware bug that is
+   present in Hauppauge PVR-150 (and possibly PVR-500) cards that have
+   certain NTSC tuners (tveeprom tuner model numbers 85, 99 and 112). The
+   audio autodetect fails on some channels for these models and the workaround
+   is to select the audio standard explicitly. Many thanks to Hauppauge for
+   providing this information.
+   This platform data only needs to be supplied by the ivtv driver. */
+struct cx25840_platform_data {
+       int pvr150_workaround;
+};
+
+#endif
diff --git a/include/media/drv-intf/exynos-fimc.h b/include/media/drv-intf/exynos-fimc.h
new file mode 100644 (file)
index 0000000..69bcd2a
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Samsung S5P/Exynos4 SoC series camera interface driver header
+ *
+ * Copyright (C) 2010 - 2013 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@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.
+ */
+
+#ifndef S5P_FIMC_H_
+#define S5P_FIMC_H_
+
+#include <media/media-entity.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-mediabus.h>
+
+/*
+ * Enumeration of data inputs to the camera subsystem.
+ */
+enum fimc_input {
+       FIMC_INPUT_PARALLEL_0   = 1,
+       FIMC_INPUT_PARALLEL_1,
+       FIMC_INPUT_MIPI_CSI2_0  = 3,
+       FIMC_INPUT_MIPI_CSI2_1,
+       FIMC_INPUT_WRITEBACK_A  = 5,
+       FIMC_INPUT_WRITEBACK_B,
+       FIMC_INPUT_WRITEBACK_ISP = 5,
+};
+
+/*
+ * Enumeration of the FIMC data bus types.
+ */
+enum fimc_bus_type {
+       /* Camera parallel bus */
+       FIMC_BUS_TYPE_ITU_601 = 1,
+       /* Camera parallel bus with embedded synchronization */
+       FIMC_BUS_TYPE_ITU_656,
+       /* Camera MIPI-CSI2 serial bus */
+       FIMC_BUS_TYPE_MIPI_CSI2,
+       /* FIFO link from LCD controller (WriteBack A) */
+       FIMC_BUS_TYPE_LCD_WRITEBACK_A,
+       /* FIFO link from LCD controller (WriteBack B) */
+       FIMC_BUS_TYPE_LCD_WRITEBACK_B,
+       /* FIFO link from FIMC-IS */
+       FIMC_BUS_TYPE_ISP_WRITEBACK = FIMC_BUS_TYPE_LCD_WRITEBACK_B,
+};
+
+#define fimc_input_is_parallel(x) ((x) == 1 || (x) == 2)
+#define fimc_input_is_mipi_csi(x) ((x) == 3 || (x) == 4)
+
+/*
+ * The subdevices' group IDs.
+ */
+#define GRP_ID_SENSOR          (1 << 8)
+#define GRP_ID_FIMC_IS_SENSOR  (1 << 9)
+#define GRP_ID_WRITEBACK       (1 << 10)
+#define GRP_ID_CSIS            (1 << 11)
+#define GRP_ID_FIMC            (1 << 12)
+#define GRP_ID_FLITE           (1 << 13)
+#define GRP_ID_FIMC_IS         (1 << 14)
+
+/**
+ * struct fimc_source_info - video source description required for the host
+ *                          interface configuration
+ *
+ * @fimc_bus_type: FIMC camera input type
+ * @sensor_bus_type: image sensor bus type, MIPI, ITU-R BT.601 etc.
+ * @flags: the parallel sensor bus flags defining signals polarity (V4L2_MBUS_*)
+ * @mux_id: FIMC camera interface multiplexer index (separate for MIPI and ITU)
+ */
+struct fimc_source_info {
+       enum fimc_bus_type fimc_bus_type;
+       enum fimc_bus_type sensor_bus_type;
+       u16 flags;
+       u16 mux_id;
+};
+
+/*
+ * v4l2_device notification id. This is only for internal use in the kernel.
+ * Sensor subdevs should issue S5P_FIMC_TX_END_NOTIFY notification in single
+ * frame capture mode when there is only one VSYNC pulse issued by the sensor
+ * at begining of the frame transmission.
+ */
+#define S5P_FIMC_TX_END_NOTIFY _IO('e', 0)
+
+#define FIMC_MAX_PLANES        3
+
+/**
+ * struct fimc_fmt - color format data structure
+ * @mbus_code: media bus pixel code, -1 if not applicable
+ * @name: format description
+ * @fourcc: fourcc code for this format, 0 if not applicable
+ * @color: the driver's private color format id
+ * @memplanes: number of physically non-contiguous data planes
+ * @colplanes: number of physically contiguous data planes
+ * @colorspace: v4l2 colorspace (V4L2_COLORSPACE_*)
+ * @depth: per plane driver's private 'number of bits per pixel'
+ * @mdataplanes: bitmask indicating meta data plane(s), (1 << plane_no)
+ * @flags: flags indicating which operation mode format applies to
+ */
+struct fimc_fmt {
+       u32 mbus_code;
+       char    *name;
+       u32     fourcc;
+       u32     color;
+       u16     memplanes;
+       u16     colplanes;
+       u8      colorspace;
+       u8      depth[FIMC_MAX_PLANES];
+       u16     mdataplanes;
+       u16     flags;
+#define FMT_FLAGS_CAM          (1 << 0)
+#define FMT_FLAGS_M2M_IN       (1 << 1)
+#define FMT_FLAGS_M2M_OUT      (1 << 2)
+#define FMT_FLAGS_M2M          (1 << 1 | 1 << 2)
+#define FMT_HAS_ALPHA          (1 << 3)
+#define FMT_FLAGS_COMPRESSED   (1 << 4)
+#define FMT_FLAGS_WRITEBACK    (1 << 5)
+#define FMT_FLAGS_RAW_BAYER    (1 << 6)
+#define FMT_FLAGS_YUV          (1 << 7)
+};
+
+struct exynos_media_pipeline;
+
+/*
+ * Media pipeline operations to be called from within a video node,  i.e. the
+ * last entity within the pipeline. Implemented by related media device driver.
+ */
+struct exynos_media_pipeline_ops {
+       int (*prepare)(struct exynos_media_pipeline *p,
+                                               struct media_entity *me);
+       int (*unprepare)(struct exynos_media_pipeline *p);
+       int (*open)(struct exynos_media_pipeline *p, struct media_entity *me,
+                                                       bool resume);
+       int (*close)(struct exynos_media_pipeline *p);
+       int (*set_stream)(struct exynos_media_pipeline *p, bool state);
+};
+
+struct exynos_video_entity {
+       struct video_device vdev;
+       struct exynos_media_pipeline *pipe;
+};
+
+struct exynos_media_pipeline {
+       struct media_pipeline mp;
+       const struct exynos_media_pipeline_ops *ops;
+};
+
+static inline struct exynos_video_entity *vdev_to_exynos_video_entity(
+                                       struct video_device *vdev)
+{
+       return container_of(vdev, struct exynos_video_entity, vdev);
+}
+
+#define fimc_pipeline_call(ent, op, args...)                             \
+       (!(ent) ? -ENOENT : (((ent)->pipe->ops && (ent)->pipe->ops->op) ? \
+       (ent)->pipe->ops->op(((ent)->pipe), ##args) : -ENOIOCTLCMD))      \
+
+#endif /* S5P_FIMC_H_ */
diff --git a/include/media/drv-intf/msp3400.h b/include/media/drv-intf/msp3400.h
new file mode 100644 (file)
index 0000000..1e6e802
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+    msp3400.h - definition for msp3400 inputs and outputs
+
+    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
+
+    This program is 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 _MSP3400_H_
+#define _MSP3400_H_
+
+/* msp3400 routing
+   ===============
+
+   The msp3400 has a complicated routing scheme with many possible
+   combinations. The details are all in the datasheets but I will try
+   to give a short description here.
+
+   Inputs
+   ======
+
+   There are 1) tuner inputs, 2) I2S inputs, 3) SCART inputs. You will have
+   to select which tuner input to use and which SCART input to use. The
+   selected tuner input, the selected SCART input and all I2S inputs go to
+   the DSP (the tuner input first goes through the demodulator).
+
+   The DSP handles things like volume, bass/treble, balance, and some chips
+   have support for surround sound. It has several outputs: MAIN, AUX, I2S
+   and SCART1/2. Each output can select which DSP input to use. So the MAIN
+   output can select the tuner input while at the same time the SCART1 output
+   uses the I2S input.
+
+   Outputs
+   =======
+
+   Most DSP outputs are also the outputs of the msp3400. However, the SCART
+   outputs of the msp3400 can select which input to use: either the SCART1 or
+   SCART2 output from the DSP, or the msp3400 SCART inputs, thus completely
+   bypassing the DSP.
+
+   Summary
+   =======
+
+   So to specify a complete routing scheme for the msp3400 you will have to
+   specify in the 'input' arg of the s_routing function:
+
+   1) which tuner input to use
+   2) which SCART input to use
+   3) which DSP input to use for each DSP output
+
+   And in the 'output' arg of the s_routing function you specify:
+
+   1) which SCART input to use for each SCART output
+
+   Depending on how the msp is wired to the other components you can
+   ignore or mute certain inputs or outputs.
+
+   Also, depending on the msp version only a subset of the inputs or
+   outputs may be present. At the end of this header some tables are
+   added containing a list of what is available for each msp version.
+ */
+
+/* Inputs to the DSP unit: two independent selections have to be made:
+   1) the tuner (SIF) input
+   2) the SCART input
+   Bits 0-2 are used for the SCART input select, bit 3 is used for the tuner
+   input, bits 4-7 are reserved.
+ */
+
+/* SCART input to DSP selection */
+#define MSP_IN_SCART1                  0  /* Pin SC1_IN */
+#define MSP_IN_SCART2                  1  /* Pin SC2_IN */
+#define MSP_IN_SCART3                  2  /* Pin SC3_IN */
+#define MSP_IN_SCART4                  3  /* Pin SC4_IN */
+#define MSP_IN_MONO            6  /* Pin MONO_IN */
+#define MSP_IN_MUTE            7  /* Mute DSP input */
+#define MSP_SCART_TO_DSP(in)   (in)
+/* Tuner input to demodulator and DSP selection */
+#define MSP_IN_TUNER1          0  /* Analog Sound IF input pin ANA_IN1 */
+#define MSP_IN_TUNER2          1  /* Analog Sound IF input pin ANA_IN2 */
+#define MSP_TUNER_TO_DSP(in)   ((in) << 3)
+
+/* The msp has up to 5 DSP outputs, each output can independently select
+   a DSP input.
+
+   The DSP outputs are: loudspeaker output (aka MAIN), headphones output
+   (aka AUX), SCART1 DA output, SCART2 DA output and an I2S output.
+   There also is a quasi-peak detector output, but that is not used by
+   this driver and is set to the same input as the loudspeaker output.
+   Not all outputs are supported by all msp models. Setting the input
+   of an unsupported output will be ignored by the driver.
+
+   There are up to 16 DSP inputs to choose from, so each output is
+   assigned 4 bits.
+
+   Note: the 44x8G can mix two inputs and feed the result back to the
+   DSP. This is currently not implemented. Also not implemented is the
+   multi-channel capable I2S3 input of the 44x0G. If someone can demonstrate
+   a need for one of those features then additional support can be added. */
+#define MSP_DSP_IN_TUNER       0  /* Tuner DSP input */
+#define MSP_DSP_IN_SCART       2  /* SCART DSP input */
+#define MSP_DSP_IN_I2S1        5  /* I2S1 DSP input */
+#define MSP_DSP_IN_I2S2        6  /* I2S2 DSP input */
+#define MSP_DSP_IN_I2S3        7  /* I2S3 DSP input */
+#define MSP_DSP_IN_MAIN_AVC    11 /* MAIN AVC processed DSP input */
+#define MSP_DSP_IN_MAIN        12 /* MAIN DSP input */
+#define MSP_DSP_IN_AUX                 13 /* AUX DSP input */
+#define MSP_DSP_TO_MAIN(in)    ((in) << 4)
+#define MSP_DSP_TO_AUX(in)     ((in) << 8)
+#define MSP_DSP_TO_SCART1(in)  ((in) << 12)
+#define MSP_DSP_TO_SCART2(in)  ((in) << 16)
+#define MSP_DSP_TO_I2S(in)     ((in) << 20)
+
+/* Output SCART select: the SCART outputs can select which input
+   to use. */
+#define MSP_SC_IN_SCART1       0  /* SCART1 input, bypassing the DSP */
+#define MSP_SC_IN_SCART2       1  /* SCART2 input, bypassing the DSP */
+#define MSP_SC_IN_SCART3       2  /* SCART3 input, bypassing the DSP */
+#define MSP_SC_IN_SCART4       3  /* SCART4 input, bypassing the DSP */
+#define MSP_SC_IN_DSP_SCART1   4  /* DSP SCART1 input */
+#define MSP_SC_IN_DSP_SCART2   5  /* DSP SCART2 input */
+#define MSP_SC_IN_MONO                 6  /* MONO input, bypassing the DSP */
+#define MSP_SC_IN_MUTE                 7  /* MUTE output */
+#define MSP_SC_TO_SCART1(in)   (in)
+#define MSP_SC_TO_SCART2(in)   ((in) << 4)
+
+/* Shortcut macros */
+#define MSP_INPUT(sc, t, main_aux_src, sc_i2s_src) \
+       (MSP_SCART_TO_DSP(sc) | \
+        MSP_TUNER_TO_DSP(t) | \
+        MSP_DSP_TO_MAIN(main_aux_src) | \
+        MSP_DSP_TO_AUX(main_aux_src) | \
+        MSP_DSP_TO_SCART1(sc_i2s_src) | \
+        MSP_DSP_TO_SCART2(sc_i2s_src) | \
+        MSP_DSP_TO_I2S(sc_i2s_src))
+#define MSP_INPUT_DEFAULT MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, \
+                                   MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER)
+#define MSP_OUTPUT(sc) \
+       (MSP_SC_TO_SCART1(sc) | \
+        MSP_SC_TO_SCART2(sc))
+/* This equals the RESET position of the msp3400 ACB register */
+#define MSP_OUTPUT_DEFAULT (MSP_SC_TO_SCART1(MSP_SC_IN_SCART3) | \
+                           MSP_SC_TO_SCART2(MSP_SC_IN_DSP_SCART1))
+
+/* Tuner inputs vs. msp version */
+/* Chip      TUNER_1   TUNER_2
+   -------------------------
+   msp34x0b  y         y
+   msp34x0c  y         y
+   msp34x0d  y         y
+   msp34x5d  y         n
+   msp34x7d  y         n
+   msp34x0g  y         y
+   msp34x1g  y         y
+   msp34x2g  y         y
+   msp34x5g  y         n
+   msp34x7g  y         n
+   msp44x0g  y         y
+   msp44x8g  y         y
+ */
+
+/* SCART inputs vs. msp version */
+/* Chip      SC1 SC2 SC3 SC4
+   -------------------------
+   msp34x0b  y   y   y   n
+   msp34x0c  y   y   y   n
+   msp34x0d  y   y   y   y
+   msp34x5d  y   y   n   n
+   msp34x7d  y   n   n   n
+   msp34x0g  y   y   y   y
+   msp34x1g  y   y   y   y
+   msp34x2g  y   y   y   y
+   msp34x5g  y   y   n   n
+   msp34x7g  y   n   n   n
+   msp44x0g  y   y   y   y
+   msp44x8g  y   y   y   y
+ */
+
+/* DSP inputs vs. msp version (tuner and SCART inputs are always available) */
+/* Chip      I2S1 I2S2 I2S3 MAIN_AVC MAIN AUX
+   ------------------------------------------
+   msp34x0b  y    n    n    n        n    n
+   msp34x0c  y    y    n    n        n    n
+   msp34x0d  y    y    n    n        n    n
+   msp34x5d  y    y    n    n        n    n
+   msp34x7d  n    n    n    n        n    n
+   msp34x0g  y    y    n    n        n    n
+   msp34x1g  y    y    n    n        n    n
+   msp34x2g  y    y    n    y        y    y
+   msp34x5g  y    y    n    n        n    n
+   msp34x7g  n    n    n    n        n    n
+   msp44x0g  y    y    y    y        y    y
+   msp44x8g  y    y    y    n        n    n
+ */
+
+/* DSP outputs vs. msp version */
+/* Chip      MAIN AUX SCART1 SCART2 I2S
+   ------------------------------------
+   msp34x0b  y    y   y      n      y
+   msp34x0c  y    y   y      n      y
+   msp34x0d  y    y   y      y      y
+   msp34x5d  y    n   y      n      y
+   msp34x7d  y    n   y      n      n
+   msp34x0g  y    y   y      y      y
+   msp34x1g  y    y   y      y      y
+   msp34x2g  y    y   y      y      y
+   msp34x5g  y    n   y      n      y
+   msp34x7g  y    n   y      n      n
+   msp44x0g  y    y   y      y      y
+   msp44x8g  y    y   y      y      y
+ */
+
+#endif /* MSP3400_H */
diff --git a/include/media/drv-intf/s3c_camif.h b/include/media/drv-intf/s3c_camif.h
new file mode 100644 (file)
index 0000000..df96c2c
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * s3c24xx/s3c64xx SoC series Camera Interface (CAMIF) driver
+ *
+ * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@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.
+*/
+
+#ifndef MEDIA_S3C_CAMIF_
+#define MEDIA_S3C_CAMIF_
+
+#include <linux/i2c.h>
+#include <media/v4l2-mediabus.h>
+
+/**
+ * struct s3c_camif_sensor_info - an image sensor description
+ * @i2c_board_info: pointer to an I2C sensor subdevice board info
+ * @clock_frequency: frequency of the clock the host provides to a sensor
+ * @mbus_type: media bus type
+ * @i2c_bus_num: i2c control bus id the sensor is attached to
+ * @flags: the parallel bus flags defining signals polarity (V4L2_MBUS_*)
+ * @use_field: 1 if parallel bus FIELD signal is used (only s3c64xx)
+ */
+struct s3c_camif_sensor_info {
+       struct i2c_board_info i2c_board_info;
+       unsigned long clock_frequency;
+       enum v4l2_mbus_type mbus_type;
+       u16 i2c_bus_num;
+       u16 flags;
+       u8 use_field;
+};
+
+struct s3c_camif_plat_data {
+       struct s3c_camif_sensor_info sensor;
+       int (*gpio_get)(void);
+       int (*gpio_put)(void);
+};
+
+/* Platform default helper functions */
+int s3c_camif_gpio_get(void);
+int s3c_camif_gpio_put(void);
+
+#endif /* MEDIA_S3C_CAMIF_ */
diff --git a/include/media/drv-intf/saa7146.h b/include/media/drv-intf/saa7146.h
new file mode 100644 (file)
index 0000000..96058a5
--- /dev/null
@@ -0,0 +1,471 @@
+#ifndef __SAA7146__
+#define __SAA7146__
+
+#include <linux/delay.h>       /* for delay-stuff */
+#include <linux/slab.h>                /* for kmalloc/kfree */
+#include <linux/pci.h>         /* for pci-config-stuff, vendor ids etc. */
+#include <linux/init.h>                /* for "__init" */
+#include <linux/interrupt.h>   /* for IMMEDIATE_BH */
+#include <linux/kmod.h>                /* for kernel module loader */
+#include <linux/i2c.h>         /* for i2c subsystem */
+#include <asm/io.h>            /* for accessing devices */
+#include <linux/stringify.h>
+#include <linux/mutex.h>
+#include <linux/scatterlist.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+#include <linux/vmalloc.h>     /* for vmalloc() */
+#include <linux/mm.h>          /* for vmalloc_to_page() */
+
+#define saa7146_write(sxy,adr,dat)    writel((dat),(sxy->mem+(adr)))
+#define saa7146_read(sxy,adr)         readl(sxy->mem+(adr))
+
+extern unsigned int saa7146_debug;
+
+#ifndef DEBUG_VARIABLE
+       #define DEBUG_VARIABLE saa7146_debug
+#endif
+
+#define ERR(fmt, ...)  pr_err("%s: " fmt, __func__, ##__VA_ARGS__)
+
+#define _DBG(mask, fmt, ...)                                           \
+do {                                                                   \
+       if (DEBUG_VARIABLE & mask)                                      \
+               pr_debug("%s(): " fmt, __func__, ##__VA_ARGS__);        \
+} while (0)
+
+/* simple debug messages */
+#define DEB_S(fmt, ...)                _DBG(0x01, fmt, ##__VA_ARGS__)
+/* more detailed debug messages */
+#define DEB_D(fmt, ...)                _DBG(0x02, fmt, ##__VA_ARGS__)
+/* print enter and exit of functions */
+#define DEB_EE(fmt, ...)       _DBG(0x04, fmt, ##__VA_ARGS__)
+/* i2c debug messages */
+#define DEB_I2C(fmt, ...)      _DBG(0x08, fmt, ##__VA_ARGS__)
+/* vbi debug messages */
+#define DEB_VBI(fmt, ...)      _DBG(0x10, fmt, ##__VA_ARGS__)
+/* interrupt debug messages */
+#define DEB_INT(fmt, ...)      _DBG(0x20, fmt, ##__VA_ARGS__)
+/* capture debug messages */
+#define DEB_CAP(fmt, ...)      _DBG(0x40, fmt, ##__VA_ARGS__)
+
+#define SAA7146_ISR_CLEAR(x,y) \
+       saa7146_write(x, ISR, (y));
+
+struct module;
+
+struct saa7146_dev;
+struct saa7146_extension;
+struct saa7146_vv;
+
+/* saa7146 page table */
+struct saa7146_pgtable {
+       unsigned int    size;
+       __le32          *cpu;
+       dma_addr_t      dma;
+       /* used for offsets for u,v planes for planar capture modes */
+       unsigned long   offset;
+       /* used for custom pagetables (used for example by budget dvb cards) */
+       struct scatterlist *slist;
+       int             nents;
+};
+
+struct saa7146_pci_extension_data {
+       struct saa7146_extension *ext;
+       void *ext_priv;                 /* most likely a name string */
+};
+
+#define MAKE_EXTENSION_PCI(x_var, x_vendor, x_device)          \
+       {                                                       \
+               .vendor    = PCI_VENDOR_ID_PHILIPS,             \
+               .device    = PCI_DEVICE_ID_PHILIPS_SAA7146,     \
+               .subvendor = x_vendor,                          \
+               .subdevice = x_device,                          \
+               .driver_data = (unsigned long)& x_var,          \
+       }
+
+struct saa7146_extension
+{
+       char    name[32];               /* name of the device */
+#define SAA7146_USE_I2C_IRQ    0x1
+#define SAA7146_I2C_SHORT_DELAY        0x2
+       int     flags;
+
+       /* pairs of subvendor and subdevice ids for
+          supported devices, last entry 0xffff, 0xfff */
+       struct module *module;
+       struct pci_driver driver;
+       struct pci_device_id *pci_tbl;
+
+       /* extension functions */
+       int (*probe)(struct saa7146_dev *);
+       int (*attach)(struct saa7146_dev *, struct saa7146_pci_extension_data *);
+       int (*detach)(struct saa7146_dev*);
+
+       u32     irq_mask;       /* mask to indicate, which irq-events are handled by the extension */
+       void    (*irq_func)(struct saa7146_dev*, u32* irq_mask);
+};
+
+struct saa7146_dma
+{
+       dma_addr_t      dma_handle;
+       __le32          *cpu_addr;
+};
+
+struct saa7146_dev
+{
+       struct module                   *module;
+
+       struct v4l2_device              v4l2_dev;
+       struct v4l2_ctrl_handler        ctrl_handler;
+
+       /* different device locks */
+       spinlock_t                      slock;
+       struct mutex                    v4l2_lock;
+
+       unsigned char                   __iomem *mem;           /* pointer to mapped IO memory */
+       u32                             revision;       /* chip revision; needed for bug-workarounds*/
+
+       /* pci-device & irq stuff*/
+       char                            name[32];
+       struct pci_dev                  *pci;
+       u32                             int_todo;
+       spinlock_t                      int_slock;
+
+       /* extension handling */
+       struct saa7146_extension        *ext;           /* indicates if handled by extension */
+       void                            *ext_priv;      /* pointer for extension private use (most likely some private data) */
+       struct saa7146_ext_vv           *ext_vv_data;
+
+       /* per device video/vbi informations (if available) */
+       struct saa7146_vv       *vv_data;
+       void (*vv_callback)(struct saa7146_dev *dev, unsigned long status);
+
+       /* i2c-stuff */
+       struct mutex                    i2c_lock;
+
+       u32                             i2c_bitrate;
+       struct saa7146_dma              d_i2c;  /* pointer to i2c memory */
+       wait_queue_head_t               i2c_wq;
+       int                             i2c_op;
+
+       /* memories */
+       struct saa7146_dma              d_rps0;
+       struct saa7146_dma              d_rps1;
+};
+
+static inline struct saa7146_dev *to_saa7146_dev(struct v4l2_device *v4l2_dev)
+{
+       return container_of(v4l2_dev, struct saa7146_dev, v4l2_dev);
+}
+
+/* from saa7146_i2c.c */
+int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate);
+
+/* from saa7146_core.c */
+int saa7146_register_extension(struct saa7146_extension*);
+int saa7146_unregister_extension(struct saa7146_extension*);
+struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc);
+int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt);
+void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt);
+int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, struct scatterlist *list, int length );
+void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt);
+void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt);
+void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data);
+int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop);
+
+/* some memory sizes */
+#define SAA7146_I2C_MEM                ( 1*PAGE_SIZE)
+#define SAA7146_RPS_MEM                ( 1*PAGE_SIZE)
+
+/* some i2c constants */
+#define SAA7146_I2C_TIMEOUT    100     /* i2c-timeout-value in ms */
+#define SAA7146_I2C_RETRIES    3       /* how many times shall we retry an i2c-operation? */
+#define SAA7146_I2C_DELAY      5       /* time we wait after certain i2c-operations */
+
+/* unsorted defines */
+#define ME1    0x0000000800
+#define PV1    0x0000000008
+
+/* gpio defines */
+#define SAA7146_GPIO_INPUT 0x00
+#define SAA7146_GPIO_IRQHI 0x10
+#define SAA7146_GPIO_IRQLO 0x20
+#define SAA7146_GPIO_IRQHL 0x30
+#define SAA7146_GPIO_OUTLO 0x40
+#define SAA7146_GPIO_OUTHI 0x50
+
+/* debi defines */
+#define DEBINOSWAP 0x000e0000
+
+/* define for the register programming sequencer (rps) */
+#define CMD_NOP                0x00000000  /* No operation */
+#define CMD_CLR_EVENT  0x00000000  /* Clear event */
+#define CMD_SET_EVENT  0x10000000  /* Set signal event */
+#define CMD_PAUSE      0x20000000  /* Pause */
+#define CMD_CHECK_LATE 0x30000000  /* Check late */
+#define CMD_UPLOAD     0x40000000  /* Upload */
+#define CMD_STOP       0x50000000  /* Stop */
+#define CMD_INTERRUPT  0x60000000  /* Interrupt */
+#define CMD_JUMP       0x80000000  /* Jump */
+#define CMD_WR_REG     0x90000000  /* Write (load) register */
+#define CMD_RD_REG     0xa0000000  /* Read (store) register */
+#define CMD_WR_REG_MASK        0xc0000000  /* Write register with mask */
+
+#define CMD_OAN                MASK_27
+#define CMD_INV                MASK_26
+#define CMD_SIG4       MASK_25
+#define CMD_SIG3       MASK_24
+#define CMD_SIG2       MASK_23
+#define CMD_SIG1       MASK_22
+#define CMD_SIG0       MASK_21
+#define CMD_O_FID_B    MASK_14
+#define CMD_E_FID_B    MASK_13
+#define CMD_O_FID_A    MASK_12
+#define CMD_E_FID_A    MASK_11
+
+/* some events and command modifiers for rps1 squarewave generator */
+#define EVT_HS          (1<<15)     // Source Line Threshold reached
+#define EVT_VBI_B       (1<<9)      // VSYNC Event
+#define RPS_OAN         (1<<27)     // 1: OR events, 0: AND events
+#define RPS_INV         (1<<26)     // Invert (compound) event
+#define GPIO3_MSK       0xFF000000  // GPIO #3 control bits
+
+/* Bit mask constants */
+#define MASK_00   0x00000001    /* Mask value for bit 0 */
+#define MASK_01   0x00000002    /* Mask value for bit 1 */
+#define MASK_02   0x00000004    /* Mask value for bit 2 */
+#define MASK_03   0x00000008    /* Mask value for bit 3 */
+#define MASK_04   0x00000010    /* Mask value for bit 4 */
+#define MASK_05   0x00000020    /* Mask value for bit 5 */
+#define MASK_06   0x00000040    /* Mask value for bit 6 */
+#define MASK_07   0x00000080    /* Mask value for bit 7 */
+#define MASK_08   0x00000100    /* Mask value for bit 8 */
+#define MASK_09   0x00000200    /* Mask value for bit 9 */
+#define MASK_10   0x00000400    /* Mask value for bit 10 */
+#define MASK_11   0x00000800    /* Mask value for bit 11 */
+#define MASK_12   0x00001000    /* Mask value for bit 12 */
+#define MASK_13   0x00002000    /* Mask value for bit 13 */
+#define MASK_14   0x00004000    /* Mask value for bit 14 */
+#define MASK_15   0x00008000    /* Mask value for bit 15 */
+#define MASK_16   0x00010000    /* Mask value for bit 16 */
+#define MASK_17   0x00020000    /* Mask value for bit 17 */
+#define MASK_18   0x00040000    /* Mask value for bit 18 */
+#define MASK_19   0x00080000    /* Mask value for bit 19 */
+#define MASK_20   0x00100000    /* Mask value for bit 20 */
+#define MASK_21   0x00200000    /* Mask value for bit 21 */
+#define MASK_22   0x00400000    /* Mask value for bit 22 */
+#define MASK_23   0x00800000    /* Mask value for bit 23 */
+#define MASK_24   0x01000000    /* Mask value for bit 24 */
+#define MASK_25   0x02000000    /* Mask value for bit 25 */
+#define MASK_26   0x04000000    /* Mask value for bit 26 */
+#define MASK_27   0x08000000    /* Mask value for bit 27 */
+#define MASK_28   0x10000000    /* Mask value for bit 28 */
+#define MASK_29   0x20000000    /* Mask value for bit 29 */
+#define MASK_30   0x40000000    /* Mask value for bit 30 */
+#define MASK_31   0x80000000    /* Mask value for bit 31 */
+
+#define MASK_B0   0x000000ff    /* Mask value for byte 0 */
+#define MASK_B1   0x0000ff00    /* Mask value for byte 1 */
+#define MASK_B2   0x00ff0000    /* Mask value for byte 2 */
+#define MASK_B3   0xff000000    /* Mask value for byte 3 */
+
+#define MASK_W0   0x0000ffff    /* Mask value for word 0 */
+#define MASK_W1   0xffff0000    /* Mask value for word 1 */
+
+#define MASK_PA   0xfffffffc    /* Mask value for physical address */
+#define MASK_PR   0xfffffffe   /* Mask value for protection register */
+#define MASK_ER   0xffffffff    /* Mask value for the entire register */
+
+#define MASK_NONE 0x00000000    /* No mask */
+
+/* register aliases */
+#define BASE_ODD1         0x00  /* Video DMA 1 registers  */
+#define BASE_EVEN1        0x04
+#define PROT_ADDR1        0x08
+#define PITCH1            0x0C
+#define BASE_PAGE1        0x10  /* Video DMA 1 base page */
+#define NUM_LINE_BYTE1    0x14
+
+#define BASE_ODD2         0x18  /* Video DMA 2 registers */
+#define BASE_EVEN2        0x1C
+#define PROT_ADDR2        0x20
+#define PITCH2            0x24
+#define BASE_PAGE2        0x28  /* Video DMA 2 base page */
+#define NUM_LINE_BYTE2    0x2C
+
+#define BASE_ODD3         0x30  /* Video DMA 3 registers */
+#define BASE_EVEN3        0x34
+#define PROT_ADDR3        0x38
+#define PITCH3            0x3C
+#define BASE_PAGE3        0x40  /* Video DMA 3 base page */
+#define NUM_LINE_BYTE3    0x44
+
+#define PCI_BT_V1         0x48  /* Video/FIFO 1 */
+#define PCI_BT_V2         0x49  /* Video/FIFO 2 */
+#define PCI_BT_V3         0x4A  /* Video/FIFO 3 */
+#define PCI_BT_DEBI       0x4B  /* DEBI */
+#define PCI_BT_A          0x4C  /* Audio */
+
+#define DD1_INIT          0x50  /* Init setting of DD1 interface */
+
+#define DD1_STREAM_B      0x54  /* DD1 B video data stream handling */
+#define DD1_STREAM_A      0x56  /* DD1 A video data stream handling */
+
+#define BRS_CTRL          0x58  /* BRS control register */
+#define HPS_CTRL          0x5C  /* HPS control register */
+#define HPS_V_SCALE       0x60  /* HPS vertical scale */
+#define HPS_V_GAIN        0x64  /* HPS vertical ACL and gain */
+#define HPS_H_PRESCALE    0x68  /* HPS horizontal prescale   */
+#define HPS_H_SCALE       0x6C  /* HPS horizontal scale */
+#define BCS_CTRL          0x70  /* BCS control */
+#define CHROMA_KEY_RANGE  0x74
+#define CLIP_FORMAT_CTRL  0x78  /* HPS outputs formats & clipping */
+
+#define DEBI_CONFIG       0x7C
+#define DEBI_COMMAND      0x80
+#define DEBI_PAGE         0x84
+#define DEBI_AD           0x88
+
+#define I2C_TRANSFER      0x8C
+#define I2C_STATUS        0x90
+
+#define BASE_A1_IN        0x94 /* Audio 1 input DMA */
+#define PROT_A1_IN        0x98
+#define PAGE_A1_IN        0x9C
+
+#define BASE_A1_OUT       0xA0  /* Audio 1 output DMA */
+#define PROT_A1_OUT       0xA4
+#define PAGE_A1_OUT       0xA8
+
+#define BASE_A2_IN        0xAC  /* Audio 2 input DMA */
+#define PROT_A2_IN        0xB0
+#define PAGE_A2_IN        0xB4
+
+#define BASE_A2_OUT       0xB8  /* Audio 2 output DMA */
+#define PROT_A2_OUT       0xBC
+#define PAGE_A2_OUT       0xC0
+
+#define RPS_PAGE0         0xC4  /* RPS task 0 page register */
+#define RPS_PAGE1         0xC8  /* RPS task 1 page register */
+
+#define RPS_THRESH0       0xCC  /* HBI threshold for task 0 */
+#define RPS_THRESH1       0xD0  /* HBI threshold for task 1 */
+
+#define RPS_TOV0          0xD4  /* RPS timeout for task 0 */
+#define RPS_TOV1          0xD8  /* RPS timeout for task 1 */
+
+#define IER               0xDC  /* Interrupt enable register */
+
+#define GPIO_CTRL         0xE0  /* GPIO 0-3 register */
+
+#define EC1SSR            0xE4  /* Event cnt set 1 source select */
+#define EC2SSR            0xE8  /* Event cnt set 2 source select */
+#define ECT1R             0xEC  /* Event cnt set 1 thresholds */
+#define ECT2R             0xF0  /* Event cnt set 2 thresholds */
+
+#define ACON1             0xF4
+#define ACON2             0xF8
+
+#define MC1               0xFC   /* Main control register 1 */
+#define MC2               0x100  /* Main control register 2  */
+
+#define RPS_ADDR0         0x104  /* RPS task 0 address register */
+#define RPS_ADDR1         0x108  /* RPS task 1 address register */
+
+#define ISR               0x10C  /* Interrupt status register */
+#define PSR               0x110  /* Primary status register */
+#define SSR               0x114  /* Secondary status register */
+
+#define EC1R              0x118  /* Event counter set 1 register */
+#define EC2R              0x11C  /* Event counter set 2 register */
+
+#define PCI_VDP1          0x120  /* Video DMA pointer of FIFO 1 */
+#define PCI_VDP2          0x124  /* Video DMA pointer of FIFO 2 */
+#define PCI_VDP3          0x128  /* Video DMA pointer of FIFO 3 */
+#define PCI_ADP1          0x12C  /* Audio DMA pointer of audio out 1 */
+#define PCI_ADP2          0x130  /* Audio DMA pointer of audio in 1 */
+#define PCI_ADP3          0x134  /* Audio DMA pointer of audio out 2 */
+#define PCI_ADP4          0x138  /* Audio DMA pointer of audio in 2 */
+#define PCI_DMA_DDP       0x13C  /* DEBI DMA pointer */
+
+#define LEVEL_REP         0x140,
+#define A_TIME_SLOT1      0x180,  /* from 180 - 1BC */
+#define A_TIME_SLOT2      0x1C0,  /* from 1C0 - 1FC */
+
+/* isr masks */
+#define SPCI_PPEF       0x80000000  /* PCI parity error */
+#define SPCI_PABO       0x40000000  /* PCI access error (target or master abort) */
+#define SPCI_PPED       0x20000000  /* PCI parity error on 'real time data' */
+#define SPCI_RPS_I1     0x10000000  /* Interrupt issued by RPS1 */
+#define SPCI_RPS_I0     0x08000000  /* Interrupt issued by RPS0 */
+#define SPCI_RPS_LATE1  0x04000000  /* RPS task 1 is late */
+#define SPCI_RPS_LATE0  0x02000000  /* RPS task 0 is late */
+#define SPCI_RPS_E1     0x01000000  /* RPS error from task 1 */
+#define SPCI_RPS_E0     0x00800000  /* RPS error from task 0 */
+#define SPCI_RPS_TO1    0x00400000  /* RPS timeout task 1 */
+#define SPCI_RPS_TO0    0x00200000  /* RPS timeout task 0 */
+#define SPCI_UPLD       0x00100000  /* RPS in upload */
+#define SPCI_DEBI_S     0x00080000  /* DEBI status */
+#define SPCI_DEBI_E     0x00040000  /* DEBI error */
+#define SPCI_IIC_S      0x00020000  /* I2C status */
+#define SPCI_IIC_E      0x00010000  /* I2C error */
+#define SPCI_A2_IN      0x00008000  /* Audio 2 input DMA protection / limit */
+#define SPCI_A2_OUT     0x00004000  /* Audio 2 output DMA protection / limit */
+#define SPCI_A1_IN      0x00002000  /* Audio 1 input DMA protection / limit */
+#define SPCI_A1_OUT     0x00001000  /* Audio 1 output DMA protection / limit */
+#define SPCI_AFOU       0x00000800  /* Audio FIFO over- / underflow */
+#define SPCI_V_PE       0x00000400  /* Video protection address */
+#define SPCI_VFOU       0x00000200  /* Video FIFO over- / underflow */
+#define SPCI_FIDA       0x00000100  /* Field ID video port A */
+#define SPCI_FIDB       0x00000080  /* Field ID video port B */
+#define SPCI_PIN3       0x00000040  /* GPIO pin 3 */
+#define SPCI_PIN2       0x00000020  /* GPIO pin 2 */
+#define SPCI_PIN1       0x00000010  /* GPIO pin 1 */
+#define SPCI_PIN0       0x00000008  /* GPIO pin 0 */
+#define SPCI_ECS        0x00000004  /* Event counter 1, 2, 4, 5 */
+#define SPCI_EC3S       0x00000002  /* Event counter 3 */
+#define SPCI_EC0S       0x00000001  /* Event counter 0 */
+
+/* i2c */
+#define        SAA7146_I2C_ABORT       (1<<7)
+#define        SAA7146_I2C_SPERR       (1<<6)
+#define        SAA7146_I2C_APERR       (1<<5)
+#define        SAA7146_I2C_DTERR       (1<<4)
+#define        SAA7146_I2C_DRERR       (1<<3)
+#define        SAA7146_I2C_AL          (1<<2)
+#define        SAA7146_I2C_ERR         (1<<1)
+#define        SAA7146_I2C_BUSY        (1<<0)
+
+#define        SAA7146_I2C_START       (0x3)
+#define        SAA7146_I2C_CONT        (0x2)
+#define        SAA7146_I2C_STOP        (0x1)
+#define        SAA7146_I2C_NOP         (0x0)
+
+#define SAA7146_I2C_BUS_BIT_RATE_6400  (0x500)
+#define SAA7146_I2C_BUS_BIT_RATE_3200  (0x100)
+#define SAA7146_I2C_BUS_BIT_RATE_480   (0x400)
+#define SAA7146_I2C_BUS_BIT_RATE_320   (0x600)
+#define SAA7146_I2C_BUS_BIT_RATE_240   (0x700)
+#define SAA7146_I2C_BUS_BIT_RATE_120   (0x000)
+#define SAA7146_I2C_BUS_BIT_RATE_80    (0x200)
+#define SAA7146_I2C_BUS_BIT_RATE_60    (0x300)
+
+static inline void SAA7146_IER_DISABLE(struct saa7146_dev *x, unsigned y)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&x->int_slock, flags);
+       saa7146_write(x, IER, saa7146_read(x, IER) & ~y);
+       spin_unlock_irqrestore(&x->int_slock, flags);
+}
+
+static inline void SAA7146_IER_ENABLE(struct saa7146_dev *x, unsigned y)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&x->int_slock, flags);
+       saa7146_write(x, IER, saa7146_read(x, IER) | y);
+       spin_unlock_irqrestore(&x->int_slock, flags);
+}
+
+#endif
diff --git a/include/media/drv-intf/saa7146_vv.h b/include/media/drv-intf/saa7146_vv.h
new file mode 100644 (file)
index 0000000..0da6ccc
--- /dev/null
@@ -0,0 +1,265 @@
+#ifndef __SAA7146_VV__
+#define __SAA7146_VV__
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/drv-intf/saa7146.h>
+#include <media/videobuf-dma-sg.h>
+
+#define MAX_SAA7146_CAPTURE_BUFFERS    32      /* arbitrary */
+#define BUFFER_TIMEOUT     (HZ/2)  /* 0.5 seconds */
+
+#define WRITE_RPS0(x) do { \
+       dev->d_rps0.cpu_addr[ count++ ] = cpu_to_le32(x); \
+       } while (0);
+
+#define WRITE_RPS1(x) do { \
+       dev->d_rps1.cpu_addr[ count++ ] = cpu_to_le32(x); \
+       } while (0);
+
+struct saa7146_video_dma {
+       u32 base_odd;
+       u32 base_even;
+       u32 prot_addr;
+       u32 pitch;
+       u32 base_page;
+       u32 num_line_byte;
+};
+
+#define FORMAT_BYTE_SWAP       0x1
+#define FORMAT_IS_PLANAR       0x2
+
+struct saa7146_format {
+       char    *name;
+       u32     pixelformat;
+       u32     trans;
+       u8      depth;
+       u8      flags;
+       u8      swap;
+};
+
+struct saa7146_standard
+{
+       char          *name;
+       v4l2_std_id   id;
+
+       int v_offset;   /* number of lines of vertical offset before processing */
+       int v_field;    /* number of lines in a field for HPS to process */
+
+       int h_offset;   /* horizontal offset of processing window */
+       int h_pixels;   /* number of horizontal pixels to process */
+
+       int v_max_out;
+       int h_max_out;
+};
+
+/* buffer for one video/vbi frame */
+struct saa7146_buf {
+       /* common v4l buffer stuff -- must be first */
+       struct videobuf_buffer vb;
+
+       /* saa7146 specific */
+       struct v4l2_pix_format  *fmt;
+       int (*activate)(struct saa7146_dev *dev,
+                       struct saa7146_buf *buf,
+                       struct saa7146_buf *next);
+
+       /* page tables */
+       struct saa7146_pgtable  pt[3];
+};
+
+struct saa7146_dmaqueue {
+       struct saa7146_dev      *dev;
+       struct saa7146_buf      *curr;
+       struct list_head        queue;
+       struct timer_list       timeout;
+};
+
+struct saa7146_overlay {
+       struct saa7146_fh       *fh;
+       struct v4l2_window      win;
+       struct v4l2_clip        clips[16];
+       int                     nclips;
+};
+
+/* per open data */
+struct saa7146_fh {
+       /* Must be the first field! */
+       struct v4l2_fh          fh;
+       struct saa7146_dev      *dev;
+
+       /* video capture */
+       struct videobuf_queue   video_q;
+
+       /* vbi capture */
+       struct videobuf_queue   vbi_q;
+
+       unsigned int resources; /* resource management for device open */
+};
+
+#define STATUS_OVERLAY 0x01
+#define STATUS_CAPTURE 0x02
+
+struct saa7146_vv
+{
+       /* vbi capture */
+       struct saa7146_dmaqueue         vbi_dmaq;
+       struct v4l2_vbi_format          vbi_fmt;
+       struct timer_list               vbi_read_timeout;
+       /* vbi workaround interrupt queue */
+       wait_queue_head_t               vbi_wq;
+       int                             vbi_fieldcount;
+       struct saa7146_fh               *vbi_streaming;
+
+       int                             video_status;
+       struct saa7146_fh               *video_fh;
+
+       /* video overlay */
+       struct saa7146_overlay          ov;
+       struct v4l2_framebuffer         ov_fb;
+       struct saa7146_format           *ov_fmt;
+       struct saa7146_fh               *ov_suspend;
+
+       /* video capture */
+       struct saa7146_dmaqueue         video_dmaq;
+       struct v4l2_pix_format          video_fmt;
+       enum v4l2_field                 last_field;
+
+       /* common: fixme? shouldn't this be in saa7146_fh?
+          (this leads to a more complicated question: shall the driver
+          store the different settings (for example S_INPUT) for every open
+          and restore it appropriately, or should all settings be common for
+          all opens? currently, we do the latter, like all other
+          drivers do... */
+       struct saa7146_standard *standard;
+
+       int     vflip;
+       int     hflip;
+       int     current_hps_source;
+       int     current_hps_sync;
+
+       struct saa7146_dma      d_clipping;     /* pointer to clipping memory */
+
+       unsigned int resources; /* resource management for device */
+};
+
+/* flags */
+#define SAA7146_USE_PORT_B_FOR_VBI     0x2     /* use input port b for vbi hardware bug workaround */
+
+struct saa7146_ext_vv
+{
+       /* informations about the video capabilities of the device */
+       int     inputs;
+       int     audios;
+       u32     capabilities;
+       int     flags;
+
+       /* additionally supported transmission standards */
+       struct saa7146_standard *stds;
+       int num_stds;
+       int (*std_callback)(struct saa7146_dev*, struct saa7146_standard *);
+
+       /* the extension can override this */
+       struct v4l2_ioctl_ops vid_ops;
+       struct v4l2_ioctl_ops vbi_ops;
+       /* pointer to the saa7146 core ops */
+       const struct v4l2_ioctl_ops *core_ops;
+
+       struct v4l2_file_operations vbi_fops;
+};
+
+struct saa7146_use_ops  {
+       void (*init)(struct saa7146_dev *, struct saa7146_vv *);
+       int(*open)(struct saa7146_dev *, struct file *);
+       void (*release)(struct saa7146_dev *, struct file *);
+       void (*irq_done)(struct saa7146_dev *, unsigned long status);
+       ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
+};
+
+/* from saa7146_fops.c */
+int saa7146_register_device(struct video_device *vid, struct saa7146_dev *dev, char *name, int type);
+int saa7146_unregister_device(struct video_device *vid, struct saa7146_dev *dev);
+void saa7146_buffer_finish(struct saa7146_dev *dev, struct saa7146_dmaqueue *q, int state);
+void saa7146_buffer_next(struct saa7146_dev *dev, struct saa7146_dmaqueue *q,int vbi);
+int saa7146_buffer_queue(struct saa7146_dev *dev, struct saa7146_dmaqueue *q, struct saa7146_buf *buf);
+void saa7146_buffer_timeout(unsigned long data);
+void saa7146_dma_free(struct saa7146_dev* dev,struct videobuf_queue *q,
+                                               struct saa7146_buf *buf);
+
+int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv);
+int saa7146_vv_release(struct saa7146_dev* dev);
+
+/* from saa7146_hlp.c */
+int saa7146_enable_overlay(struct saa7146_fh *fh);
+void saa7146_disable_overlay(struct saa7146_fh *fh);
+
+void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next);
+void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma) ;
+void saa7146_set_hps_source_and_sync(struct saa7146_dev *saa, int source, int sync);
+void saa7146_set_gpio(struct saa7146_dev *saa, u8 pin, u8 data);
+
+/* from saa7146_video.c */
+extern const struct v4l2_ioctl_ops saa7146_video_ioctl_ops;
+extern const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops;
+extern struct saa7146_use_ops saa7146_video_uops;
+int saa7146_start_preview(struct saa7146_fh *fh);
+int saa7146_stop_preview(struct saa7146_fh *fh);
+long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg);
+int saa7146_s_ctrl(struct v4l2_ctrl *ctrl);
+
+/* from saa7146_vbi.c */
+extern struct saa7146_use_ops saa7146_vbi_uops;
+
+/* resource management functions */
+int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit);
+void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits);
+
+#define RESOURCE_DMA1_HPS      0x1
+#define RESOURCE_DMA2_CLP      0x2
+#define RESOURCE_DMA3_BRS      0x4
+
+/* saa7146 source inputs */
+#define SAA7146_HPS_SOURCE_PORT_A      0x00
+#define SAA7146_HPS_SOURCE_PORT_B      0x01
+#define SAA7146_HPS_SOURCE_YPB_CPA     0x02
+#define SAA7146_HPS_SOURCE_YPA_CPB     0x03
+
+/* sync inputs */
+#define SAA7146_HPS_SYNC_PORT_A                0x00
+#define SAA7146_HPS_SYNC_PORT_B                0x01
+
+/* some memory sizes */
+/* max. 16 clipping rectangles */
+#define SAA7146_CLIPPING_MEM   (16 * 4 * sizeof(u32))
+
+/* some defines for the various clipping-modes */
+#define SAA7146_CLIPPING_RECT          0x4
+#define SAA7146_CLIPPING_RECT_INVERTED 0x5
+#define SAA7146_CLIPPING_MASK          0x6
+#define SAA7146_CLIPPING_MASK_INVERTED 0x7
+
+/* output formats: each entry holds four informations */
+#define RGB08_COMPOSED 0x0217 /* composed is used in the sense of "not-planar" */
+/* this means: planar?=0, yuv2rgb-conversation-mode=2, dither=yes(=1), format-mode = 7 */
+#define RGB15_COMPOSED 0x0213
+#define RGB16_COMPOSED 0x0210
+#define RGB24_COMPOSED 0x0201
+#define RGB32_COMPOSED 0x0202
+
+#define Y8                     0x0006
+#define YUV411_COMPOSED                0x0003
+#define YUV422_COMPOSED                0x0000
+/* this means: planar?=1, yuv2rgb-conversion-mode=0, dither=no(=0), format-mode = b */
+#define YUV411_DECOMPOSED      0x100b
+#define YUV422_DECOMPOSED      0x1009
+#define YUV420_DECOMPOSED      0x100a
+
+#define IS_PLANAR(x) (x & 0xf000)
+
+/* misc defines */
+#define SAA7146_NO_SWAP                (0x0)
+#define SAA7146_TWO_BYTE_SWAP  (0x1)
+#define SAA7146_FOUR_BYTE_SWAP (0x2)
+
+#endif
diff --git a/include/media/drv-intf/sh_mobile_ceu.h b/include/media/drv-intf/sh_mobile_ceu.h
new file mode 100644 (file)
index 0000000..7f57056
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __ASM_SH_MOBILE_CEU_H__
+#define __ASM_SH_MOBILE_CEU_H__
+
+#define SH_CEU_FLAG_USE_8BIT_BUS       (1 << 0) /* use  8bit bus width */
+#define SH_CEU_FLAG_USE_16BIT_BUS      (1 << 1) /* use 16bit bus width */
+#define SH_CEU_FLAG_HSYNC_LOW          (1 << 2) /* default High if possible */
+#define SH_CEU_FLAG_VSYNC_LOW          (1 << 3) /* default High if possible */
+#define SH_CEU_FLAG_LOWER_8BIT         (1 << 4) /* default upper 8bit */
+
+struct device;
+struct resource;
+
+struct sh_mobile_ceu_companion {
+       u32             num_resources;
+       struct resource *resource;
+       int             id;
+       void            *platform_data;
+};
+
+struct sh_mobile_ceu_info {
+       unsigned long flags;
+       int max_width;
+       int max_height;
+       struct sh_mobile_ceu_companion *csi2;
+       struct v4l2_async_subdev **asd; /* Flat array, arranged in groups */
+       unsigned int *asd_sizes;        /* 0-terminated array pf asd group sizes */
+};
+
+#endif /* __ASM_SH_MOBILE_CEU_H__ */
diff --git a/include/media/drv-intf/sh_mobile_csi2.h b/include/media/drv-intf/sh_mobile_csi2.h
new file mode 100644 (file)
index 0000000..14030db
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Driver header for the SH-Mobile MIPI CSI-2 unit
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.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.
+ */
+
+#ifndef SH_MIPI_CSI
+#define SH_MIPI_CSI
+
+#include <linux/list.h>
+
+enum sh_csi2_phy {
+       SH_CSI2_PHY_MAIN,
+       SH_CSI2_PHY_SUB,
+};
+
+enum sh_csi2_type {
+       SH_CSI2C,
+       SH_CSI2I,
+};
+
+#define SH_CSI2_CRC    (1 << 0)
+#define SH_CSI2_ECC    (1 << 1)
+
+struct platform_device;
+
+struct sh_csi2_client_config {
+       enum sh_csi2_phy phy;
+       unsigned char lanes;            /* bitmask[3:0] */
+       unsigned char channel;          /* 0..3 */
+       struct platform_device *pdev;   /* client platform device */
+       const char *name;               /* async matching: client name */
+};
+
+struct v4l2_device;
+
+struct sh_csi2_pdata {
+       enum sh_csi2_type type;
+       unsigned int flags;
+       struct sh_csi2_client_config *clients;
+       int num_clients;
+};
+
+#endif
diff --git a/include/media/drv-intf/sh_vou.h b/include/media/drv-intf/sh_vou.h
new file mode 100644 (file)
index 0000000..ec3ba9a
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * SuperH Video Output Unit (VOU) driver header
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.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.
+ */
+#ifndef SH_VOU_H
+#define SH_VOU_H
+
+#include <linux/i2c.h>
+
+/* Bus flags */
+#define SH_VOU_PCLK_FALLING    (1 << 0)
+#define SH_VOU_HSYNC_LOW       (1 << 1)
+#define SH_VOU_VSYNC_LOW       (1 << 2)
+
+enum sh_vou_bus_fmt {
+       SH_VOU_BUS_8BIT,
+       SH_VOU_BUS_16BIT,
+       SH_VOU_BUS_BT656,
+};
+
+struct sh_vou_pdata {
+       enum sh_vou_bus_fmt bus_fmt;
+       int i2c_adap;
+       struct i2c_board_info *board_info;
+       unsigned long flags;
+};
+
+#endif
diff --git a/include/media/drv-intf/si476x.h b/include/media/drv-intf/si476x.h
new file mode 100644 (file)
index 0000000..ad87fa8
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * include/media/drv-intf/si476x.h -- Common definitions for si476x driver
+ *
+ * Copyright (C) 2012 Innovative Converged Devices(ICD)
+ * Copyright (C) 2013 Andrey Smirnov
+ *
+ * Author: Andrey Smirnov <andrew.smirnov@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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#ifndef SI476X_H
+#define SI476X_H
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <linux/mfd/si476x-reports.h>
+
+enum si476x_ctrl_id {
+       V4L2_CID_SI476X_RSSI_THRESHOLD  = (V4L2_CID_USER_SI476X_BASE + 1),
+       V4L2_CID_SI476X_SNR_THRESHOLD   = (V4L2_CID_USER_SI476X_BASE + 2),
+       V4L2_CID_SI476X_MAX_TUNE_ERROR  = (V4L2_CID_USER_SI476X_BASE + 3),
+       V4L2_CID_SI476X_HARMONICS_COUNT = (V4L2_CID_USER_SI476X_BASE + 4),
+       V4L2_CID_SI476X_DIVERSITY_MODE  = (V4L2_CID_USER_SI476X_BASE + 5),
+       V4L2_CID_SI476X_INTERCHIP_LINK  = (V4L2_CID_USER_SI476X_BASE + 6),
+};
+
+#endif /* SI476X_H*/
diff --git a/include/media/drv-intf/soc_mediabus.h b/include/media/drv-intf/soc_mediabus.h
new file mode 100644 (file)
index 0000000..2ff7737
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * SoC-camera Media Bus API extensions
+ *
+ * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.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.
+ */
+
+#ifndef SOC_MEDIABUS_H
+#define SOC_MEDIABUS_H
+
+#include <linux/videodev2.h>
+#include <linux/v4l2-mediabus.h>
+
+/**
+ * enum soc_mbus_packing - data packing types on the media-bus
+ * @SOC_MBUS_PACKING_NONE:     no packing, bit-for-bit transfer to RAM, one
+ *                             sample represents one pixel
+ * @SOC_MBUS_PACKING_2X8_PADHI:        16 bits transferred in 2 8-bit samples, in the
+ *                             possibly incomplete byte high bits are padding
+ * @SOC_MBUS_PACKING_2X8_PADLO:        as above, but low bits are padding
+ * @SOC_MBUS_PACKING_EXTEND16: sample width (e.g., 10 bits) has to be extended
+ *                             to 16 bits
+ * @SOC_MBUS_PACKING_VARIABLE: compressed formats with variable packing
+ * @SOC_MBUS_PACKING_1_5X8:    used for packed YUV 4:2:0 formats, where 4
+ *                             pixels occupy 6 bytes in RAM
+ * @SOC_MBUS_PACKING_EXTEND32: sample width (e.g., 24 bits) has to be extended
+ *                             to 32 bits
+ */
+enum soc_mbus_packing {
+       SOC_MBUS_PACKING_NONE,
+       SOC_MBUS_PACKING_2X8_PADHI,
+       SOC_MBUS_PACKING_2X8_PADLO,
+       SOC_MBUS_PACKING_EXTEND16,
+       SOC_MBUS_PACKING_VARIABLE,
+       SOC_MBUS_PACKING_1_5X8,
+       SOC_MBUS_PACKING_EXTEND32,
+};
+
+/**
+ * enum soc_mbus_order - sample order on the media bus
+ * @SOC_MBUS_ORDER_LE:         least significant sample first
+ * @SOC_MBUS_ORDER_BE:         most significant sample first
+ */
+enum soc_mbus_order {
+       SOC_MBUS_ORDER_LE,
+       SOC_MBUS_ORDER_BE,
+};
+
+/**
+ * enum soc_mbus_layout - planes layout in memory
+ * @SOC_MBUS_LAYOUT_PACKED:            color components packed
+ * @SOC_MBUS_LAYOUT_PLANAR_2Y_U_V:     YUV components stored in 3 planes (4:2:2)
+ * @SOC_MBUS_LAYOUT_PLANAR_2Y_C:       YUV components stored in a luma and a
+ *                                     chroma plane (C plane is half the size
+ *                                     of Y plane)
+ * @SOC_MBUS_LAYOUT_PLANAR_Y_C:                YUV components stored in a luma and a
+ *                                     chroma plane (C plane is the same size
+ *                                     as Y plane)
+ */
+enum soc_mbus_layout {
+       SOC_MBUS_LAYOUT_PACKED = 0,
+       SOC_MBUS_LAYOUT_PLANAR_2Y_U_V,
+       SOC_MBUS_LAYOUT_PLANAR_2Y_C,
+       SOC_MBUS_LAYOUT_PLANAR_Y_C,
+};
+
+/**
+ * struct soc_mbus_pixelfmt - Data format on the media bus
+ * @name:              Name of the format
+ * @fourcc:            Fourcc code, that will be obtained if the data is
+ *                     stored in memory in the following way:
+ * @packing:           Type of sample-packing, that has to be used
+ * @order:             Sample order when storing in memory
+ * @bits_per_sample:   How many bits the bridge has to sample
+ */
+struct soc_mbus_pixelfmt {
+       const char              *name;
+       u32                     fourcc;
+       enum soc_mbus_packing   packing;
+       enum soc_mbus_order     order;
+       enum soc_mbus_layout    layout;
+       u8                      bits_per_sample;
+};
+
+/**
+ * struct soc_mbus_lookup - Lookup FOURCC IDs by mediabus codes for pass-through
+ * @code:      mediabus pixel-code
+ * @fmt:       pixel format description
+ */
+struct soc_mbus_lookup {
+       u32     code;
+       struct soc_mbus_pixelfmt        fmt;
+};
+
+const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc(
+       u32 code,
+       const struct soc_mbus_lookup *lookup,
+       int n);
+const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc(
+       u32 code);
+s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf);
+s32 soc_mbus_image_size(const struct soc_mbus_pixelfmt *mf,
+                       u32 bytes_per_line, u32 height);
+int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf,
+                       unsigned int *numerator, unsigned int *denominator);
+unsigned int soc_mbus_config_compatible(const struct v4l2_mbus_config *cfg,
+                                       unsigned int flags);
+
+#endif
diff --git a/include/media/drv-intf/tea575x.h b/include/media/drv-intf/tea575x.h
new file mode 100644 (file)
index 0000000..fb272d4
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef __SOUND_TEA575X_TUNER_H
+#define __SOUND_TEA575X_TUNER_H
+
+/*
+ *   ALSA driver for TEA5757/5759 Philips AM/FM tuner chips
+ *
+ *     Copyright (c) 2004 Jaroslav Kysela <perex@perex.cz>
+ *
+ *   This program is 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
+ *
+ */
+
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+
+#define TEA575X_FMIF   10700
+#define TEA575X_AMIF     450
+
+#define TEA575X_DATA   (1 << 0)
+#define TEA575X_CLK    (1 << 1)
+#define TEA575X_WREN   (1 << 2)
+#define TEA575X_MOST   (1 << 3)
+
+struct snd_tea575x;
+
+struct snd_tea575x_ops {
+       /* Drivers using snd_tea575x must either define read_ and write_val */
+       void (*write_val)(struct snd_tea575x *tea, u32 val);
+       u32 (*read_val)(struct snd_tea575x *tea);
+       /* Or define the 3 pin functions */
+       void (*set_pins)(struct snd_tea575x *tea, u8 pins);
+       u8 (*get_pins)(struct snd_tea575x *tea);
+       void (*set_direction)(struct snd_tea575x *tea, bool output);
+};
+
+struct snd_tea575x {
+       struct v4l2_device *v4l2_dev;
+       struct v4l2_file_operations fops;
+       struct video_device vd;         /* video device */
+       int radio_nr;                   /* radio_nr */
+       bool tea5759;                   /* 5759 chip is present */
+       bool has_am;                    /* Device can tune to AM freqs */
+       bool cannot_read_data;          /* Device cannot read the data pin */
+       bool cannot_mute;               /* Device cannot mute */
+       bool mute;                      /* Device is muted? */
+       bool stereo;                    /* receiving stereo */
+       bool tuned;                     /* tuned to a station */
+       unsigned int val;               /* hw value */
+       u32 band;                       /* 0: FM, 1: FM-Japan, 2: AM */
+       u32 freq;                       /* frequency */
+       struct mutex mutex;
+       const struct snd_tea575x_ops *ops;
+       void *private_data;
+       u8 card[32];
+       u8 bus_info[32];
+       struct v4l2_ctrl_handler ctrl_handler;
+       int (*ext_init)(struct snd_tea575x *tea);
+};
+
+int snd_tea575x_enum_freq_bands(struct snd_tea575x *tea,
+                                       struct v4l2_frequency_band *band);
+int snd_tea575x_g_tuner(struct snd_tea575x *tea, struct v4l2_tuner *v);
+int snd_tea575x_s_hw_freq_seek(struct file *file, struct snd_tea575x *tea,
+                               const struct v4l2_hw_freq_seek *a);
+int snd_tea575x_hw_init(struct snd_tea575x *tea);
+int snd_tea575x_init(struct snd_tea575x *tea, struct module *owner);
+void snd_tea575x_exit(struct snd_tea575x *tea);
+void snd_tea575x_set_freq(struct snd_tea575x *tea);
+
+#endif /* __SOUND_TEA575X_TUNER_H */
diff --git a/include/media/exynos-fimc.h b/include/media/exynos-fimc.h
deleted file mode 100644 (file)
index 69bcd2a..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Samsung S5P/Exynos4 SoC series camera interface driver header
- *
- * Copyright (C) 2010 - 2013 Samsung Electronics Co., Ltd.
- * Sylwester Nawrocki <s.nawrocki@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.
- */
-
-#ifndef S5P_FIMC_H_
-#define S5P_FIMC_H_
-
-#include <media/media-entity.h>
-#include <media/v4l2-dev.h>
-#include <media/v4l2-mediabus.h>
-
-/*
- * Enumeration of data inputs to the camera subsystem.
- */
-enum fimc_input {
-       FIMC_INPUT_PARALLEL_0   = 1,
-       FIMC_INPUT_PARALLEL_1,
-       FIMC_INPUT_MIPI_CSI2_0  = 3,
-       FIMC_INPUT_MIPI_CSI2_1,
-       FIMC_INPUT_WRITEBACK_A  = 5,
-       FIMC_INPUT_WRITEBACK_B,
-       FIMC_INPUT_WRITEBACK_ISP = 5,
-};
-
-/*
- * Enumeration of the FIMC data bus types.
- */
-enum fimc_bus_type {
-       /* Camera parallel bus */
-       FIMC_BUS_TYPE_ITU_601 = 1,
-       /* Camera parallel bus with embedded synchronization */
-       FIMC_BUS_TYPE_ITU_656,
-       /* Camera MIPI-CSI2 serial bus */
-       FIMC_BUS_TYPE_MIPI_CSI2,
-       /* FIFO link from LCD controller (WriteBack A) */
-       FIMC_BUS_TYPE_LCD_WRITEBACK_A,
-       /* FIFO link from LCD controller (WriteBack B) */
-       FIMC_BUS_TYPE_LCD_WRITEBACK_B,
-       /* FIFO link from FIMC-IS */
-       FIMC_BUS_TYPE_ISP_WRITEBACK = FIMC_BUS_TYPE_LCD_WRITEBACK_B,
-};
-
-#define fimc_input_is_parallel(x) ((x) == 1 || (x) == 2)
-#define fimc_input_is_mipi_csi(x) ((x) == 3 || (x) == 4)
-
-/*
- * The subdevices' group IDs.
- */
-#define GRP_ID_SENSOR          (1 << 8)
-#define GRP_ID_FIMC_IS_SENSOR  (1 << 9)
-#define GRP_ID_WRITEBACK       (1 << 10)
-#define GRP_ID_CSIS            (1 << 11)
-#define GRP_ID_FIMC            (1 << 12)
-#define GRP_ID_FLITE           (1 << 13)
-#define GRP_ID_FIMC_IS         (1 << 14)
-
-/**
- * struct fimc_source_info - video source description required for the host
- *                          interface configuration
- *
- * @fimc_bus_type: FIMC camera input type
- * @sensor_bus_type: image sensor bus type, MIPI, ITU-R BT.601 etc.
- * @flags: the parallel sensor bus flags defining signals polarity (V4L2_MBUS_*)
- * @mux_id: FIMC camera interface multiplexer index (separate for MIPI and ITU)
- */
-struct fimc_source_info {
-       enum fimc_bus_type fimc_bus_type;
-       enum fimc_bus_type sensor_bus_type;
-       u16 flags;
-       u16 mux_id;
-};
-
-/*
- * v4l2_device notification id. This is only for internal use in the kernel.
- * Sensor subdevs should issue S5P_FIMC_TX_END_NOTIFY notification in single
- * frame capture mode when there is only one VSYNC pulse issued by the sensor
- * at begining of the frame transmission.
- */
-#define S5P_FIMC_TX_END_NOTIFY _IO('e', 0)
-
-#define FIMC_MAX_PLANES        3
-
-/**
- * struct fimc_fmt - color format data structure
- * @mbus_code: media bus pixel code, -1 if not applicable
- * @name: format description
- * @fourcc: fourcc code for this format, 0 if not applicable
- * @color: the driver's private color format id
- * @memplanes: number of physically non-contiguous data planes
- * @colplanes: number of physically contiguous data planes
- * @colorspace: v4l2 colorspace (V4L2_COLORSPACE_*)
- * @depth: per plane driver's private 'number of bits per pixel'
- * @mdataplanes: bitmask indicating meta data plane(s), (1 << plane_no)
- * @flags: flags indicating which operation mode format applies to
- */
-struct fimc_fmt {
-       u32 mbus_code;
-       char    *name;
-       u32     fourcc;
-       u32     color;
-       u16     memplanes;
-       u16     colplanes;
-       u8      colorspace;
-       u8      depth[FIMC_MAX_PLANES];
-       u16     mdataplanes;
-       u16     flags;
-#define FMT_FLAGS_CAM          (1 << 0)
-#define FMT_FLAGS_M2M_IN       (1 << 1)
-#define FMT_FLAGS_M2M_OUT      (1 << 2)
-#define FMT_FLAGS_M2M          (1 << 1 | 1 << 2)
-#define FMT_HAS_ALPHA          (1 << 3)
-#define FMT_FLAGS_COMPRESSED   (1 << 4)
-#define FMT_FLAGS_WRITEBACK    (1 << 5)
-#define FMT_FLAGS_RAW_BAYER    (1 << 6)
-#define FMT_FLAGS_YUV          (1 << 7)
-};
-
-struct exynos_media_pipeline;
-
-/*
- * Media pipeline operations to be called from within a video node,  i.e. the
- * last entity within the pipeline. Implemented by related media device driver.
- */
-struct exynos_media_pipeline_ops {
-       int (*prepare)(struct exynos_media_pipeline *p,
-                                               struct media_entity *me);
-       int (*unprepare)(struct exynos_media_pipeline *p);
-       int (*open)(struct exynos_media_pipeline *p, struct media_entity *me,
-                                                       bool resume);
-       int (*close)(struct exynos_media_pipeline *p);
-       int (*set_stream)(struct exynos_media_pipeline *p, bool state);
-};
-
-struct exynos_video_entity {
-       struct video_device vdev;
-       struct exynos_media_pipeline *pipe;
-};
-
-struct exynos_media_pipeline {
-       struct media_pipeline mp;
-       const struct exynos_media_pipeline_ops *ops;
-};
-
-static inline struct exynos_video_entity *vdev_to_exynos_video_entity(
-                                       struct video_device *vdev)
-{
-       return container_of(vdev, struct exynos_video_entity, vdev);
-}
-
-#define fimc_pipeline_call(ent, op, args...)                             \
-       (!(ent) ? -ENOENT : (((ent)->pipe->ops && (ent)->pipe->ops->op) ? \
-       (ent)->pipe->ops->op(((ent)->pipe), ##args) : -ENOIOCTLCMD))      \
-
-#endif /* S5P_FIMC_H_ */
diff --git a/include/media/gpio-ir-recv.h b/include/media/gpio-ir-recv.h
deleted file mode 100644 (file)
index 0142736..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __GPIO_IR_RECV_H__
-#define __GPIO_IR_RECV_H__
-
-struct gpio_ir_recv_platform_data {
-       int             gpio_nr;
-       bool            active_low;
-       u64             allowed_protos;
-       const char      *map_name;
-};
-
-#endif /* __GPIO_IR_RECV_H__ */
-
diff --git a/include/media/i2c/ad9389b.h b/include/media/i2c/ad9389b.h
new file mode 100644 (file)
index 0000000..5ba9af8
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Analog Devices AD9389B/AD9889B video encoder driver header
+ *
+ * Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef AD9389B_H
+#define AD9389B_H
+
+enum ad9389b_tmds_pll_gear {
+       AD9389B_TMDS_PLL_GEAR_AUTOMATIC,
+       AD9389B_TMDS_PLL_GEAR_SEMI_AUTOMATIC,
+};
+
+/* Platform dependent definitions */
+struct ad9389b_platform_data {
+       enum ad9389b_tmds_pll_gear tmds_pll_gear ;
+       /* Differential Data/Clock Output Drive Strength (reg. 0xa2/0xa3) */
+       u8 diff_data_drive_strength;
+       u8 diff_clk_drive_strength;
+};
+
+/* notify events */
+#define AD9389B_MONITOR_DETECT 0
+#define AD9389B_EDID_DETECT 1
+
+struct ad9389b_monitor_detect {
+       int present;
+};
+
+struct ad9389b_edid_detect {
+       int present;
+       int segment;
+};
+
+#endif
diff --git a/include/media/i2c/adp1653.h b/include/media/i2c/adp1653.h
new file mode 100644 (file)
index 0000000..0b67093
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * include/media/i2c/adp1653.h
+ *
+ * Copyright (C) 2008--2011 Nokia Corporation
+ *
+ * Contact: Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * Contributors:
+ *     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.
+ *
+ * You 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
+#define ADP1653_H
+
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+
+#define ADP1653_NAME                           "adp1653"
+#define ADP1653_I2C_ADDR                       (0x60 >> 1)
+
+/* Register definitions */
+#define ADP1653_REG_OUT_SEL                    0x00
+#define ADP1653_REG_OUT_SEL_HPLED_TORCH_MIN    0x01
+#define ADP1653_REG_OUT_SEL_HPLED_TORCH_MAX    0x0b
+#define ADP1653_REG_OUT_SEL_HPLED_FLASH_MIN    0x0c
+#define ADP1653_REG_OUT_SEL_HPLED_FLASH_MAX    0x1f
+#define ADP1653_REG_OUT_SEL_HPLED_SHIFT                3
+#define ADP1653_REG_OUT_SEL_ILED_MAX           0x07
+#define ADP1653_REG_OUT_SEL_ILED_SHIFT         0
+
+#define ADP1653_REG_CONFIG                     0x01
+#define ADP1653_REG_CONFIG_TMR_CFG             (1 << 4)
+#define ADP1653_REG_CONFIG_TMR_SET_MAX         0x0f
+#define ADP1653_REG_CONFIG_TMR_SET_SHIFT       0
+
+#define ADP1653_REG_SW_STROBE                  0x02
+#define ADP1653_REG_SW_STROBE_SW_STROBE                (1 << 0)
+
+#define ADP1653_REG_FAULT                      0x03
+#define ADP1653_REG_FAULT_FLT_SCP              (1 << 3)
+#define ADP1653_REG_FAULT_FLT_OT               (1 << 2)
+#define ADP1653_REG_FAULT_FLT_TMR              (1 << 1)
+#define ADP1653_REG_FAULT_FLT_OV               (1 << 0)
+
+#define ADP1653_INDICATOR_INTENSITY_MIN                0
+#define ADP1653_INDICATOR_INTENSITY_STEP       2500
+#define ADP1653_INDICATOR_INTENSITY_MAX                \
+       (ADP1653_REG_OUT_SEL_ILED_MAX * ADP1653_INDICATOR_INTENSITY_STEP)
+#define ADP1653_INDICATOR_INTENSITY_uA_TO_REG(a) \
+       ((a) / ADP1653_INDICATOR_INTENSITY_STEP)
+#define ADP1653_INDICATOR_INTENSITY_REG_TO_uA(a) \
+       ((a) * ADP1653_INDICATOR_INTENSITY_STEP)
+
+#define ADP1653_FLASH_INTENSITY_BASE           35
+#define ADP1653_FLASH_INTENSITY_STEP           15
+#define ADP1653_FLASH_INTENSITY_MIN                                    \
+       (ADP1653_FLASH_INTENSITY_BASE                                   \
+        + ADP1653_REG_OUT_SEL_HPLED_FLASH_MIN * ADP1653_FLASH_INTENSITY_STEP)
+#define ADP1653_FLASH_INTENSITY_MAX                    \
+       (ADP1653_FLASH_INTENSITY_MIN +                  \
+        (ADP1653_REG_OUT_SEL_HPLED_FLASH_MAX -         \
+         ADP1653_REG_OUT_SEL_HPLED_FLASH_MIN + 1) *    \
+        ADP1653_FLASH_INTENSITY_STEP)
+
+#define ADP1653_FLASH_INTENSITY_mA_TO_REG(a)                           \
+       ((a) < ADP1653_FLASH_INTENSITY_BASE ? 0 :                       \
+        (((a) - ADP1653_FLASH_INTENSITY_BASE) / ADP1653_FLASH_INTENSITY_STEP))
+#define ADP1653_FLASH_INTENSITY_REG_TO_mA(a)           \
+       ((a) * ADP1653_FLASH_INTENSITY_STEP + ADP1653_FLASH_INTENSITY_BASE)
+
+#define ADP1653_TORCH_INTENSITY_MIN                                    \
+       (ADP1653_FLASH_INTENSITY_BASE                                   \
+        + ADP1653_REG_OUT_SEL_HPLED_TORCH_MIN * ADP1653_FLASH_INTENSITY_STEP)
+#define ADP1653_TORCH_INTENSITY_MAX                    \
+       (ADP1653_TORCH_INTENSITY_MIN +                  \
+        (ADP1653_REG_OUT_SEL_HPLED_TORCH_MAX -         \
+         ADP1653_REG_OUT_SEL_HPLED_TORCH_MIN + 1) *    \
+        ADP1653_FLASH_INTENSITY_STEP)
+
+struct adp1653_platform_data {
+       int (*power)(struct v4l2_subdev *sd, int on);
+
+       u32 max_flash_timeout;          /* flash light timeout in us */
+       u32 max_flash_intensity;        /* led intensity, flash mode, mA */
+       u32 max_torch_intensity;        /* led intensity, torch mode, mA */
+       u32 max_indicator_intensity;    /* indicator led intensity, uA */
+
+       struct gpio_desc *enable_gpio;  /* for device-tree based boot */
+};
+
+#define to_adp1653_flash(sd)   container_of(sd, struct adp1653_flash, subdev)
+
+struct adp1653_flash {
+       struct v4l2_subdev subdev;
+       struct adp1653_platform_data *platform_data;
+
+       struct v4l2_ctrl_handler ctrls;
+       struct v4l2_ctrl *led_mode;
+       struct v4l2_ctrl *flash_timeout;
+       struct v4l2_ctrl *flash_intensity;
+       struct v4l2_ctrl *torch_intensity;
+       struct v4l2_ctrl *indicator_intensity;
+
+       struct mutex power_lock;
+       int power_count;
+       int fault;
+};
+
+#endif /* ADP1653_H */
diff --git a/include/media/i2c/adv7183.h b/include/media/i2c/adv7183.h
new file mode 100644 (file)
index 0000000..c5c2d37
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * adv7183.h - definition for adv7183 inputs and outputs
+ *
+ * Copyright (c) 2011 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 _ADV7183_H_
+#define _ADV7183_H_
+
+/* ADV7183 HW inputs */
+#define ADV7183_COMPOSITE0  0  /* CVBS in on AIN1 */
+#define ADV7183_COMPOSITE1  1  /* CVBS in on AIN2 */
+#define ADV7183_COMPOSITE2  2  /* CVBS in on AIN3 */
+#define ADV7183_COMPOSITE3  3  /* CVBS in on AIN4 */
+#define ADV7183_COMPOSITE4  4  /* CVBS in on AIN5 */
+#define ADV7183_COMPOSITE5  5  /* CVBS in on AIN6 */
+#define ADV7183_COMPOSITE6  6  /* CVBS in on AIN7 */
+#define ADV7183_COMPOSITE7  7  /* CVBS in on AIN8 */
+#define ADV7183_COMPOSITE8  8  /* CVBS in on AIN9 */
+#define ADV7183_COMPOSITE9  9  /* CVBS in on AIN10 */
+#define ADV7183_COMPOSITE10 10 /* CVBS in on AIN11 */
+
+#define ADV7183_SVIDEO0     11 /* Y on AIN1, C on AIN4 */
+#define ADV7183_SVIDEO1     12 /* Y on AIN2, C on AIN5 */
+#define ADV7183_SVIDEO2     13 /* Y on AIN3, C on AIN6 */
+
+#define ADV7183_COMPONENT0  14 /* Y on AIN1, Pr on AIN4, Pb on AIN5 */
+#define ADV7183_COMPONENT1  15 /* Y on AIN2, Pr on AIN3, Pb on AIN6 */
+
+/* ADV7183 HW outputs */
+#define ADV7183_8BIT_OUT    0
+#define ADV7183_16BIT_OUT   1
+
+#endif
diff --git a/include/media/i2c/adv7343.h b/include/media/i2c/adv7343.h
new file mode 100644 (file)
index 0000000..e4142b1
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * ADV7343 header file
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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.
+ */
+
+#ifndef ADV7343_H
+#define ADV7343_H
+
+#define ADV7343_COMPOSITE_ID   (0)
+#define ADV7343_COMPONENT_ID   (1)
+#define ADV7343_SVIDEO_ID      (2)
+
+/**
+ * adv7343_power_mode - power mode configuration.
+ * @sleep_mode: on enable the current consumption is reduced to micro ampere
+ *             level. All DACs and the internal PLL circuit are disabled.
+ *             Registers can be read from and written in sleep mode.
+ * @pll_control: PLL and oversampling control. This control allows internal
+ *              PLL 1 circuit to be powered down and the oversampling to be
+ *              switched off.
+ * @dac: array to configure power on/off DAC's 1..6
+ *
+ * Power mode register (Register 0x0), for more info refer REGISTER MAP ACCESS
+ * section of datasheet[1], table 17 page no 30.
+ *
+ * [1] http://www.analog.com/static/imported-files/data_sheets/ADV7342_7343.pdf
+ */
+struct adv7343_power_mode {
+       bool sleep_mode;
+       bool pll_control;
+       u32 dac[6];
+};
+
+/**
+ * struct adv7343_sd_config - SD Only Output Configuration.
+ * @sd_dac_out: array configuring SD DAC Outputs 1 and 2
+ */
+struct adv7343_sd_config {
+       /* SD only Output Configuration */
+       u32 sd_dac_out[2];
+};
+
+/**
+ * struct adv7343_platform_data - Platform data values and access functions.
+ * @mode_config: Configuration for power mode.
+ * @sd_config: SD Only Configuration.
+ */
+struct adv7343_platform_data {
+       struct adv7343_power_mode mode_config;
+       struct adv7343_sd_config sd_config;
+};
+
+#endif                         /* End of #ifndef ADV7343_H */
diff --git a/include/media/i2c/adv7393.h b/include/media/i2c/adv7393.h
new file mode 100644 (file)
index 0000000..b28edf3
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * ADV7393 header file
+ *
+ * Copyright (C) 2010-2012 ADVANSEE - http://www.advansee.com/
+ * Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
+ *
+ * Based on ADV7343 driver,
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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.
+ */
+
+#ifndef ADV7393_H
+#define ADV7393_H
+
+#define ADV7393_COMPOSITE_ID   (0)
+#define ADV7393_COMPONENT_ID   (1)
+#define ADV7393_SVIDEO_ID      (2)
+
+#endif                         /* End of #ifndef ADV7393_H */
diff --git a/include/media/i2c/adv7511.h b/include/media/i2c/adv7511.h
new file mode 100644 (file)
index 0000000..d83b91d
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Analog Devices ADV7511 HDMI Transmitter Device Driver
+ *
+ * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef ADV7511_H
+#define ADV7511_H
+
+/* notify events */
+#define ADV7511_MONITOR_DETECT 0
+#define ADV7511_EDID_DETECT 1
+
+
+struct adv7511_monitor_detect {
+       int present;
+};
+
+struct adv7511_edid_detect {
+       int present;
+       int segment;
+};
+
+struct adv7511_cec_arg {
+       void *arg;
+       u32 f_flags;
+};
+
+struct adv7511_platform_data {
+       u8 i2c_edid;
+       u8 i2c_cec;
+       u8 i2c_pktmem;
+       u32 cec_clk;
+};
+
+#endif
diff --git a/include/media/i2c/adv7604.h b/include/media/i2c/adv7604.h
new file mode 100644 (file)
index 0000000..a913859
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * adv7604 - Analog Devices ADV7604 video decoder driver
+ *
+ * Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _ADV7604_
+#define _ADV7604_
+
+#include <linux/types.h>
+
+/* Analog input muxing modes (AFE register 0x02, [2:0]) */
+enum adv7604_ain_sel {
+       ADV7604_AIN1_2_3_NC_SYNC_1_2 = 0,
+       ADV7604_AIN4_5_6_NC_SYNC_2_1 = 1,
+       ADV7604_AIN7_8_9_NC_SYNC_3_1 = 2,
+       ADV7604_AIN10_11_12_NC_SYNC_4_1 = 3,
+       ADV7604_AIN9_4_5_6_SYNC_2_1 = 4,
+};
+
+/*
+ * Bus rotation and reordering. This is used to specify component reordering on
+ * the board and describes the components order on the bus when the ADV7604
+ * outputs RGB.
+ */
+enum adv7604_bus_order {
+       ADV7604_BUS_ORDER_RGB,          /* No operation */
+       ADV7604_BUS_ORDER_GRB,          /* Swap 1-2     */
+       ADV7604_BUS_ORDER_RBG,          /* Swap 2-3     */
+       ADV7604_BUS_ORDER_BGR,          /* Swap 1-3     */
+       ADV7604_BUS_ORDER_BRG,          /* Rotate right */
+       ADV7604_BUS_ORDER_GBR,          /* Rotate left  */
+};
+
+/* Input Color Space (IO register 0x02, [7:4]) */
+enum adv76xx_inp_color_space {
+       ADV76XX_INP_COLOR_SPACE_LIM_RGB = 0,
+       ADV76XX_INP_COLOR_SPACE_FULL_RGB = 1,
+       ADV76XX_INP_COLOR_SPACE_LIM_YCbCr_601 = 2,
+       ADV76XX_INP_COLOR_SPACE_LIM_YCbCr_709 = 3,
+       ADV76XX_INP_COLOR_SPACE_XVYCC_601 = 4,
+       ADV76XX_INP_COLOR_SPACE_XVYCC_709 = 5,
+       ADV76XX_INP_COLOR_SPACE_FULL_YCbCr_601 = 6,
+       ADV76XX_INP_COLOR_SPACE_FULL_YCbCr_709 = 7,
+       ADV76XX_INP_COLOR_SPACE_AUTO = 0xf,
+};
+
+/* Select output format (IO register 0x03, [4:2]) */
+enum adv7604_op_format_mode_sel {
+       ADV7604_OP_FORMAT_MODE0 = 0x00,
+       ADV7604_OP_FORMAT_MODE1 = 0x04,
+       ADV7604_OP_FORMAT_MODE2 = 0x08,
+};
+
+enum adv76xx_drive_strength {
+       ADV76XX_DR_STR_MEDIUM_LOW = 1,
+       ADV76XX_DR_STR_MEDIUM_HIGH = 2,
+       ADV76XX_DR_STR_HIGH = 3,
+};
+
+/* INT1 Configuration (IO register 0x40, [1:0]) */
+enum adv76xx_int1_config {
+       ADV76XX_INT1_CONFIG_OPEN_DRAIN,
+       ADV76XX_INT1_CONFIG_ACTIVE_LOW,
+       ADV76XX_INT1_CONFIG_ACTIVE_HIGH,
+       ADV76XX_INT1_CONFIG_DISABLED,
+};
+
+enum adv76xx_page {
+       ADV76XX_PAGE_IO,
+       ADV7604_PAGE_AVLINK,
+       ADV76XX_PAGE_CEC,
+       ADV76XX_PAGE_INFOFRAME,
+       ADV7604_PAGE_ESDP,
+       ADV7604_PAGE_DPP,
+       ADV76XX_PAGE_AFE,
+       ADV76XX_PAGE_REP,
+       ADV76XX_PAGE_EDID,
+       ADV76XX_PAGE_HDMI,
+       ADV76XX_PAGE_TEST,
+       ADV76XX_PAGE_CP,
+       ADV7604_PAGE_VDP,
+       ADV76XX_PAGE_MAX,
+};
+
+/* Platform dependent definition */
+struct adv76xx_platform_data {
+       /* DIS_PWRDNB: 1 if the PWRDNB pin is unused and unconnected */
+       unsigned disable_pwrdnb:1;
+
+       /* DIS_CABLE_DET_RST: 1 if the 5V pins are unused and unconnected */
+       unsigned disable_cable_det_rst:1;
+
+       int default_input;
+
+       /* Analog input muxing mode */
+       enum adv7604_ain_sel ain_sel;
+
+       /* Bus rotation and reordering */
+       enum adv7604_bus_order bus_order;
+
+       /* Select output format mode */
+       enum adv7604_op_format_mode_sel op_format_mode_sel;
+
+       /* Configuration of the INT1 pin */
+       enum adv76xx_int1_config int1_config;
+
+       /* IO register 0x02 */
+       unsigned alt_gamma:1;
+       unsigned op_656_range:1;
+       unsigned alt_data_sat:1;
+
+       /* IO register 0x05 */
+       unsigned blank_data:1;
+       unsigned insert_av_codes:1;
+       unsigned replicate_av_codes:1;
+
+       /* IO register 0x06 */
+       unsigned inv_vs_pol:1;
+       unsigned inv_hs_pol:1;
+       unsigned inv_llc_pol:1;
+
+       /* IO register 0x14 */
+       enum adv76xx_drive_strength dr_str_data;
+       enum adv76xx_drive_strength dr_str_clk;
+       enum adv76xx_drive_strength dr_str_sync;
+
+       /* IO register 0x30 */
+       unsigned output_bus_lsb_to_msb:1;
+
+       /* Free run */
+       unsigned hdmi_free_run_mode;
+
+       /* i2c addresses: 0 == use default */
+       u8 i2c_addresses[ADV76XX_PAGE_MAX];
+};
+
+enum adv76xx_pad {
+       ADV76XX_PAD_HDMI_PORT_A = 0,
+       ADV7604_PAD_HDMI_PORT_B = 1,
+       ADV7604_PAD_HDMI_PORT_C = 2,
+       ADV7604_PAD_HDMI_PORT_D = 3,
+       ADV7604_PAD_VGA_RGB = 4,
+       ADV7604_PAD_VGA_COMP = 5,
+       /* The source pad is either 1 (ADV7611) or 6 (ADV7604) */
+       ADV7604_PAD_SOURCE = 6,
+       ADV7611_PAD_SOURCE = 1,
+       ADV76XX_PAD_MAX = 7,
+};
+
+#define V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE  (V4L2_CID_DV_CLASS_BASE + 0x1000)
+#define V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL  (V4L2_CID_DV_CLASS_BASE + 0x1001)
+#define V4L2_CID_ADV_RX_FREE_RUN_COLOR         (V4L2_CID_DV_CLASS_BASE + 0x1002)
+
+/* notify events */
+#define ADV76XX_HOTPLUG                1
+
+#endif
diff --git a/include/media/i2c/adv7842.h b/include/media/i2c/adv7842.h
new file mode 100644 (file)
index 0000000..bc24970
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * adv7842 - Analog Devices ADV7842 video decoder driver
+ *
+ * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _ADV7842_
+#define _ADV7842_
+
+/* Analog input muxing modes (AFE register 0x02, [2:0]) */
+enum adv7842_ain_sel {
+       ADV7842_AIN1_2_3_NC_SYNC_1_2 = 0,
+       ADV7842_AIN4_5_6_NC_SYNC_2_1 = 1,
+       ADV7842_AIN7_8_9_NC_SYNC_3_1 = 2,
+       ADV7842_AIN10_11_12_NC_SYNC_4_1 = 3,
+       ADV7842_AIN9_4_5_6_SYNC_2_1 = 4,
+};
+
+/*
+ * Bus rotation and reordering. This is used to specify component reordering on
+ * the board and describes the components order on the bus when the ADV7842
+ * outputs RGB.
+ */
+enum adv7842_bus_order {
+       ADV7842_BUS_ORDER_RGB,          /* No operation */
+       ADV7842_BUS_ORDER_GRB,          /* Swap 1-2     */
+       ADV7842_BUS_ORDER_RBG,          /* Swap 2-3     */
+       ADV7842_BUS_ORDER_BGR,          /* Swap 1-3     */
+       ADV7842_BUS_ORDER_BRG,          /* Rotate right */
+       ADV7842_BUS_ORDER_GBR,          /* Rotate left  */
+};
+
+/* Input Color Space (IO register 0x02, [7:4]) */
+enum adv7842_inp_color_space {
+       ADV7842_INP_COLOR_SPACE_LIM_RGB = 0,
+       ADV7842_INP_COLOR_SPACE_FULL_RGB = 1,
+       ADV7842_INP_COLOR_SPACE_LIM_YCbCr_601 = 2,
+       ADV7842_INP_COLOR_SPACE_LIM_YCbCr_709 = 3,
+       ADV7842_INP_COLOR_SPACE_XVYCC_601 = 4,
+       ADV7842_INP_COLOR_SPACE_XVYCC_709 = 5,
+       ADV7842_INP_COLOR_SPACE_FULL_YCbCr_601 = 6,
+       ADV7842_INP_COLOR_SPACE_FULL_YCbCr_709 = 7,
+       ADV7842_INP_COLOR_SPACE_AUTO = 0xf,
+};
+
+/* Select output format (IO register 0x03, [4:2]) */
+enum adv7842_op_format_mode_sel {
+       ADV7842_OP_FORMAT_MODE0 = 0x00,
+       ADV7842_OP_FORMAT_MODE1 = 0x04,
+       ADV7842_OP_FORMAT_MODE2 = 0x08,
+};
+
+/* Mode of operation */
+enum adv7842_mode {
+       ADV7842_MODE_SDP,
+       ADV7842_MODE_COMP,
+       ADV7842_MODE_RGB,
+       ADV7842_MODE_HDMI
+};
+
+/* Video standard select (IO register 0x00, [5:0]) */
+enum adv7842_vid_std_select {
+       /* SDP */
+       ADV7842_SDP_VID_STD_CVBS_SD_4x1 = 0x01,
+       ADV7842_SDP_VID_STD_YC_SD4_x1 = 0x09,
+       /* RGB */
+       ADV7842_RGB_VID_STD_AUTO_GRAPH_MODE = 0x07,
+       /* HDMI GR */
+       ADV7842_HDMI_GR_VID_STD_AUTO_GRAPH_MODE = 0x02,
+       /* HDMI COMP */
+       ADV7842_HDMI_COMP_VID_STD_HD_1250P = 0x1e,
+};
+
+enum adv7842_select_input {
+       ADV7842_SELECT_HDMI_PORT_A,
+       ADV7842_SELECT_HDMI_PORT_B,
+       ADV7842_SELECT_VGA_RGB,
+       ADV7842_SELECT_VGA_COMP,
+       ADV7842_SELECT_SDP_CVBS,
+       ADV7842_SELECT_SDP_YC,
+};
+
+enum adv7842_drive_strength {
+       ADV7842_DR_STR_LOW = 0,
+       ADV7842_DR_STR_MEDIUM_LOW = 1,
+       ADV7842_DR_STR_MEDIUM_HIGH = 2,
+       ADV7842_DR_STR_HIGH = 3,
+};
+
+struct adv7842_sdp_csc_coeff {
+       bool manual;
+       u16 scaling;
+       u16 A1;
+       u16 A2;
+       u16 A3;
+       u16 A4;
+       u16 B1;
+       u16 B2;
+       u16 B3;
+       u16 B4;
+       u16 C1;
+       u16 C2;
+       u16 C3;
+       u16 C4;
+};
+
+struct adv7842_sdp_io_sync_adjustment {
+       bool adjust;
+       u16 hs_beg;
+       u16 hs_width;
+       u16 de_beg;
+       u16 de_end;
+       u8 vs_beg_o;
+       u8 vs_beg_e;
+       u8 vs_end_o;
+       u8 vs_end_e;
+       u8 de_v_beg_o;
+       u8 de_v_beg_e;
+       u8 de_v_end_o;
+       u8 de_v_end_e;
+};
+
+/* Platform dependent definition */
+struct adv7842_platform_data {
+       /* chip reset during probe */
+       unsigned chip_reset:1;
+
+       /* DIS_PWRDNB: 1 if the PWRDNB pin is unused and unconnected */
+       unsigned disable_pwrdnb:1;
+
+       /* DIS_CABLE_DET_RST: 1 if the 5V pins are unused and unconnected */
+       unsigned disable_cable_det_rst:1;
+
+       /* Analog input muxing mode */
+       enum adv7842_ain_sel ain_sel;
+
+       /* Bus rotation and reordering */
+       enum adv7842_bus_order bus_order;
+
+       /* Select output format mode */
+       enum adv7842_op_format_mode_sel op_format_mode_sel;
+
+       /* Default mode */
+       enum adv7842_mode mode;
+
+       /* Default input */
+       unsigned input;
+
+       /* Video standard */
+       enum adv7842_vid_std_select vid_std_select;
+
+       /* IO register 0x02 */
+       unsigned alt_gamma:1;
+       unsigned op_656_range:1;
+       unsigned alt_data_sat:1;
+
+       /* IO register 0x05 */
+       unsigned blank_data:1;
+       unsigned insert_av_codes:1;
+       unsigned replicate_av_codes:1;
+
+       /* IO register 0x30 */
+       unsigned output_bus_lsb_to_msb:1;
+
+       /* IO register 0x14 */
+       enum adv7842_drive_strength dr_str_data;
+       enum adv7842_drive_strength dr_str_clk;
+       enum adv7842_drive_strength dr_str_sync;
+
+       /*
+        * IO register 0x19: Adjustment to the LLC DLL phase in
+        * increments of 1/32 of a clock period.
+        */
+       unsigned llc_dll_phase:5;
+
+       /* External RAM for 3-D comb or frame synchronizer */
+       unsigned sd_ram_size; /* ram size in MB */
+       unsigned sd_ram_ddr:1; /* ddr or sdr sdram */
+
+       /* HDMI free run, CP-reg 0xBA */
+       unsigned hdmi_free_run_enable:1;
+       /* 0 = Mode 0: run when there is no TMDS clock
+          1 = Mode 1: run when there is no TMDS clock or the
+              video resolution does not match programmed one. */
+       unsigned hdmi_free_run_mode:1;
+
+       /* SDP free run, CP-reg 0xDD */
+       unsigned sdp_free_run_auto:1;
+       unsigned sdp_free_run_man_col_en:1;
+       unsigned sdp_free_run_cbar_en:1;
+       unsigned sdp_free_run_force:1;
+
+       /* HPA manual (0) or auto (1), affects HDMI register 0x69 */
+       unsigned hpa_auto:1;
+
+       struct adv7842_sdp_csc_coeff sdp_csc_coeff;
+
+       struct adv7842_sdp_io_sync_adjustment sdp_io_sync_625;
+       struct adv7842_sdp_io_sync_adjustment sdp_io_sync_525;
+
+       /* i2c addresses */
+       u8 i2c_sdp_io;
+       u8 i2c_sdp;
+       u8 i2c_cp;
+       u8 i2c_vdp;
+       u8 i2c_afe;
+       u8 i2c_hdmi;
+       u8 i2c_repeater;
+       u8 i2c_edid;
+       u8 i2c_infoframe;
+       u8 i2c_cec;
+       u8 i2c_avlink;
+};
+
+#define V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE  (V4L2_CID_DV_CLASS_BASE + 0x1000)
+#define V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL  (V4L2_CID_DV_CLASS_BASE + 0x1001)
+#define V4L2_CID_ADV_RX_FREE_RUN_COLOR         (V4L2_CID_DV_CLASS_BASE + 0x1002)
+
+/* custom ioctl, used to test the external RAM that's used by the
+ * deinterlacer. */
+#define ADV7842_CMD_RAM_TEST _IO('V', BASE_VIDIOC_PRIVATE)
+
+#define ADV7842_EDID_PORT_A   0
+#define ADV7842_EDID_PORT_B   1
+#define ADV7842_EDID_PORT_VGA 2
+#define ADV7842_PAD_SOURCE    3
+
+#endif
diff --git a/include/media/i2c/ak881x.h b/include/media/i2c/ak881x.h
new file mode 100644 (file)
index 0000000..b7f2add
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Header for AK8813 / AK8814 TV-ecoders from Asahi Kasei Microsystems Co., Ltd. (AKM)
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.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.
+ */
+
+#ifndef AK881X_H
+#define AK881X_H
+
+#define AK881X_IF_MODE_MASK    (3 << 0)
+#define AK881X_IF_MODE_BT656   (0 << 0)
+#define AK881X_IF_MODE_MASTER  (1 << 0)
+#define AK881X_IF_MODE_SLAVE   (2 << 0)
+#define AK881X_FIELD           (1 << 2)
+#define AK881X_COMPONENT       (1 << 3)
+
+struct ak881x_pdata {
+       unsigned long flags;
+};
+
+#endif
diff --git a/include/media/i2c/as3645a.h b/include/media/i2c/as3645a.h
new file mode 100644 (file)
index 0000000..0e07484
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * include/media/i2c/as3645a.h
+ *
+ * Copyright (C) 2008-2011 Nokia Corporation
+ *
+ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __AS3645A_H__
+#define __AS3645A_H__
+
+#include <media/v4l2-subdev.h>
+
+#define AS3645A_NAME                           "as3645a"
+#define AS3645A_I2C_ADDR                       (0x60 >> 1) /* W:0x60, R:0x61 */
+
+#define AS3645A_FLASH_TIMEOUT_MIN              100000  /* us */
+#define AS3645A_FLASH_TIMEOUT_MAX              850000
+#define AS3645A_FLASH_TIMEOUT_STEP             50000
+
+#define AS3645A_FLASH_INTENSITY_MIN            200     /* mA */
+#define AS3645A_FLASH_INTENSITY_MAX_1LED       500
+#define AS3645A_FLASH_INTENSITY_MAX_2LEDS      400
+#define AS3645A_FLASH_INTENSITY_STEP           20
+
+#define AS3645A_TORCH_INTENSITY_MIN            20      /* mA */
+#define AS3645A_TORCH_INTENSITY_MAX            160
+#define AS3645A_TORCH_INTENSITY_STEP           20
+
+#define AS3645A_INDICATOR_INTENSITY_MIN                0       /* uA */
+#define AS3645A_INDICATOR_INTENSITY_MAX                10000
+#define AS3645A_INDICATOR_INTENSITY_STEP       2500
+
+/*
+ * as3645a_platform_data - Flash controller platform data
+ * @set_power: Set power callback
+ * @vref:      VREF offset (0=0V, 1=+0.3V, 2=-0.3V, 3=+0.6V)
+ * @peak:      Inductor peak current limit (0=1.25A, 1=1.5A, 2=1.75A, 3=2.0A)
+ * @ext_strobe:        True if external flash strobe can be used
+ * @flash_max_current: Max flash current (mA, <= AS3645A_FLASH_INTENSITY_MAX)
+ * @torch_max_current: Max torch current (mA, >= AS3645A_TORCH_INTENSITY_MAX)
+ * @timeout_max:       Max flash timeout (us, <= AS3645A_FLASH_TIMEOUT_MAX)
+ */
+struct as3645a_platform_data {
+       int (*set_power)(struct v4l2_subdev *subdev, int on);
+       unsigned int vref;
+       unsigned int peak;
+       bool ext_strobe;
+
+       /* Flash and torch currents and timeout limits */
+       unsigned int flash_max_current;
+       unsigned int torch_max_current;
+       unsigned int timeout_max;
+};
+
+#endif /* __AS3645A_H__ */
diff --git a/include/media/i2c/bt819.h b/include/media/i2c/bt819.h
new file mode 100644 (file)
index 0000000..8025f4b
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+    bt819.h - bt819 notifications
+
+    Copyright (C) 2009 Hans Verkuil (hverkuil@xs4all.nl)
+
+    This program is 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 _BT819_H_
+#define _BT819_H_
+
+#include <linux/ioctl.h>
+
+/* v4l2_device notifications. */
+
+/* Needed to reset the FIFO buffer when changing the input
+   or the video standard.
+
+   Note: these ioctls that internal to the kernel and are never called
+   from userspace. */
+#define BT819_FIFO_RESET_LOW   _IO('b', 0)
+#define BT819_FIFO_RESET_HIGH  _IO('b', 1)
+
+#endif
diff --git a/include/media/i2c/cs5345.h b/include/media/i2c/cs5345.h
new file mode 100644 (file)
index 0000000..6ccae24
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+    cs5345.h - definition for cs5345 inputs and outputs
+
+    Copyright (C) 2007 Hans Verkuil (hverkuil@xs4all.nl)
+
+    This program is 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 _CS5345_H_
+#define _CS5345_H_
+
+/* CS5345 HW inputs */
+#define CS5345_IN_MIC 0
+#define CS5345_IN_1   1
+#define CS5345_IN_2   2
+#define CS5345_IN_3   3
+#define CS5345_IN_4   4
+#define CS5345_IN_5   5
+#define CS5345_IN_6   6
+
+#define CS5345_MCLK_1   0x00
+#define CS5345_MCLK_1_5 0x10
+#define CS5345_MCLK_2   0x20
+#define CS5345_MCLK_3   0x30
+#define CS5345_MCLK_4   0x40
+
+#endif
diff --git a/include/media/i2c/cs53l32a.h b/include/media/i2c/cs53l32a.h
new file mode 100644 (file)
index 0000000..bf76197
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+    cs53l32a.h - definition for cs53l32a inputs and outputs
+
+    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
+
+    This program is 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 _CS53L32A_H_
+#define _CS53L32A_H_
+
+/* There are 2 physical inputs, but the second input can be
+   placed in two modes, the first mode bypasses the PGA (gain),
+   the second goes through the PGA. Hence there are three
+   possible inputs to choose from. */
+
+/* CS53L32A HW inputs */
+#define CS53L32A_IN0 0
+#define CS53L32A_IN1 1
+#define CS53L32A_IN2 2
+
+#endif
diff --git a/include/media/i2c/ir-kbd-i2c.h b/include/media/i2c/ir-kbd-i2c.h
new file mode 100644 (file)
index 0000000..d856435
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef _IR_I2C
+#define _IR_I2C
+
+#include <media/rc-core.h>
+
+#define DEFAULT_POLLING_INTERVAL       100     /* ms */
+
+struct IR_i2c;
+
+struct IR_i2c {
+       char                   *ir_codes;
+       struct i2c_client      *c;
+       struct rc_dev          *rc;
+
+       /* Used to avoid fast repeating */
+       unsigned char          old;
+
+       u32                    polling_interval; /* in ms */
+
+       struct delayed_work    work;
+       char                   name[32];
+       char                   phys[32];
+       int                    (*get_key)(struct IR_i2c *ir, enum rc_type *protocol,
+                                         u32 *scancode, u8 *toggle);
+};
+
+enum ir_kbd_get_key_fn {
+       IR_KBD_GET_KEY_CUSTOM = 0,
+       IR_KBD_GET_KEY_PIXELVIEW,
+       IR_KBD_GET_KEY_HAUP,
+       IR_KBD_GET_KEY_KNC1,
+       IR_KBD_GET_KEY_FUSIONHDTV,
+       IR_KBD_GET_KEY_HAUP_XVR,
+       IR_KBD_GET_KEY_AVERMEDIA_CARDBUS,
+};
+
+/* Can be passed when instantiating an ir_video i2c device */
+struct IR_i2c_init_data {
+       char                    *ir_codes;
+       const char              *name;
+       u64                     type; /* RC_BIT_RC5, etc */
+       u32                     polling_interval; /* 0 means DEFAULT_POLLING_INTERVAL */
+
+       /*
+        * Specify either a function pointer or a value indicating one of
+        * ir_kbd_i2c's internal get_key functions
+        */
+       int                    (*get_key)(struct IR_i2c *ir, enum rc_type *protocol,
+                                         u32 *scancode, u8 *toggle);
+       enum ir_kbd_get_key_fn internal_get_key_func;
+
+       struct rc_dev           *rc_dev;
+};
+#endif
diff --git a/include/media/i2c/lm3560.h b/include/media/i2c/lm3560.h
new file mode 100644 (file)
index 0000000..5ed942a
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * include/media/i2c/lm3560.h
+ *
+ * Copyright (C) 2013 Texas Instruments
+ *
+ * Contact: Daniel Jeong <gshark.jeong@gmail.com>
+ *                     Ldd-Mlp <ldd-mlp@list.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.
+ *
+ * You 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__
+#define __LM3560_H__
+
+#include <media/v4l2-subdev.h>
+
+#define LM3560_NAME    "lm3560"
+#define LM3560_I2C_ADDR        (0x53)
+
+/*  FLASH Brightness
+ *     min 62500uA, step 62500uA, max 1000000uA
+ */
+#define LM3560_FLASH_BRT_MIN 62500
+#define LM3560_FLASH_BRT_STEP 62500
+#define LM3560_FLASH_BRT_MAX 1000000
+#define LM3560_FLASH_BRT_uA_TO_REG(a)  \
+       ((a) < LM3560_FLASH_BRT_MIN ? 0 :       \
+        (((a) - LM3560_FLASH_BRT_MIN) / LM3560_FLASH_BRT_STEP))
+#define LM3560_FLASH_BRT_REG_TO_uA(a)          \
+       ((a) * LM3560_FLASH_BRT_STEP + LM3560_FLASH_BRT_MIN)
+
+/*  FLASH TIMEOUT DURATION
+ *     min 32ms, step 32ms, max 1024ms
+ */
+#define LM3560_FLASH_TOUT_MIN 32
+#define LM3560_FLASH_TOUT_STEP 32
+#define LM3560_FLASH_TOUT_MAX 1024
+#define LM3560_FLASH_TOUT_ms_TO_REG(a) \
+       ((a) < LM3560_FLASH_TOUT_MIN ? 0 :      \
+        (((a) - LM3560_FLASH_TOUT_MIN) / LM3560_FLASH_TOUT_STEP))
+#define LM3560_FLASH_TOUT_REG_TO_ms(a)         \
+       ((a) * LM3560_FLASH_TOUT_STEP + LM3560_FLASH_TOUT_MIN)
+
+/*  TORCH BRT
+ *     min 31250uA, step 31250uA, max 250000uA
+ */
+#define LM3560_TORCH_BRT_MIN 31250
+#define LM3560_TORCH_BRT_STEP 31250
+#define LM3560_TORCH_BRT_MAX 250000
+#define LM3560_TORCH_BRT_uA_TO_REG(a)  \
+       ((a) < LM3560_TORCH_BRT_MIN ? 0 :       \
+        (((a) - LM3560_TORCH_BRT_MIN) / LM3560_TORCH_BRT_STEP))
+#define LM3560_TORCH_BRT_REG_TO_uA(a)          \
+       ((a) * LM3560_TORCH_BRT_STEP + LM3560_TORCH_BRT_MIN)
+
+enum lm3560_led_id {
+       LM3560_LED0 = 0,
+       LM3560_LED1,
+       LM3560_LED_MAX
+};
+
+enum lm3560_peak_current {
+       LM3560_PEAK_1600mA = 0x00,
+       LM3560_PEAK_2300mA = 0x20,
+       LM3560_PEAK_3000mA = 0x40,
+       LM3560_PEAK_3600mA = 0x60
+};
+
+/* struct lm3560_platform_data
+ *
+ * @peak :  peak current
+ * @max_flash_timeout: flash timeout
+ * @max_flash_brt: flash mode led brightness
+ * @max_torch_brt: torch mode led brightness
+ */
+struct lm3560_platform_data {
+       enum lm3560_peak_current peak;
+
+       u32 max_flash_timeout;
+       u32 max_flash_brt[LM3560_LED_MAX];
+       u32 max_torch_brt[LM3560_LED_MAX];
+};
+
+#endif /* __LM3560_H__ */
diff --git a/include/media/i2c/lm3646.h b/include/media/i2c/lm3646.h
new file mode 100644 (file)
index 0000000..724c100
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * include/media/i2c/lm3646.h
+ *
+ * Copyright (C) 2014 Texas Instruments
+ *
+ * Contact: Daniel Jeong <gshark.jeong@gmail.com>
+ *                     Ldd-Mlp <ldd-mlp@list.ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef __LM3646_H__
+#define __LM3646_H__
+
+#include <media/v4l2-subdev.h>
+
+#define LM3646_NAME    "lm3646"
+#define LM3646_I2C_ADDR_REV1   (0x67)
+#define LM3646_I2C_ADDR_REV0   (0x63)
+
+/*  TOTAL FLASH Brightness Max
+ *     min 93350uA, step 93750uA, max 1499600uA
+ */
+#define LM3646_TOTAL_FLASH_BRT_MIN 93350
+#define LM3646_TOTAL_FLASH_BRT_STEP 93750
+#define LM3646_TOTAL_FLASH_BRT_MAX 1499600
+#define LM3646_TOTAL_FLASH_BRT_uA_TO_REG(a)    \
+       ((a) < LM3646_TOTAL_FLASH_BRT_MIN ? 0 : \
+        ((((a) - LM3646_TOTAL_FLASH_BRT_MIN) / LM3646_TOTAL_FLASH_BRT_STEP)))
+
+/*  TOTAL TORCH Brightness Max
+ *     min 23040uA, step 23430uA, max 187100uA
+ */
+#define LM3646_TOTAL_TORCH_BRT_MIN 23040
+#define LM3646_TOTAL_TORCH_BRT_STEP 23430
+#define LM3646_TOTAL_TORCH_BRT_MAX 187100
+#define LM3646_TOTAL_TORCH_BRT_uA_TO_REG(a)    \
+       ((a) < LM3646_TOTAL_TORCH_BRT_MIN ? 0 : \
+        ((((a) - LM3646_TOTAL_TORCH_BRT_MIN) / LM3646_TOTAL_TORCH_BRT_STEP)))
+
+/*  LED1 FLASH Brightness
+ *     min 23040uA, step 11718uA, max 1499600uA
+ */
+#define LM3646_LED1_FLASH_BRT_MIN 23040
+#define LM3646_LED1_FLASH_BRT_STEP 11718
+#define LM3646_LED1_FLASH_BRT_MAX 1499600
+#define LM3646_LED1_FLASH_BRT_uA_TO_REG(a)     \
+       ((a) <= LM3646_LED1_FLASH_BRT_MIN ? 0 : \
+        ((((a) - LM3646_LED1_FLASH_BRT_MIN) / LM3646_LED1_FLASH_BRT_STEP))+1)
+
+/*  LED1 TORCH Brightness
+ *     min 2530uA, step 1460uA, max 187100uA
+ */
+#define LM3646_LED1_TORCH_BRT_MIN 2530
+#define LM3646_LED1_TORCH_BRT_STEP 1460
+#define LM3646_LED1_TORCH_BRT_MAX 187100
+#define LM3646_LED1_TORCH_BRT_uA_TO_REG(a)     \
+       ((a) <= LM3646_LED1_TORCH_BRT_MIN ? 0 : \
+        ((((a) - LM3646_LED1_TORCH_BRT_MIN) / LM3646_LED1_TORCH_BRT_STEP))+1)
+
+/*  FLASH TIMEOUT DURATION
+ *     min 50ms, step 50ms, max 400ms
+ */
+#define LM3646_FLASH_TOUT_MIN 50
+#define LM3646_FLASH_TOUT_STEP 50
+#define LM3646_FLASH_TOUT_MAX 400
+#define LM3646_FLASH_TOUT_ms_TO_REG(a) \
+       ((a) <= LM3646_FLASH_TOUT_MIN ? 0 :     \
+        (((a) - LM3646_FLASH_TOUT_MIN) / LM3646_FLASH_TOUT_STEP))
+
+/* struct lm3646_platform_data
+ *
+ * @flash_timeout: flash timeout
+ * @led1_flash_brt: led1 flash mode brightness, uA
+ * @led1_torch_brt: led1 torch mode brightness, uA
+ */
+struct lm3646_platform_data {
+
+       u32 flash_timeout;
+
+       u32 led1_flash_brt;
+       u32 led1_torch_brt;
+};
+
+#endif /* __LM3646_H__ */
diff --git a/include/media/i2c/m52790.h b/include/media/i2c/m52790.h
new file mode 100644 (file)
index 0000000..7ddffae
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+    m52790.h - definition for m52790 inputs and outputs
+
+    Copyright (C) 2007 Hans Verkuil (hverkuil@xs4all.nl)
+
+    This program is 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 _M52790_H_
+#define _M52790_H_
+
+/* Input routing switch 1 */
+
+#define M52790_SW1_IN_MASK     0x0003
+#define M52790_SW1_IN_TUNER    0x0000
+#define M52790_SW1_IN_V2       0x0001
+#define M52790_SW1_IN_V3       0x0002
+#define M52790_SW1_IN_V4       0x0003
+
+/* Selects component input instead of composite */
+#define M52790_SW1_YCMIX       0x0004
+
+
+/* Input routing switch 2 */
+
+#define M52790_SW2_IN_MASK     0x0300
+#define M52790_SW2_IN_TUNER    0x0000
+#define M52790_SW2_IN_V2       0x0100
+#define M52790_SW2_IN_V3       0x0200
+#define M52790_SW2_IN_V4       0x0300
+
+/* Selects component input instead of composite */
+#define M52790_SW2_YCMIX       0x0400
+
+
+/* Output routing switch 1 */
+
+/* Enable 6dB amplifier for composite out */
+#define M52790_SW1_V_AMP       0x0008
+
+/* Enable 6dB amplifier for component out */
+#define M52790_SW1_YC_AMP      0x0010
+
+/* Audio output mode */
+#define M52790_SW1_AUDIO_MASK  0x00c0
+#define M52790_SW1_AUDIO_MUTE  0x0000
+#define M52790_SW1_AUDIO_R     0x0040
+#define M52790_SW1_AUDIO_L     0x0080
+#define M52790_SW1_AUDIO_STEREO 0x00c0
+
+
+/* Output routing switch 2 */
+
+/* Enable 6dB amplifier for composite out */
+#define M52790_SW2_V_AMP       0x0800
+
+/* Enable 6dB amplifier for component out */
+#define M52790_SW2_YC_AMP      0x1000
+
+/* Audio output mode */
+#define M52790_SW2_AUDIO_MASK  0xc000
+#define M52790_SW2_AUDIO_MUTE  0x0000
+#define M52790_SW2_AUDIO_R     0x4000
+#define M52790_SW2_AUDIO_L     0x8000
+#define M52790_SW2_AUDIO_STEREO 0xc000
+
+
+/* Common values */
+#define M52790_IN_TUNER (M52790_SW1_IN_TUNER | M52790_SW2_IN_TUNER)
+#define M52790_IN_V2    (M52790_SW1_IN_V2 | M52790_SW2_IN_V2)
+#define M52790_IN_V3    (M52790_SW1_IN_V3 | M52790_SW2_IN_V3)
+#define M52790_IN_V4    (M52790_SW1_IN_V4 | M52790_SW2_IN_V4)
+
+#define M52790_OUT_STEREO      (M52790_SW1_AUDIO_STEREO | \
+                                M52790_SW2_AUDIO_STEREO)
+#define M52790_OUT_AMP_STEREO  (M52790_SW1_AUDIO_STEREO | \
+                                M52790_SW1_V_AMP | \
+                                M52790_SW2_AUDIO_STEREO | \
+                                M52790_SW2_V_AMP)
+
+#endif
diff --git a/include/media/i2c/m5mols.h b/include/media/i2c/m5mols.h
new file mode 100644 (file)
index 0000000..4a825ae
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Driver header for M-5MOLS 8M Pixel camera sensor with ISP
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Author: HeungJun Kim <riverful.kim@samsung.com>
+ *
+ * Copyright (C) 2009 Samsung Electronics Co., Ltd.
+ * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef MEDIA_M5MOLS_H
+#define MEDIA_M5MOLS_H
+
+/**
+ * struct m5mols_platform_data - platform data for M-5MOLS driver
+ * @gpio_reset:        GPIO driving the reset pin of M-5MOLS
+ * @reset_polarity: active state for gpio_reset pin, 0 or 1
+ * @set_power: an additional callback to the board setup code
+ *             to be called after enabling and before disabling
+ *             the sensor's supply regulators
+ */
+struct m5mols_platform_data {
+       int gpio_reset;
+       u8 reset_polarity;
+       int (*set_power)(struct device *dev, int on);
+};
+
+#endif /* MEDIA_M5MOLS_H */
diff --git a/include/media/i2c/mt9m032.h b/include/media/i2c/mt9m032.h
new file mode 100644 (file)
index 0000000..c3a7811
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Driver for MT9M032 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2010-2011 Lund Engineering
+ * Contact: Gil Lund <gwlund@lundeng.com>
+ * Author: Martin Hostettler <martin@neutronstar.dyndns.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MT9M032_H
+#define MT9M032_H
+
+#define MT9M032_NAME           "mt9m032"
+#define MT9M032_I2C_ADDR       (0xb8 >> 1)
+
+struct mt9m032_platform_data {
+       u32 ext_clock;
+       u32 pix_clock;
+       bool invert_pixclock;
+
+};
+#endif /* MT9M032_H */
diff --git a/include/media/i2c/mt9p031.h b/include/media/i2c/mt9p031.h
new file mode 100644 (file)
index 0000000..1ba3612
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef MT9P031_H
+#define MT9P031_H
+
+struct v4l2_subdev;
+
+/*
+ * struct mt9p031_platform_data - MT9P031 platform data
+ * @ext_freq: Input clock frequency
+ * @target_freq: Pixel clock frequency
+ */
+struct mt9p031_platform_data {
+       int ext_freq;
+       int target_freq;
+};
+
+#endif
diff --git a/include/media/i2c/mt9t001.h b/include/media/i2c/mt9t001.h
new file mode 100644 (file)
index 0000000..03fd63e
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _MEDIA_MT9T001_H
+#define _MEDIA_MT9T001_H
+
+struct mt9t001_platform_data {
+       unsigned int clk_pol:1;
+       unsigned int ext_clk;
+};
+
+#endif
diff --git a/include/media/i2c/mt9t112.h b/include/media/i2c/mt9t112.h
new file mode 100644 (file)
index 0000000..a43c74a
--- /dev/null
@@ -0,0 +1,30 @@
+/* mt9t112 Camera
+ *
+ * Copyright (C) 2009 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __MT9T112_H__
+#define __MT9T112_H__
+
+#define MT9T112_FLAG_PCLK_RISING_EDGE  (1 << 0)
+#define MT9T112_FLAG_DATAWIDTH_8       (1 << 1) /* default width is 10 */
+
+struct mt9t112_pll_divider {
+       u8 m, n;
+       u8 p1, p2, p3, p4, p5, p6, p7;
+};
+
+/*
+ * mt9t112 camera info
+ */
+struct mt9t112_camera_info {
+       u32 flags;
+       struct mt9t112_pll_divider divider;
+};
+
+#endif /* __MT9T112_H__ */
diff --git a/include/media/i2c/mt9v011.h b/include/media/i2c/mt9v011.h
new file mode 100644 (file)
index 0000000..ea29fc7
--- /dev/null
@@ -0,0 +1,17 @@
+/* mt9v011 sensor
+ *
+ * Copyright (C) 2011 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * 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 __MT9V011_H__
+#define __MT9V011_H__
+
+struct mt9v011_platform_data {
+       unsigned xtal;  /* Hz */
+};
+
+#endif
diff --git a/include/media/i2c/mt9v022.h b/include/media/i2c/mt9v022.h
new file mode 100644 (file)
index 0000000..4056180
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * mt9v022 sensor
+ *
+ * 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 __MT9V022_H__
+#define __MT9V022_H__
+
+struct mt9v022_platform_data {
+       unsigned short y_skip_top;      /* Lines to skip at the top */
+};
+
+#endif
diff --git a/include/media/i2c/mt9v032.h b/include/media/i2c/mt9v032.h
new file mode 100644 (file)
index 0000000..12175a6
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _MEDIA_MT9V032_H
+#define _MEDIA_MT9V032_H
+
+struct mt9v032_platform_data {
+       unsigned int clk_pol:1;
+
+       const s64 *link_freqs;
+       s64 link_def_freq;
+};
+
+#endif
diff --git a/include/media/i2c/noon010pc30.h b/include/media/i2c/noon010pc30.h
new file mode 100644 (file)
index 0000000..58eafee
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Driver header for NOON010PC30L camera sensor chip.
+ *
+ * Copyright (c) 2010 Samsung Electronics, Co. Ltd
+ * Contact: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef NOON010PC30_H
+#define NOON010PC30_H
+
+/**
+ * @clk_rate: the clock frequency in Hz
+ * @gpio_nreset: GPIO driving nRESET pin
+ * @gpio_nstby: GPIO driving nSTBY pin
+ */
+
+struct noon010pc30_platform_data {
+       unsigned long clk_rate;
+       int gpio_nreset;
+       int gpio_nstby;
+};
+
+#endif /* NOON010PC30_H */
diff --git a/include/media/i2c/ov2659.h b/include/media/i2c/ov2659.h
new file mode 100644 (file)
index 0000000..4216adc
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Omnivision OV2659 CMOS Image Sensor driver
+ *
+ * Copyright (C) 2015 Texas Instruments, Inc.
+ *
+ * Benoit Parrot <bparrot@ti.com>
+ * Lad, Prabhakar <prabhakar.csengg@gmail.com>
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef OV2659_H
+#define OV2659_H
+
+/**
+ * struct ov2659_platform_data - ov2659 driver platform data
+ * @link_frequency: target pixel clock frequency
+ */
+struct ov2659_platform_data {
+       s64 link_frequency;
+};
+
+#endif /* OV2659_H */
diff --git a/include/media/i2c/ov7670.h b/include/media/i2c/ov7670.h
new file mode 100644 (file)
index 0000000..1913d51
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * A V4L2 driver for OmniVision OV7670 cameras.
+ *
+ * Copyright 2010 One Laptop Per Child
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License, version 2.
+ */
+
+#ifndef __OV7670_H
+#define __OV7670_H
+
+struct ov7670_config {
+       int min_width;                  /* Filter out smaller sizes */
+       int min_height;                 /* Filter out smaller sizes */
+       int clock_speed;                /* External clock speed (MHz) */
+       bool use_smbus;                 /* Use smbus I/O instead of I2C */
+       bool pll_bypass;                /* Choose whether to bypass the PLL */
+       bool pclk_hb_disable;           /* Disable toggling pixclk during horizontal blanking */
+};
+
+#endif
diff --git a/include/media/i2c/ov772x.h b/include/media/i2c/ov772x.h
new file mode 100644 (file)
index 0000000..00dbb7c
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * ov772x Camera
+ *
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __OV772X_H__
+#define __OV772X_H__
+
+/* for flags */
+#define OV772X_FLAG_VFLIP      (1 << 0) /* Vertical flip image */
+#define OV772X_FLAG_HFLIP      (1 << 1) /* Horizontal flip image */
+
+/*
+ * for Edge ctrl
+ *
+ * strength also control Auto or Manual Edge Control Mode
+ * see also OV772X_MANUAL_EDGE_CTRL
+ */
+struct ov772x_edge_ctrl {
+       unsigned char strength;
+       unsigned char threshold;
+       unsigned char upper;
+       unsigned char lower;
+};
+
+#define OV772X_MANUAL_EDGE_CTRL                0x80 /* un-used bit of strength */
+#define OV772X_EDGE_STRENGTH_MASK      0x1F
+#define OV772X_EDGE_THRESHOLD_MASK     0x0F
+#define OV772X_EDGE_UPPER_MASK         0xFF
+#define OV772X_EDGE_LOWER_MASK         0xFF
+
+#define OV772X_AUTO_EDGECTRL(u, l)     \
+{                                      \
+       .upper = (u & OV772X_EDGE_UPPER_MASK),  \
+       .lower = (l & OV772X_EDGE_LOWER_MASK),  \
+}
+
+#define OV772X_MANUAL_EDGECTRL(s, t)                   \
+{                                                      \
+       .strength  = (s & OV772X_EDGE_STRENGTH_MASK) |  \
+                       OV772X_MANUAL_EDGE_CTRL,        \
+       .threshold = (t & OV772X_EDGE_THRESHOLD_MASK),  \
+}
+
+/*
+ * ov772x camera info
+ */
+struct ov772x_camera_info {
+       unsigned long           flags;
+       struct ov772x_edge_ctrl edgectrl;
+};
+
+#endif /* __OV772X_H__ */
diff --git a/include/media/i2c/ov9650.h b/include/media/i2c/ov9650.h
new file mode 100644 (file)
index 0000000..d630cf9
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * OV9650/OV9652 camera sensors driver
+ *
+ * Copyright (C) 2013 Sylwester Nawrocki <sylvester.nawrocki@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.
+ */
+#ifndef OV9650_H_
+#define OV9650_H_
+
+/**
+ * struct ov9650_platform_data - ov9650 driver platform data
+ * @mclk_frequency: the sensor's master clock frequency in Hz
+ * @gpio_pwdn:     number of a GPIO connected to OV965X PWDN pin
+ * @gpio_reset:     number of a GPIO connected to OV965X RESET pin
+ *
+ * If any of @gpio_pwdn or @gpio_reset are unused then they should be
+ * set to a negative value. @mclk_frequency must always be specified.
+ */
+struct ov9650_platform_data {
+       unsigned long mclk_frequency;
+       int gpio_pwdn;
+       int gpio_reset;
+};
+#endif /* OV9650_H_ */
diff --git a/include/media/i2c/rj54n1cb0c.h b/include/media/i2c/rj54n1cb0c.h
new file mode 100644 (file)
index 0000000..8ae3288
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * RJ54N1CB0C Private data
+ *
+ * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.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.
+ */
+
+#ifndef __RJ54N1CB0C_H__
+#define __RJ54N1CB0C_H__
+
+struct rj54n1_pdata {
+       unsigned int    mclk_freq;
+       bool            ioctl_high;
+};
+
+#endif
diff --git a/include/media/i2c/s5c73m3.h b/include/media/i2c/s5c73m3.h
new file mode 100644 (file)
index 0000000..ccb9e54
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Samsung LSI S5C73M3 8M pixel camera driver
+ *
+ * Copyright (C) 2012, Samsung Electronics, Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ * Andrzej Hajda <a.hajda@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.
+ *
+ * This program is 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 MEDIA_S5C73M3__
+#define MEDIA_S5C73M3__
+
+#include <linux/videodev2.h>
+#include <media/v4l2-mediabus.h>
+
+/**
+ * struct s5c73m3_gpio - data structure describing a GPIO
+ * @gpio:  GPIO number
+ * @level: indicates active state of the @gpio
+ */
+struct s5c73m3_gpio {
+       int gpio;
+       int level;
+};
+
+/**
+ * struct s5c73m3_platform_data - s5c73m3 driver platform data
+ * @mclk_frequency: sensor's master clock frequency in Hz
+ * @gpio_reset:  GPIO driving RESET pin
+ * @gpio_stby:   GPIO driving STBY pin
+ * @nlanes:      maximum number of MIPI-CSI lanes used
+ * @horiz_flip:  default horizontal image flip value, non zero to enable
+ * @vert_flip:   default vertical image flip value, non zero to enable
+ */
+
+struct s5c73m3_platform_data {
+       unsigned long mclk_frequency;
+
+       struct s5c73m3_gpio gpio_reset;
+       struct s5c73m3_gpio gpio_stby;
+
+       enum v4l2_mbus_type bus_type;
+       u8 nlanes;
+       u8 horiz_flip;
+       u8 vert_flip;
+};
+
+#endif /* MEDIA_S5C73M3__ */
diff --git a/include/media/i2c/s5k4ecgx.h b/include/media/i2c/s5k4ecgx.h
new file mode 100644 (file)
index 0000000..90c1be7
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * S5K4ECGX image sensor header file
+ *
+ * Copyright (C) 2012, Linaro
+ * Copyright (C) 2012, Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef S5K4ECGX_H
+#define S5K4ECGX_H
+
+/**
+ * struct s5k4ecgx_gpio - data structure describing a GPIO
+ * @gpio : GPIO number
+ * @level: indicates active state of the @gpio
+ */
+struct s5k4ecgx_gpio {
+       int gpio;
+       int level;
+};
+
+/**
+ * struct ss5k4ecgx_platform_data- s5k4ecgx driver platform data
+ * @gpio_reset:         GPIO driving RESET pin
+ * @gpio_stby :         GPIO driving STBY pin
+ */
+
+struct s5k4ecgx_platform_data {
+       struct s5k4ecgx_gpio gpio_reset;
+       struct s5k4ecgx_gpio gpio_stby;
+};
+
+#endif /* S5K4ECGX_H */
diff --git a/include/media/i2c/s5k6aa.h b/include/media/i2c/s5k6aa.h
new file mode 100644 (file)
index 0000000..ba34f70
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * S5K6AAFX camera sensor driver header
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef S5K6AA_H
+#define S5K6AA_H
+
+#include <media/v4l2-mediabus.h>
+
+/**
+ * struct s5k6aa_gpio - data structure describing a GPIO
+ * @gpio:  GPIO number
+ * @level: indicates active state of the @gpio
+ */
+struct s5k6aa_gpio {
+       int gpio;
+       int level;
+};
+
+/**
+ * struct s5k6aa_platform_data - s5k6aa driver platform data
+ * @set_power:   an additional callback to the board code, called
+ *               after enabling the regulators and before switching
+ *               the sensor off
+ * @mclk_frequency: sensor's master clock frequency in Hz
+ * @gpio_reset:  GPIO driving RESET pin
+ * @gpio_stby:   GPIO driving STBY pin
+ * @nlanes:      maximum number of MIPI-CSI lanes used
+ * @horiz_flip:  default horizontal image flip value, non zero to enable
+ * @vert_flip:   default vertical image flip value, non zero to enable
+ */
+
+struct s5k6aa_platform_data {
+       int (*set_power)(int enable);
+       unsigned long mclk_frequency;
+       struct s5k6aa_gpio gpio_reset;
+       struct s5k6aa_gpio gpio_stby;
+       enum v4l2_mbus_type bus_type;
+       u8 nlanes;
+       u8 horiz_flip;
+       u8 vert_flip;
+};
+
+#endif /* S5K6AA_H */
diff --git a/include/media/i2c/saa6588.h b/include/media/i2c/saa6588.h
new file mode 100644 (file)
index 0000000..b5ec1aa
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+
+    Types and defines needed for RDS. This is included by
+    saa6588.c and every driver (e.g. bttv-driver.c) that wants
+    to use the saa6588 module.
+
+    (c) 2005 by Hans J. Koch
+
+    This program is 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 _SAA6588_H
+#define _SAA6588_H
+
+struct saa6588_command {
+       unsigned int  block_count;
+       bool          nonblocking;
+       int           result;
+       unsigned char __user *buffer;
+       struct file   *instance;
+       poll_table    *event_list;
+};
+
+/* These ioctls are internal to the kernel */
+#define SAA6588_CMD_CLOSE      _IOW('R', 2, int)
+#define SAA6588_CMD_READ       _IOR('R', 3, int)
+#define SAA6588_CMD_POLL       _IOR('R', 4, int)
+
+#endif
diff --git a/include/media/i2c/saa7115.h b/include/media/i2c/saa7115.h
new file mode 100644 (file)
index 0000000..53954c9
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+    saa7115.h - definition for saa7111/3/4/5 inputs and frequency flags
+
+    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
+
+    This program is 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 _SAA7115_H_
+#define _SAA7115_H_
+
+/* s_routing inputs, outputs, and config */
+
+/* SAA7111/3/4/5 HW inputs */
+#define SAA7115_COMPOSITE0 0
+#define SAA7115_COMPOSITE1 1
+#define SAA7115_COMPOSITE2 2
+#define SAA7115_COMPOSITE3 3
+#define SAA7115_COMPOSITE4 4 /* not available for the saa7111/3 */
+#define SAA7115_COMPOSITE5 5 /* not available for the saa7111/3 */
+#define SAA7115_SVIDEO0    6
+#define SAA7115_SVIDEO1    7
+#define SAA7115_SVIDEO2    8
+#define SAA7115_SVIDEO3    9
+
+/* outputs */
+#define SAA7115_IPORT_ON       1
+#define SAA7115_IPORT_OFF      0
+
+/* SAA7111 specific outputs. */
+#define SAA7111_VBI_BYPASS     2
+#define SAA7111_FMT_YUV422      0x00
+#define SAA7111_FMT_RGB        0x40
+#define SAA7111_FMT_CCIR       0x80
+#define SAA7111_FMT_YUV411     0xc0
+
+/* config flags */
+/*
+ * Register 0x85 should set bit 0 to 0 (it's 1 by default). This bit
+ * controls the IDQ signal polarity which is set to 'inverted' if the bit
+ * it 1 and to 'default' if it is 0.
+ */
+#define SAA7115_IDQ_IS_DEFAULT  (1 << 0)
+
+/* s_crystal_freq values and flags */
+
+/* SAA7115 v4l2_crystal_freq frequency values */
+#define SAA7115_FREQ_32_11_MHZ  32110000   /* 32.11 MHz crystal, SAA7114/5 only */
+#define SAA7115_FREQ_24_576_MHZ 24576000   /* 24.576 MHz crystal */
+
+/* SAA7115 v4l2_crystal_freq audio clock control flags */
+#define SAA7115_FREQ_FL_UCGC         (1 << 0) /* SA 3A[7], UCGC, SAA7115 only */
+#define SAA7115_FREQ_FL_CGCDIV       (1 << 1) /* SA 3A[6], CGCDIV, SAA7115 only */
+#define SAA7115_FREQ_FL_APLL         (1 << 2) /* SA 3A[3], APLL, SAA7114/5 only */
+#define SAA7115_FREQ_FL_DOUBLE_ASCLK (1 << 3) /* SA 39, LRDIV, SAA7114/5 only */
+
+/* ===== SAA7113 Config enums ===== */
+
+/* Register 0x08 "Horizontal time constant" [Bit 3..4]:
+ * Should be set to "Fast Locking Mode" according to the datasheet,
+ * and that is the default setting in the gm7113c_init table.
+ * saa7113_init sets this value to "VTR Mode". */
+enum saa7113_r08_htc {
+       SAA7113_HTC_TV_MODE = 0x00,
+       SAA7113_HTC_VTR_MODE,                   /* Default for saa7113_init */
+       SAA7113_HTC_FAST_LOCKING_MODE = 0x03    /* Default for gm7113c_init */
+};
+
+/* Register 0x10 "Output format selection" [Bit 6..7]:
+ * Defaults to ITU_656 as specified in datasheet. */
+enum saa7113_r10_ofts {
+       SAA7113_OFTS_ITU_656 = 0x0,     /* Default */
+       SAA7113_OFTS_VFLAG_BY_VREF,
+       SAA7113_OFTS_VFLAG_BY_DATA_TYPE
+};
+
+/*
+ * Register 0x12 "Output control" [Bit 0..3 Or Bit 4..7]:
+ * This is used to select what data is output on the RTS0 and RTS1 pins.
+ * RTS1 [Bit 4..7] Defaults to DOT_IN. (This value can not be set for RTS0)
+ * RTS0 [Bit 0..3] Defaults to VIPB in gm7113c_init as specified
+ * in the datasheet, but is set to HREF_HS in the saa7113_init table.
+ */
+enum saa7113_r12_rts {
+       SAA7113_RTS_DOT_IN = 0,         /* OBS: Only for RTS1 (Default RTS1) */
+       SAA7113_RTS_VIPB,               /* Default RTS0 For gm7113c_init */
+       SAA7113_RTS_GPSW,
+       SAA7115_RTS_HL,
+       SAA7113_RTS_VL,
+       SAA7113_RTS_DL,
+       SAA7113_RTS_PLIN,
+       SAA7113_RTS_HREF_HS,            /* Default RTS0 For saa7113_init */
+       SAA7113_RTS_HS,
+       SAA7113_RTS_HQ,
+       SAA7113_RTS_ODD,
+       SAA7113_RTS_VS,
+       SAA7113_RTS_V123,
+       SAA7113_RTS_VGATE,
+       SAA7113_RTS_VREF,
+       SAA7113_RTS_FID
+};
+
+/**
+ * struct saa7115_platform_data - Allow overriding default initialization
+ *
+ * @saa7113_force_gm7113c_init:        Force the use of the gm7113c_init table
+ *                             instead of saa7113_init table
+ *                             (saa7113 only)
+ * @saa7113_r08_htc:           [R_08 - Bit 3..4]
+ * @saa7113_r10_vrln:          [R_10 - Bit 3]
+ *                             default: Disabled for gm7113c_init
+ *                                      Enabled for saa7113c_init
+ * @saa7113_r10_ofts:          [R_10 - Bit 6..7]
+ * @saa7113_r12_rts0:          [R_12 - Bit 0..3]
+ * @saa7113_r12_rts1:          [R_12 - Bit 4..7]
+ * @saa7113_r13_adlsb:         [R_13 - Bit 7] - default: disabled
+ */
+struct saa7115_platform_data {
+       bool saa7113_force_gm7113c_init;
+       enum saa7113_r08_htc *saa7113_r08_htc;
+       bool *saa7113_r10_vrln;
+       enum saa7113_r10_ofts *saa7113_r10_ofts;
+       enum saa7113_r12_rts *saa7113_r12_rts0;
+       enum saa7113_r12_rts *saa7113_r12_rts1;
+       bool *saa7113_r13_adlsb;
+};
+
+#endif
diff --git a/include/media/i2c/saa7127.h b/include/media/i2c/saa7127.h
new file mode 100644 (file)
index 0000000..7005ba7
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+    saa7127.h - definition for saa7126/7/8/9 inputs/outputs
+
+    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
+
+    This program is 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 _SAA7127_H_
+#define _SAA7127_H_
+
+/* Enumeration for the supported input types */
+enum saa7127_input_type {
+       SAA7127_INPUT_TYPE_NORMAL,
+       SAA7127_INPUT_TYPE_TEST_IMAGE
+};
+
+/* Enumeration for the supported output signal types */
+enum saa7127_output_type {
+       SAA7127_OUTPUT_TYPE_BOTH,
+       SAA7127_OUTPUT_TYPE_COMPOSITE,
+       SAA7127_OUTPUT_TYPE_SVIDEO,
+       SAA7127_OUTPUT_TYPE_RGB,
+       SAA7127_OUTPUT_TYPE_YUV_C,
+       SAA7127_OUTPUT_TYPE_YUV_V
+};
+
+#endif
diff --git a/include/media/i2c/smiapp.h b/include/media/i2c/smiapp.h
new file mode 100644 (file)
index 0000000..029142d
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * include/media/i2c/smiapp.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __SMIAPP_H_
+#define __SMIAPP_H_
+
+#include <media/v4l2-subdev.h>
+
+#define SMIAPP_NAME            "smiapp"
+
+#define SMIAPP_DFL_I2C_ADDR    (0x20 >> 1) /* Default I2C Address */
+#define SMIAPP_ALT_I2C_ADDR    (0x6e >> 1) /* Alternate I2C Address */
+
+#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK     0
+#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE    1
+#define SMIAPP_CSI_SIGNALLING_MODE_CSI2                        2
+
+#define SMIAPP_NO_XSHUTDOWN    -1
+
+/*
+ * Sometimes due to board layout considerations the camera module can be
+ * mounted rotated. The typical rotation used is 180 degrees which can be
+ * corrected by giving a default H-FLIP and V-FLIP in the sensor readout.
+ * FIXME: rotation also changes the bayer pattern.
+ */
+enum smiapp_module_board_orient {
+       SMIAPP_MODULE_BOARD_ORIENT_0 = 0,
+       SMIAPP_MODULE_BOARD_ORIENT_180,
+};
+
+struct smiapp_flash_strobe_parms {
+       u8 mode;
+       u32 strobe_width_high_us;
+       u16 strobe_delay;
+       u16 stobe_start_point;
+       u8 trigger;
+};
+
+struct smiapp_platform_data {
+       /*
+        * Change the cci address if i2c_addr_alt is set.
+        * Both default and alternate cci addr need to be present
+        */
+       unsigned short i2c_addr_dfl;    /* Default i2c addr */
+       unsigned short i2c_addr_alt;    /* Alternate i2c addr */
+
+       uint32_t nvm_size;              /* bytes */
+       uint32_t ext_clk;               /* sensor external clk */
+
+       unsigned int lanes;             /* Number of CSI-2 lanes */
+       uint32_t csi_signalling_mode;   /* SMIAPP_CSI_SIGNALLING_MODE_* */
+       uint64_t *op_sys_clock;
+
+       enum smiapp_module_board_orient module_board_orient;
+
+       struct smiapp_flash_strobe_parms *strobe_setup;
+
+       int (*set_xclk)(struct v4l2_subdev *sd, int hz);
+       int32_t xshutdown;              /* gpio or SMIAPP_NO_XSHUTDOWN */
+};
+
+#endif /* __SMIAPP_H_  */
diff --git a/include/media/i2c/sr030pc30.h b/include/media/i2c/sr030pc30.h
new file mode 100644 (file)
index 0000000..6f901a6
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Driver header for SR030PC30 camera sensor
+ *
+ * Copyright (c) 2010 Samsung Electronics, Co. Ltd
+ * Contact: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef SR030PC30_H
+#define SR030PC30_H
+
+struct sr030pc30_platform_data {
+       unsigned long clk_rate; /* master clock frequency in Hz */
+       int (*set_power)(struct device *dev, int on);
+};
+
+#endif /* SR030PC30_H */
diff --git a/include/media/i2c/tc358743.h b/include/media/i2c/tc358743.h
new file mode 100644 (file)
index 0000000..4513f2f
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * tc358743 - Toshiba HDMI to CSI-2 bridge
+ *
+ * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights
+ * reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+/*
+ * References (c = chapter, p = page):
+ * REF_01 - Toshiba, TC358743XBG (H2C), Functional Specification, Rev 0.60
+ * REF_02 - Toshiba, TC358743XBG_HDMI-CSI_Tv11p_nm.xls
+ */
+
+#ifndef _TC358743_
+#define _TC358743_
+
+enum tc358743_ddc5v_delays {
+       DDC5V_DELAY_0_MS,
+       DDC5V_DELAY_50_MS,
+       DDC5V_DELAY_100_MS,
+       DDC5V_DELAY_200_MS,
+};
+
+enum tc358743_hdmi_detection_delay {
+       HDMI_MODE_DELAY_0_MS,
+       HDMI_MODE_DELAY_25_MS,
+       HDMI_MODE_DELAY_50_MS,
+       HDMI_MODE_DELAY_100_MS,
+};
+
+struct tc358743_platform_data {
+       /* System clock connected to REFCLK (pin H5) */
+       u32 refclk_hz; /* 26 MHz, 27 MHz or 42 MHz */
+
+       /* DDC +5V debounce delay to avoid spurious interrupts when the cable
+        * is connected.
+        * Sets DDC5V_MODE in register DDC_CTL.
+        * Default: DDC5V_DELAY_0_MS
+        */
+       enum tc358743_ddc5v_delays ddc5v_delay;
+
+       bool enable_hdcp;
+
+       /*
+        * The FIFO size is 512x32, so Toshiba recommend to set the default FIFO
+        * level to somewhere in the middle (e.g. 300), so it can cover speed
+        * mismatches in input and output ports.
+        */
+       u16 fifo_level;
+
+       /* Bps pr lane is (refclk_hz / pll_prd) * pll_fbd */
+       u16 pll_prd;
+       u16 pll_fbd;
+
+       /* CSI
+        * Calculate CSI parameters with REF_02 for the highest resolution your
+        * CSI interface can handle. The driver will adjust the number of CSI
+        * lanes in use according to the pixel clock.
+        *
+        * The values in brackets are calculated with REF_02 when the number of
+        * bps pr lane is 823.5 MHz, and can serve as a starting point.
+        */
+       u32 lineinitcnt;        /* (0x00001770) */
+       u32 lptxtimecnt;        /* (0x00000005) */
+       u32 tclk_headercnt;     /* (0x00001d04) */
+       u32 tclk_trailcnt;      /* (0x00000000) */
+       u32 ths_headercnt;      /* (0x00000505) */
+       u32 twakeup;            /* (0x00004650) */
+       u32 tclk_postcnt;       /* (0x00000000) */
+       u32 ths_trailcnt;       /* (0x00000004) */
+       u32 hstxvregcnt;        /* (0x00000005) */
+
+       /* DVI->HDMI detection delay to avoid unnecessary switching between DVI
+        * and HDMI mode.
+        * Sets HDMI_DET_V in register HDMI_DET.
+        * Default: HDMI_MODE_DELAY_0_MS
+        */
+       enum tc358743_hdmi_detection_delay hdmi_detection_delay;
+
+       /* Reset PHY automatically when TMDS clock goes from DC to AC.
+        * Sets PHY_AUTO_RST2 in register PHY_CTL2.
+        * Default: false
+        */
+       bool hdmi_phy_auto_reset_tmds_detected;
+
+       /* Reset PHY automatically when TMDS clock passes 21 MHz.
+        * Sets PHY_AUTO_RST3 in register PHY_CTL2.
+        * Default: false
+        */
+       bool hdmi_phy_auto_reset_tmds_in_range;
+
+       /* Reset PHY automatically when TMDS clock is detected.
+        * Sets PHY_AUTO_RST4 in register PHY_CTL2.
+        * Default: false
+        */
+       bool hdmi_phy_auto_reset_tmds_valid;
+
+       /* Reset HDMI PHY automatically when hsync period is out of range.
+        * Sets H_PI_RST in register HV_RST.
+        * Default: false
+        */
+       bool hdmi_phy_auto_reset_hsync_out_of_range;
+
+       /* Reset HDMI PHY automatically when vsync period is out of range.
+        * Sets V_PI_RST in register HV_RST.
+        * Default: false
+        */
+       bool hdmi_phy_auto_reset_vsync_out_of_range;
+};
+
+/* custom controls */
+/* Audio sample rate in Hz */
+#define TC358743_CID_AUDIO_SAMPLING_RATE (V4L2_CID_USER_TC358743_BASE + 0)
+/* Audio present status */
+#define TC358743_CID_AUDIO_PRESENT       (V4L2_CID_USER_TC358743_BASE + 1)
+
+#endif
diff --git a/include/media/i2c/ths7303.h b/include/media/i2c/ths7303.h
new file mode 100644 (file)
index 0000000..a7b4929
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2013 Texas Instruments Inc
+ *
+ * Copyright 2013 Cisco Systems, Inc. and/or its affiliates.
+ *
+ * Contributors:
+ *     Hans Verkuil <hans.verkuil@cisco.com>
+ *     Lad, Prabhakar <prabhakar.lad@ti.com>
+ *     Martin Bugge <marbugge@cisco.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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
+#define THS7353_H
+
+/**
+ * struct ths7303_platform_data - Platform dependent data
+ * @ch_1: Bias value for channel one.
+ * @ch_2: Bias value for channel two.
+ * @ch_3: Bias value for channel three.
+ */
+struct ths7303_platform_data {
+       u8 ch_1;
+       u8 ch_2;
+       u8 ch_3;
+};
+
+#endif
diff --git a/include/media/i2c/tvaudio.h b/include/media/i2c/tvaudio.h
new file mode 100644 (file)
index 0000000..1ac8184
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+    tvaudio.h - definition for tvaudio inputs
+
+    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
+
+    This program is 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 _TVAUDIO_H
+#define _TVAUDIO_H
+
+#include <media/i2c-addr.h>
+
+/* The tvaudio module accepts the following inputs: */
+#define TVAUDIO_INPUT_TUNER  0
+#define TVAUDIO_INPUT_RADIO  1
+#define TVAUDIO_INPUT_EXTERN 2
+#define TVAUDIO_INPUT_INTERN 3
+
+static inline const unsigned short *tvaudio_addrs(void)
+{
+       static const unsigned short addrs[] = {
+               I2C_ADDR_TDA8425   >> 1,
+               I2C_ADDR_TEA6300   >> 1,
+               I2C_ADDR_TEA6420   >> 1,
+               I2C_ADDR_TDA9840   >> 1,
+               I2C_ADDR_TDA985x_L >> 1,
+               I2C_ADDR_TDA985x_H >> 1,
+               I2C_ADDR_TDA9874   >> 1,
+               I2C_ADDR_PIC16C54  >> 1,
+               I2C_CLIENT_END
+       };
+
+       return addrs;
+}
+
+#endif
diff --git a/include/media/i2c/tvp514x.h b/include/media/i2c/tvp514x.h
new file mode 100644 (file)
index 0000000..86ed7e8
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * drivers/media/video/tvp514x.h
+ *
+ * Copyright (C) 2008 Texas Instruments Inc
+ * Author: Vaibhav Hiremath <hvaibhav@ti.com>
+ *
+ * Contributors:
+ *     Sivaraj R <sivaraj@ti.com>
+ *     Brijesh R Jadav <brijesh.j@ti.com>
+ *     Hardik Shah <hardik.shah@ti.com>
+ *     Manjunath Hadli <mrh@ti.com>
+ *     Karicheri Muralidharan <m-karicheri2@ti.com>
+ *
+ * This package 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _TVP514X_H
+#define _TVP514X_H
+
+/*
+ * Other macros
+ */
+#define TVP514X_MODULE_NAME            "tvp514x"
+
+#define TVP514X_XCLK_BT656             (27000000)
+
+/* Number of pixels and number of lines per frame for different standards */
+#define NTSC_NUM_ACTIVE_PIXELS         (720)
+#define NTSC_NUM_ACTIVE_LINES          (480)
+#define PAL_NUM_ACTIVE_PIXELS          (720)
+#define PAL_NUM_ACTIVE_LINES           (576)
+
+/**
+ * enum tvp514x_input - enum for different decoder input pin
+ *             configuration.
+ */
+enum tvp514x_input {
+       /*
+        * CVBS input selection
+        */
+       INPUT_CVBS_VI1A = 0x0,
+       INPUT_CVBS_VI1B,
+       INPUT_CVBS_VI1C,
+       INPUT_CVBS_VI2A = 0x04,
+       INPUT_CVBS_VI2B,
+       INPUT_CVBS_VI2C,
+       INPUT_CVBS_VI3A = 0x08,
+       INPUT_CVBS_VI3B,
+       INPUT_CVBS_VI3C,
+       INPUT_CVBS_VI4A = 0x0C,
+       /*
+        * S-Video input selection
+        */
+       INPUT_SVIDEO_VI2A_VI1A = 0x44,
+       INPUT_SVIDEO_VI2B_VI1B,
+       INPUT_SVIDEO_VI2C_VI1C,
+       INPUT_SVIDEO_VI2A_VI3A = 0x54,
+       INPUT_SVIDEO_VI2B_VI3B,
+       INPUT_SVIDEO_VI2C_VI3C,
+       INPUT_SVIDEO_VI4A_VI1A = 0x4C,
+       INPUT_SVIDEO_VI4A_VI1B,
+       INPUT_SVIDEO_VI4A_VI1C,
+       INPUT_SVIDEO_VI4A_VI3A = 0x5C,
+       INPUT_SVIDEO_VI4A_VI3B,
+       INPUT_SVIDEO_VI4A_VI3C,
+
+       /* Need to add entries for
+        * RGB, YPbPr and SCART.
+        */
+       INPUT_INVALID
+};
+
+/**
+ * enum tvp514x_output - enum for output format
+ *                     supported.
+ *
+ */
+enum tvp514x_output {
+       OUTPUT_10BIT_422_EMBEDDED_SYNC = 0,
+       OUTPUT_20BIT_422_SEPERATE_SYNC,
+       OUTPUT_10BIT_422_SEPERATE_SYNC = 3,
+       OUTPUT_INVALID
+};
+
+/**
+ * struct tvp514x_platform_data - Platform data values and access functions.
+ * @clk_polarity: Clock polarity of the current interface.
+ * @hs_polarity: HSYNC Polarity configuration for current interface.
+ * @vs_polarity: VSYNC Polarity configuration for current interface.
+ */
+struct tvp514x_platform_data {
+       /* Interface control params */
+       bool clk_polarity;
+       bool hs_polarity;
+       bool vs_polarity;
+};
+
+
+#endif                         /* ifndef _TVP514X_H */
diff --git a/include/media/i2c/tvp5150.h b/include/media/i2c/tvp5150.h
new file mode 100644 (file)
index 0000000..649908a
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+    tvp5150.h - definition for tvp5150 inputs
+
+    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
+
+    This program is 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 _TVP5150_H_
+#define _TVP5150_H_
+
+/* TVP5150 HW inputs */
+#define TVP5150_COMPOSITE0 0
+#define TVP5150_COMPOSITE1 1
+#define TVP5150_SVIDEO     2
+
+/* TVP5150 HW outputs */
+#define TVP5150_NORMAL       0
+#define TVP5150_BLACK_SCREEN 1
+
+#endif
diff --git a/include/media/i2c/tvp7002.h b/include/media/i2c/tvp7002.h
new file mode 100644 (file)
index 0000000..fadb6af
--- /dev/null
@@ -0,0 +1,54 @@
+/* Texas Instruments Triple 8-/10-BIT 165-/110-MSPS Video and Graphics
+ * Digitizer with Horizontal PLL registers
+ *
+ * Copyright (C) 2009 Texas Instruments Inc
+ * Author: Santiago Nunez-Corrales <santiago.nunez@ridgerun.com>
+ *
+ * This code is partially based upon the TVP5150 driver
+ * written by Mauro Carvalho Chehab (mchehab@infradead.org),
+ * the TVP514x driver written by Vaibhav Hiremath <hvaibhav@ti.com>
+ * and the TVP7002 driver in the TI LSP 2.10.00.14
+ *
+ * This program is 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 _TVP7002_H_
+#define _TVP7002_H_
+
+#define TVP7002_MODULE_NAME "tvp7002"
+
+/**
+ * struct tvp7002_config - Platform dependent data
+ *@clk_polarity: Clock polarity
+ *             0 - Data clocked out on rising edge of DATACLK signal
+ *             1 - Data clocked out on falling edge of DATACLK signal
+ *@hs_polarity:  HSYNC polarity
+ *             0 - Active low HSYNC output, 1 - Active high HSYNC output
+ *@vs_polarity: VSYNC Polarity
+ *             0 - Active low VSYNC output, 1 - Active high VSYNC output
+ *@fid_polarity: Active-high Field ID polarity.
+ *             0 - The field ID output is set to logic 1 for an odd field
+ *                 (field 1) and set to logic 0 for an even field (field 0).
+ *             1 - Operation with polarity inverted.
+ *@sog_polarity: Active high Sync on Green output polarity.
+ *             0 - Normal operation, 1 - Operation with polarity inverted
+ */
+struct tvp7002_config {
+       bool clk_polarity;
+       bool hs_polarity;
+       bool vs_polarity;
+       bool fid_polarity;
+       bool sog_polarity;
+};
+#endif
diff --git a/include/media/i2c/tw9910.h b/include/media/i2c/tw9910.h
new file mode 100644 (file)
index 0000000..90bcf1f
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * tw9910 Driver header
+ *
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov772x.h
+ *
+ * Copyright (C) Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __TW9910_H__
+#define __TW9910_H__
+
+#include <media/soc_camera.h>
+
+enum tw9910_mpout_pin {
+       TW9910_MPO_VLOSS,
+       TW9910_MPO_HLOCK,
+       TW9910_MPO_SLOCK,
+       TW9910_MPO_VLOCK,
+       TW9910_MPO_MONO,
+       TW9910_MPO_DET50,
+       TW9910_MPO_FIELD,
+       TW9910_MPO_RTCO,
+};
+
+struct tw9910_video_info {
+       unsigned long           buswidth;
+       enum tw9910_mpout_pin   mpout;
+};
+
+
+#endif /* __TW9910_H__ */
diff --git a/include/media/i2c/uda1342.h b/include/media/i2c/uda1342.h
new file mode 100644 (file)
index 0000000..cd15640
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * uda1342.h - definition for uda1342 inputs
+ *
+ * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _UDA1342_H_
+#define _UDA1342_H_
+
+/* The UDA1342 has 2 inputs */
+
+#define UDA1342_IN1 1
+#define UDA1342_IN2 2
+
+#endif
diff --git a/include/media/i2c/upd64031a.h b/include/media/i2c/upd64031a.h
new file mode 100644 (file)
index 0000000..3ad6a32
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * upd64031a - NEC Electronics Ghost Reduction input defines
+ *
+ * 2006 by Hans Verkuil (hverkuil@xs4all.nl)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _UPD64031A_H_
+#define _UPD64031A_H_
+
+/* Ghost reduction modes */
+#define UPD64031A_GR_ON        0
+#define UPD64031A_GR_OFF       1
+#define UPD64031A_GR_THROUGH   3
+
+/* Direct 3D/YCS Connection */
+#define UPD64031A_3DYCS_DISABLE   (0 << 2)
+#define UPD64031A_3DYCS_COMPOSITE (2 << 2)
+#define UPD64031A_3DYCS_SVIDEO    (3 << 2)
+
+/* Composite sync digital separation circuit */
+#define UPD64031A_COMPOSITE_EXTERNAL (1 << 4)
+
+/* Vertical sync digital separation circuit */
+#define UPD64031A_VERTICAL_EXTERNAL (1 << 5)
+
+#endif
diff --git a/include/media/i2c/upd64083.h b/include/media/i2c/upd64083.h
new file mode 100644 (file)
index 0000000..59b6f32
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * upd6408x - NEC Electronics 3-Dimensional Y/C separation input defines
+ *
+ * 2006 by Hans Verkuil (hverkuil@xs4all.nl)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _UPD64083_H_
+#define _UPD64083_H_
+
+/* There are two bits of information that the driver needs in order
+   to select the correct routing: the operating mode and the selection
+   of the Y input (external or internal).
+
+   The first two operating modes expect a composite signal on the Y input,
+   the second two operating modes use both the Y and C inputs.
+
+   Normally YCS_MODE is used for tuner and composite inputs, and the
+   YCNR mode is used for S-Video inputs.
+
+   The external Y-ADC is selected when the composite input comes from a
+   upd64031a ghost reduction device. If this device is not present, or
+   the input is a S-Video signal, then the internal Y-ADC input should
+   be used. */
+
+/* Operating modes: */
+
+/* YCS mode: Y/C separation (burst locked clocking) */
+#define UPD64083_YCS_MODE      0
+/* YCS+ mode: 2D Y/C separation and YCNR (burst locked clocking) */
+#define UPD64083_YCS_PLUS_MODE 1
+
+/* Note: the following two modes cannot be used in combination with the
+   external Y-ADC. */
+/* MNNR mode: frame comb type YNR+C delay (line locked clocking) */
+#define UPD64083_MNNR_MODE     2
+/* YCNR mode: frame recursive YCNR (burst locked clocking) */
+#define UPD64083_YCNR_MODE     3
+
+/* Select external Y-ADC: this should be set if this device is used in
+   combination with the upd64031a ghost reduction device.
+   Otherwise leave at 0 (use internal Y-ADC). */
+#define UPD64083_EXT_Y_ADC     (1 << 2)
+
+#endif
diff --git a/include/media/i2c/wm8775.h b/include/media/i2c/wm8775.h
new file mode 100644 (file)
index 0000000..d0e801a
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+    wm8775.h - definition for wm8775 inputs and outputs
+
+    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
+
+    This program is 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 _WM8775_H_
+#define _WM8775_H_
+
+/* The WM8775 has 4 inputs and one output. Zero or more inputs
+   are multiplexed together to the output. Hence there are
+   16 combinations.
+   If only one input is active (the normal case) then the
+   input values 1, 2, 4 or 8 should be used. */
+
+#define WM8775_AIN1 1
+#define WM8775_AIN2 2
+#define WM8775_AIN3 4
+#define WM8775_AIN4 8
+
+
+struct wm8775_platform_data {
+       /*
+        * FIXME: Instead, we should parametrize the params
+        * that need different settings between ivtv, pvrusb2, and Nova-S
+        */
+       bool is_nova_s;
+};
+
+#endif
diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h
deleted file mode 100644 (file)
index d856435..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef _IR_I2C
-#define _IR_I2C
-
-#include <media/rc-core.h>
-
-#define DEFAULT_POLLING_INTERVAL       100     /* ms */
-
-struct IR_i2c;
-
-struct IR_i2c {
-       char                   *ir_codes;
-       struct i2c_client      *c;
-       struct rc_dev          *rc;
-
-       /* Used to avoid fast repeating */
-       unsigned char          old;
-
-       u32                    polling_interval; /* in ms */
-
-       struct delayed_work    work;
-       char                   name[32];
-       char                   phys[32];
-       int                    (*get_key)(struct IR_i2c *ir, enum rc_type *protocol,
-                                         u32 *scancode, u8 *toggle);
-};
-
-enum ir_kbd_get_key_fn {
-       IR_KBD_GET_KEY_CUSTOM = 0,
-       IR_KBD_GET_KEY_PIXELVIEW,
-       IR_KBD_GET_KEY_HAUP,
-       IR_KBD_GET_KEY_KNC1,
-       IR_KBD_GET_KEY_FUSIONHDTV,
-       IR_KBD_GET_KEY_HAUP_XVR,
-       IR_KBD_GET_KEY_AVERMEDIA_CARDBUS,
-};
-
-/* Can be passed when instantiating an ir_video i2c device */
-struct IR_i2c_init_data {
-       char                    *ir_codes;
-       const char              *name;
-       u64                     type; /* RC_BIT_RC5, etc */
-       u32                     polling_interval; /* 0 means DEFAULT_POLLING_INTERVAL */
-
-       /*
-        * Specify either a function pointer or a value indicating one of
-        * ir_kbd_i2c's internal get_key functions
-        */
-       int                    (*get_key)(struct IR_i2c *ir, enum rc_type *protocol,
-                                         u32 *scancode, u8 *toggle);
-       enum ir_kbd_get_key_fn internal_get_key_func;
-
-       struct rc_dev           *rc_dev;
-};
-#endif
diff --git a/include/media/ir-rx51.h b/include/media/ir-rx51.h
deleted file mode 100644 (file)
index 104aa89..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _LIRC_RX51_H
-#define _LIRC_RX51_H
-
-struct lirc_rx51_platform_data {
-       int pwm_timer;
-
-       int(*set_max_mpu_wakeup_lat)(struct device *dev, long t);
-};
-
-#endif
index 4b3ab2966b5a4a88efbde38230a1887e218f368b..554988c860c1e022050b6f173d1ff799be610149 100644 (file)
@@ -1,168 +1 @@
-/*
- * lirc.h - linux infrared remote control header file
- * last modified 2010/07/13 by Jarod Wilson
- */
-
-#ifndef _LINUX_LIRC_H
-#define _LINUX_LIRC_H
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-
-#define PULSE_BIT       0x01000000
-#define PULSE_MASK      0x00FFFFFF
-
-#define LIRC_MODE2_SPACE     0x00000000
-#define LIRC_MODE2_PULSE     0x01000000
-#define LIRC_MODE2_FREQUENCY 0x02000000
-#define LIRC_MODE2_TIMEOUT   0x03000000
-
-#define LIRC_VALUE_MASK      0x00FFFFFF
-#define LIRC_MODE2_MASK      0xFF000000
-
-#define LIRC_SPACE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_SPACE)
-#define LIRC_PULSE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_PULSE)
-#define LIRC_FREQUENCY(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_FREQUENCY)
-#define LIRC_TIMEOUT(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_TIMEOUT)
-
-#define LIRC_VALUE(val) ((val)&LIRC_VALUE_MASK)
-#define LIRC_MODE2(val) ((val)&LIRC_MODE2_MASK)
-
-#define LIRC_IS_SPACE(val) (LIRC_MODE2(val) == LIRC_MODE2_SPACE)
-#define LIRC_IS_PULSE(val) (LIRC_MODE2(val) == LIRC_MODE2_PULSE)
-#define LIRC_IS_FREQUENCY(val) (LIRC_MODE2(val) == LIRC_MODE2_FREQUENCY)
-#define LIRC_IS_TIMEOUT(val) (LIRC_MODE2(val) == LIRC_MODE2_TIMEOUT)
-
-/* used heavily by lirc userspace */
-#define lirc_t int
-
-/*** lirc compatible hardware features ***/
-
-#define LIRC_MODE2SEND(x) (x)
-#define LIRC_SEND2MODE(x) (x)
-#define LIRC_MODE2REC(x) ((x) << 16)
-#define LIRC_REC2MODE(x) ((x) >> 16)
-
-#define LIRC_MODE_RAW                  0x00000001
-#define LIRC_MODE_PULSE                0x00000002
-#define LIRC_MODE_MODE2                0x00000004
-#define LIRC_MODE_LIRCCODE             0x00000010
-
-
-#define LIRC_CAN_SEND_RAW              LIRC_MODE2SEND(LIRC_MODE_RAW)
-#define LIRC_CAN_SEND_PULSE            LIRC_MODE2SEND(LIRC_MODE_PULSE)
-#define LIRC_CAN_SEND_MODE2            LIRC_MODE2SEND(LIRC_MODE_MODE2)
-#define LIRC_CAN_SEND_LIRCCODE         LIRC_MODE2SEND(LIRC_MODE_LIRCCODE)
-
-#define LIRC_CAN_SEND_MASK             0x0000003f
-
-#define LIRC_CAN_SET_SEND_CARRIER      0x00000100
-#define LIRC_CAN_SET_SEND_DUTY_CYCLE   0x00000200
-#define LIRC_CAN_SET_TRANSMITTER_MASK  0x00000400
-
-#define LIRC_CAN_REC_RAW               LIRC_MODE2REC(LIRC_MODE_RAW)
-#define LIRC_CAN_REC_PULSE             LIRC_MODE2REC(LIRC_MODE_PULSE)
-#define LIRC_CAN_REC_MODE2             LIRC_MODE2REC(LIRC_MODE_MODE2)
-#define LIRC_CAN_REC_LIRCCODE          LIRC_MODE2REC(LIRC_MODE_LIRCCODE)
-
-#define LIRC_CAN_REC_MASK              LIRC_MODE2REC(LIRC_CAN_SEND_MASK)
-
-#define LIRC_CAN_SET_REC_CARRIER       (LIRC_CAN_SET_SEND_CARRIER << 16)
-#define LIRC_CAN_SET_REC_DUTY_CYCLE    (LIRC_CAN_SET_SEND_DUTY_CYCLE << 16)
-
-#define LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE 0x40000000
-#define LIRC_CAN_SET_REC_CARRIER_RANGE    0x80000000
-#define LIRC_CAN_GET_REC_RESOLUTION       0x20000000
-#define LIRC_CAN_SET_REC_TIMEOUT          0x10000000
-#define LIRC_CAN_SET_REC_FILTER           0x08000000
-
-#define LIRC_CAN_MEASURE_CARRIER          0x02000000
-#define LIRC_CAN_USE_WIDEBAND_RECEIVER    0x04000000
-
-#define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK)
-#define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK)
-
-#define LIRC_CAN_NOTIFY_DECODE            0x01000000
-
-/*** IOCTL commands for lirc driver ***/
-
-#define LIRC_GET_FEATURES              _IOR('i', 0x00000000, __u32)
-
-#define LIRC_GET_SEND_MODE             _IOR('i', 0x00000001, __u32)
-#define LIRC_GET_REC_MODE              _IOR('i', 0x00000002, __u32)
-#define LIRC_GET_SEND_CARRIER          _IOR('i', 0x00000003, __u32)
-#define LIRC_GET_REC_CARRIER           _IOR('i', 0x00000004, __u32)
-#define LIRC_GET_SEND_DUTY_CYCLE       _IOR('i', 0x00000005, __u32)
-#define LIRC_GET_REC_DUTY_CYCLE        _IOR('i', 0x00000006, __u32)
-#define LIRC_GET_REC_RESOLUTION        _IOR('i', 0x00000007, __u32)
-
-#define LIRC_GET_MIN_TIMEOUT           _IOR('i', 0x00000008, __u32)
-#define LIRC_GET_MAX_TIMEOUT           _IOR('i', 0x00000009, __u32)
-
-#define LIRC_GET_MIN_FILTER_PULSE      _IOR('i', 0x0000000a, __u32)
-#define LIRC_GET_MAX_FILTER_PULSE      _IOR('i', 0x0000000b, __u32)
-#define LIRC_GET_MIN_FILTER_SPACE      _IOR('i', 0x0000000c, __u32)
-#define LIRC_GET_MAX_FILTER_SPACE      _IOR('i', 0x0000000d, __u32)
-
-/* code length in bits, currently only for LIRC_MODE_LIRCCODE */
-#define LIRC_GET_LENGTH                _IOR('i', 0x0000000f, __u32)
-
-#define LIRC_SET_SEND_MODE             _IOW('i', 0x00000011, __u32)
-#define LIRC_SET_REC_MODE              _IOW('i', 0x00000012, __u32)
-/* Note: these can reset the according pulse_width */
-#define LIRC_SET_SEND_CARRIER          _IOW('i', 0x00000013, __u32)
-#define LIRC_SET_REC_CARRIER           _IOW('i', 0x00000014, __u32)
-#define LIRC_SET_SEND_DUTY_CYCLE       _IOW('i', 0x00000015, __u32)
-#define LIRC_SET_REC_DUTY_CYCLE        _IOW('i', 0x00000016, __u32)
-#define LIRC_SET_TRANSMITTER_MASK      _IOW('i', 0x00000017, __u32)
-
-/*
- * when a timeout != 0 is set the driver will send a
- * LIRC_MODE2_TIMEOUT data packet, otherwise LIRC_MODE2_TIMEOUT is
- * never sent, timeout is disabled by default
- */
-#define LIRC_SET_REC_TIMEOUT           _IOW('i', 0x00000018, __u32)
-
-/* 1 enables, 0 disables timeout reports in MODE2 */
-#define LIRC_SET_REC_TIMEOUT_REPORTS   _IOW('i', 0x00000019, __u32)
-
-/*
- * pulses shorter than this are filtered out by hardware (software
- * emulation in lirc_dev?)
- */
-#define LIRC_SET_REC_FILTER_PULSE      _IOW('i', 0x0000001a, __u32)
-/*
- * spaces shorter than this are filtered out by hardware (software
- * emulation in lirc_dev?)
- */
-#define LIRC_SET_REC_FILTER_SPACE      _IOW('i', 0x0000001b, __u32)
-/*
- * if filter cannot be set independently for pulse/space, this should
- * be used
- */
-#define LIRC_SET_REC_FILTER            _IOW('i', 0x0000001c, __u32)
-
-/*
- * if enabled from the next key press on the driver will send
- * LIRC_MODE2_FREQUENCY packets
- */
-#define LIRC_SET_MEASURE_CARRIER_MODE  _IOW('i', 0x0000001d, __u32)
-
-/*
- * to set a range use
- * LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE with the
- * lower bound first and later
- * LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER with the upper bound
- */
-
-#define LIRC_SET_REC_DUTY_CYCLE_RANGE  _IOW('i', 0x0000001e, __u32)
-#define LIRC_SET_REC_CARRIER_RANGE     _IOW('i', 0x0000001f, __u32)
-
-#define LIRC_NOTIFY_DECODE             _IO('i', 0x00000020)
-
-#define LIRC_SETUP_START               _IO('i', 0x00000021)
-#define LIRC_SETUP_END                 _IO('i', 0x00000022)
-
-#define LIRC_SET_WIDEBAND_RECEIVER     _IOW('i', 0x00000023, __u32)
-
-#endif
+#include <uapi/linux/lirc.h>
diff --git a/include/media/lm3560.h b/include/media/lm3560.h
deleted file mode 100644 (file)
index 4667070..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * include/media/lm3560.h
- *
- * Copyright (C) 2013 Texas Instruments
- *
- * Contact: Daniel Jeong <gshark.jeong@gmail.com>
- *                     Ldd-Mlp <ldd-mlp@list.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.
- *
- * You 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__
-#define __LM3560_H__
-
-#include <media/v4l2-subdev.h>
-
-#define LM3560_NAME    "lm3560"
-#define LM3560_I2C_ADDR        (0x53)
-
-/*  FLASH Brightness
- *     min 62500uA, step 62500uA, max 1000000uA
- */
-#define LM3560_FLASH_BRT_MIN 62500
-#define LM3560_FLASH_BRT_STEP 62500
-#define LM3560_FLASH_BRT_MAX 1000000
-#define LM3560_FLASH_BRT_uA_TO_REG(a)  \
-       ((a) < LM3560_FLASH_BRT_MIN ? 0 :       \
-        (((a) - LM3560_FLASH_BRT_MIN) / LM3560_FLASH_BRT_STEP))
-#define LM3560_FLASH_BRT_REG_TO_uA(a)          \
-       ((a) * LM3560_FLASH_BRT_STEP + LM3560_FLASH_BRT_MIN)
-
-/*  FLASH TIMEOUT DURATION
- *     min 32ms, step 32ms, max 1024ms
- */
-#define LM3560_FLASH_TOUT_MIN 32
-#define LM3560_FLASH_TOUT_STEP 32
-#define LM3560_FLASH_TOUT_MAX 1024
-#define LM3560_FLASH_TOUT_ms_TO_REG(a) \
-       ((a) < LM3560_FLASH_TOUT_MIN ? 0 :      \
-        (((a) - LM3560_FLASH_TOUT_MIN) / LM3560_FLASH_TOUT_STEP))
-#define LM3560_FLASH_TOUT_REG_TO_ms(a)         \
-       ((a) * LM3560_FLASH_TOUT_STEP + LM3560_FLASH_TOUT_MIN)
-
-/*  TORCH BRT
- *     min 31250uA, step 31250uA, max 250000uA
- */
-#define LM3560_TORCH_BRT_MIN 31250
-#define LM3560_TORCH_BRT_STEP 31250
-#define LM3560_TORCH_BRT_MAX 250000
-#define LM3560_TORCH_BRT_uA_TO_REG(a)  \
-       ((a) < LM3560_TORCH_BRT_MIN ? 0 :       \
-        (((a) - LM3560_TORCH_BRT_MIN) / LM3560_TORCH_BRT_STEP))
-#define LM3560_TORCH_BRT_REG_TO_uA(a)          \
-       ((a) * LM3560_TORCH_BRT_STEP + LM3560_TORCH_BRT_MIN)
-
-enum lm3560_led_id {
-       LM3560_LED0 = 0,
-       LM3560_LED1,
-       LM3560_LED_MAX
-};
-
-enum lm3560_peak_current {
-       LM3560_PEAK_1600mA = 0x00,
-       LM3560_PEAK_2300mA = 0x20,
-       LM3560_PEAK_3000mA = 0x40,
-       LM3560_PEAK_3600mA = 0x60
-};
-
-/* struct lm3560_platform_data
- *
- * @peak :  peak current
- * @max_flash_timeout: flash timeout
- * @max_flash_brt: flash mode led brightness
- * @max_torch_brt: torch mode led brightness
- */
-struct lm3560_platform_data {
-       enum lm3560_peak_current peak;
-
-       u32 max_flash_timeout;
-       u32 max_flash_brt[LM3560_LED_MAX];
-       u32 max_torch_brt[LM3560_LED_MAX];
-};
-
-#endif /* __LM3560_H__ */
diff --git a/include/media/lm3646.h b/include/media/lm3646.h
deleted file mode 100644 (file)
index c6acf5a..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * include/media/lm3646.h
- *
- * Copyright (C) 2014 Texas Instruments
- *
- * Contact: Daniel Jeong <gshark.jeong@gmail.com>
- *                     Ldd-Mlp <ldd-mlp@list.ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- */
-
-#ifndef __LM3646_H__
-#define __LM3646_H__
-
-#include <media/v4l2-subdev.h>
-
-#define LM3646_NAME    "lm3646"
-#define LM3646_I2C_ADDR_REV1   (0x67)
-#define LM3646_I2C_ADDR_REV0   (0x63)
-
-/*  TOTAL FLASH Brightness Max
- *     min 93350uA, step 93750uA, max 1499600uA
- */
-#define LM3646_TOTAL_FLASH_BRT_MIN 93350
-#define LM3646_TOTAL_FLASH_BRT_STEP 93750
-#define LM3646_TOTAL_FLASH_BRT_MAX 1499600
-#define LM3646_TOTAL_FLASH_BRT_uA_TO_REG(a)    \
-       ((a) < LM3646_TOTAL_FLASH_BRT_MIN ? 0 : \
-        ((((a) - LM3646_TOTAL_FLASH_BRT_MIN) / LM3646_TOTAL_FLASH_BRT_STEP)))
-
-/*  TOTAL TORCH Brightness Max
- *     min 23040uA, step 23430uA, max 187100uA
- */
-#define LM3646_TOTAL_TORCH_BRT_MIN 23040
-#define LM3646_TOTAL_TORCH_BRT_STEP 23430
-#define LM3646_TOTAL_TORCH_BRT_MAX 187100
-#define LM3646_TOTAL_TORCH_BRT_uA_TO_REG(a)    \
-       ((a) < LM3646_TOTAL_TORCH_BRT_MIN ? 0 : \
-        ((((a) - LM3646_TOTAL_TORCH_BRT_MIN) / LM3646_TOTAL_TORCH_BRT_STEP)))
-
-/*  LED1 FLASH Brightness
- *     min 23040uA, step 11718uA, max 1499600uA
- */
-#define LM3646_LED1_FLASH_BRT_MIN 23040
-#define LM3646_LED1_FLASH_BRT_STEP 11718
-#define LM3646_LED1_FLASH_BRT_MAX 1499600
-#define LM3646_LED1_FLASH_BRT_uA_TO_REG(a)     \
-       ((a) <= LM3646_LED1_FLASH_BRT_MIN ? 0 : \
-        ((((a) - LM3646_LED1_FLASH_BRT_MIN) / LM3646_LED1_FLASH_BRT_STEP))+1)
-
-/*  LED1 TORCH Brightness
- *     min 2530uA, step 1460uA, max 187100uA
- */
-#define LM3646_LED1_TORCH_BRT_MIN 2530
-#define LM3646_LED1_TORCH_BRT_STEP 1460
-#define LM3646_LED1_TORCH_BRT_MAX 187100
-#define LM3646_LED1_TORCH_BRT_uA_TO_REG(a)     \
-       ((a) <= LM3646_LED1_TORCH_BRT_MIN ? 0 : \
-        ((((a) - LM3646_LED1_TORCH_BRT_MIN) / LM3646_LED1_TORCH_BRT_STEP))+1)
-
-/*  FLASH TIMEOUT DURATION
- *     min 50ms, step 50ms, max 400ms
- */
-#define LM3646_FLASH_TOUT_MIN 50
-#define LM3646_FLASH_TOUT_STEP 50
-#define LM3646_FLASH_TOUT_MAX 400
-#define LM3646_FLASH_TOUT_ms_TO_REG(a) \
-       ((a) <= LM3646_FLASH_TOUT_MIN ? 0 :     \
-        (((a) - LM3646_FLASH_TOUT_MIN) / LM3646_FLASH_TOUT_STEP))
-
-/* struct lm3646_platform_data
- *
- * @flash_timeout: flash timeout
- * @led1_flash_brt: led1 flash mode brightness, uA
- * @led1_torch_brt: led1 torch mode brightness, uA
- */
-struct lm3646_platform_data {
-
-       u32 flash_timeout;
-
-       u32 led1_flash_brt;
-       u32 led1_torch_brt;
-};
-
-#endif /* __LM3646_H__ */
diff --git a/include/media/m52790.h b/include/media/m52790.h
deleted file mode 100644 (file)
index 7ddffae..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
-    m52790.h - definition for m52790 inputs and outputs
-
-    Copyright (C) 2007 Hans Verkuil (hverkuil@xs4all.nl)
-
-    This program is 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 _M52790_H_
-#define _M52790_H_
-
-/* Input routing switch 1 */
-
-#define M52790_SW1_IN_MASK     0x0003
-#define M52790_SW1_IN_TUNER    0x0000
-#define M52790_SW1_IN_V2       0x0001
-#define M52790_SW1_IN_V3       0x0002
-#define M52790_SW1_IN_V4       0x0003
-
-/* Selects component input instead of composite */
-#define M52790_SW1_YCMIX       0x0004
-
-
-/* Input routing switch 2 */
-
-#define M52790_SW2_IN_MASK     0x0300
-#define M52790_SW2_IN_TUNER    0x0000
-#define M52790_SW2_IN_V2       0x0100
-#define M52790_SW2_IN_V3       0x0200
-#define M52790_SW2_IN_V4       0x0300
-
-/* Selects component input instead of composite */
-#define M52790_SW2_YCMIX       0x0400
-
-
-/* Output routing switch 1 */
-
-/* Enable 6dB amplifier for composite out */
-#define M52790_SW1_V_AMP       0x0008
-
-/* Enable 6dB amplifier for component out */
-#define M52790_SW1_YC_AMP      0x0010
-
-/* Audio output mode */
-#define M52790_SW1_AUDIO_MASK  0x00c0
-#define M52790_SW1_AUDIO_MUTE  0x0000
-#define M52790_SW1_AUDIO_R     0x0040
-#define M52790_SW1_AUDIO_L     0x0080
-#define M52790_SW1_AUDIO_STEREO 0x00c0
-
-
-/* Output routing switch 2 */
-
-/* Enable 6dB amplifier for composite out */
-#define M52790_SW2_V_AMP       0x0800
-
-/* Enable 6dB amplifier for component out */
-#define M52790_SW2_YC_AMP      0x1000
-
-/* Audio output mode */
-#define M52790_SW2_AUDIO_MASK  0xc000
-#define M52790_SW2_AUDIO_MUTE  0x0000
-#define M52790_SW2_AUDIO_R     0x4000
-#define M52790_SW2_AUDIO_L     0x8000
-#define M52790_SW2_AUDIO_STEREO 0xc000
-
-
-/* Common values */
-#define M52790_IN_TUNER (M52790_SW1_IN_TUNER | M52790_SW2_IN_TUNER)
-#define M52790_IN_V2    (M52790_SW1_IN_V2 | M52790_SW2_IN_V2)
-#define M52790_IN_V3    (M52790_SW1_IN_V3 | M52790_SW2_IN_V3)
-#define M52790_IN_V4    (M52790_SW1_IN_V4 | M52790_SW2_IN_V4)
-
-#define M52790_OUT_STEREO      (M52790_SW1_AUDIO_STEREO | \
-                                M52790_SW2_AUDIO_STEREO)
-#define M52790_OUT_AMP_STEREO  (M52790_SW1_AUDIO_STEREO | \
-                                M52790_SW1_V_AMP | \
-                                M52790_SW2_AUDIO_STEREO | \
-                                M52790_SW2_V_AMP)
-
-#endif
diff --git a/include/media/m5mols.h b/include/media/m5mols.h
deleted file mode 100644 (file)
index 4a825ae..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Driver header for M-5MOLS 8M Pixel camera sensor with ISP
- *
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * Author: HeungJun Kim <riverful.kim@samsung.com>
- *
- * Copyright (C) 2009 Samsung Electronics Co., Ltd.
- * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef MEDIA_M5MOLS_H
-#define MEDIA_M5MOLS_H
-
-/**
- * struct m5mols_platform_data - platform data for M-5MOLS driver
- * @gpio_reset:        GPIO driving the reset pin of M-5MOLS
- * @reset_polarity: active state for gpio_reset pin, 0 or 1
- * @set_power: an additional callback to the board setup code
- *             to be called after enabling and before disabling
- *             the sensor's supply regulators
- */
-struct m5mols_platform_data {
-       int gpio_reset;
-       u8 reset_polarity;
-       int (*set_power)(struct device *dev, int on);
-};
-
-#endif /* MEDIA_M5MOLS_H */
diff --git a/include/media/mmp-camera.h b/include/media/mmp-camera.h
deleted file mode 100644 (file)
index 7611963..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Information for the Marvell Armada MMP camera
- */
-
-struct mmp_camera_platform_data {
-       struct platform_device *i2c_device;
-       int sensor_power_gpio;
-       int sensor_reset_gpio;
-};
diff --git a/include/media/msp3400.h b/include/media/msp3400.h
deleted file mode 100644 (file)
index 90cf22a..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
-    msp3400.h - definition for msp3400 inputs and outputs
-
-    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
-
-    This program is 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 _MSP3400_H_
-#define _MSP3400_H_
-
-/* msp3400 routing
-   ===============
-
-   The msp3400 has a complicated routing scheme with many possible
-   combinations. The details are all in the datasheets but I will try
-   to give a short description here.
-
-   Inputs
-   ======
-
-   There are 1) tuner inputs, 2) I2S inputs, 3) SCART inputs. You will have
-   to select which tuner input to use and which SCART input to use. The
-   selected tuner input, the selected SCART input and all I2S inputs go to
-   the DSP (the tuner input first goes through the demodulator).
-
-   The DSP handles things like volume, bass/treble, balance, and some chips
-   have support for surround sound. It has several outputs: MAIN, AUX, I2S
-   and SCART1/2. Each output can select which DSP input to use. So the MAIN
-   output can select the tuner input while at the same time the SCART1 output
-   uses the I2S input.
-
-   Outputs
-   =======
-
-   Most DSP outputs are also the outputs of the msp3400. However, the SCART
-   outputs of the msp3400 can select which input to use: either the SCART1 or
-   SCART2 output from the DSP, or the msp3400 SCART inputs, thus completely
-   bypassing the DSP.
-
-   Summary
-   =======
-
-   So to specify a complete routing scheme for the msp3400 you will have to
-   specify in the 'input' arg of the s_routing function:
-
-   1) which tuner input to use
-   2) which SCART input to use
-   3) which DSP input to use for each DSP output
-
-   And in the 'output' arg of the s_routing function you specify:
-
-   1) which SCART input to use for each SCART output
-
-   Depending on how the msp is wired to the other components you can
-   ignore or mute certain inputs or outputs.
-
-   Also, depending on the msp version only a subset of the inputs or
-   outputs may be present. At the end of this header some tables are
-   added containing a list of what is available for each msp version.
- */
-
-/* Inputs to the DSP unit: two independent selections have to be made:
-   1) the tuner (SIF) input
-   2) the SCART input
-   Bits 0-2 are used for the SCART input select, bit 3 is used for the tuner
-   input, bits 4-7 are reserved.
- */
-
-/* SCART input to DSP selection */
-#define MSP_IN_SCART1                  0  /* Pin SC1_IN */
-#define MSP_IN_SCART2                  1  /* Pin SC2_IN */
-#define MSP_IN_SCART3                  2  /* Pin SC3_IN */
-#define MSP_IN_SCART4                  3  /* Pin SC4_IN */
-#define MSP_IN_MONO            6  /* Pin MONO_IN */
-#define MSP_IN_MUTE            7  /* Mute DSP input */
-#define MSP_SCART_TO_DSP(in)   (in)
-/* Tuner input to demodulator and DSP selection */
-#define MSP_IN_TUNER1          0  /* Analog Sound IF input pin ANA_IN1 */
-#define MSP_IN_TUNER2          1  /* Analog Sound IF input pin ANA_IN2 */
-#define MSP_TUNER_TO_DSP(in)   ((in) << 3)
-
-/* The msp has up to 5 DSP outputs, each output can independently select
-   a DSP input.
-
-   The DSP outputs are: loudspeaker output (aka MAIN), headphones output
-   (aka AUX), SCART1 DA output, SCART2 DA output and an I2S output.
-   There also is a quasi-peak detector output, but that is not used by
-   this driver and is set to the same input as the loudspeaker output.
-   Not all outputs are supported by all msp models. Setting the input
-   of an unsupported output will be ignored by the driver.
-
-   There are up to 16 DSP inputs to choose from, so each output is
-   assigned 4 bits.
-
-   Note: the 44x8G can mix two inputs and feed the result back to the
-   DSP. This is currently not implemented. Also not implemented is the
-   multi-channel capable I2S3 input of the 44x0G. If someone can demonstrate
-   a need for one of those features then additional support can be added. */
-#define MSP_DSP_IN_TUNER       0  /* Tuner DSP input */
-#define MSP_DSP_IN_SCART       2  /* SCART DSP input */
-#define MSP_DSP_IN_I2S1        5  /* I2S1 DSP input */
-#define MSP_DSP_IN_I2S2        6  /* I2S2 DSP input */
-#define MSP_DSP_IN_I2S3        7  /* I2S3 DSP input */
-#define MSP_DSP_IN_MAIN_AVC    11 /* MAIN AVC processed DSP input */
-#define MSP_DSP_IN_MAIN        12 /* MAIN DSP input */
-#define MSP_DSP_IN_AUX                 13 /* AUX DSP input */
-#define MSP_DSP_TO_MAIN(in)    ((in) << 4)
-#define MSP_DSP_TO_AUX(in)     ((in) << 8)
-#define MSP_DSP_TO_SCART1(in)  ((in) << 12)
-#define MSP_DSP_TO_SCART2(in)  ((in) << 16)
-#define MSP_DSP_TO_I2S(in)     ((in) << 20)
-
-/* Output SCART select: the SCART outputs can select which input
-   to use. */
-#define MSP_SC_IN_SCART1       0  /* SCART1 input, bypassing the DSP */
-#define MSP_SC_IN_SCART2       1  /* SCART2 input, bypassing the DSP */
-#define MSP_SC_IN_SCART3       2  /* SCART3 input, bypassing the DSP */
-#define MSP_SC_IN_SCART4       3  /* SCART4 input, bypassing the DSP */
-#define MSP_SC_IN_DSP_SCART1   4  /* DSP SCART1 input */
-#define MSP_SC_IN_DSP_SCART2   5  /* DSP SCART2 input */
-#define MSP_SC_IN_MONO                 6  /* MONO input, bypassing the DSP */
-#define MSP_SC_IN_MUTE                 7  /* MUTE output */
-#define MSP_SC_TO_SCART1(in)   (in)
-#define MSP_SC_TO_SCART2(in)   ((in) << 4)
-
-/* Shortcut macros */
-#define MSP_INPUT(sc, t, main_aux_src, sc_i2s_src) \
-       (MSP_SCART_TO_DSP(sc) | \
-        MSP_TUNER_TO_DSP(t) | \
-        MSP_DSP_TO_MAIN(main_aux_src) | \
-        MSP_DSP_TO_AUX(main_aux_src) | \
-        MSP_DSP_TO_SCART1(sc_i2s_src) | \
-        MSP_DSP_TO_SCART2(sc_i2s_src) | \
-        MSP_DSP_TO_I2S(sc_i2s_src))
-#define MSP_INPUT_DEFAULT MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, \
-                                   MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER)
-#define MSP_OUTPUT(sc) \
-       (MSP_SC_TO_SCART1(sc) | \
-        MSP_SC_TO_SCART2(sc))
-/* This equals the RESET position of the msp3400 ACB register */
-#define MSP_OUTPUT_DEFAULT (MSP_SC_TO_SCART1(MSP_SC_IN_SCART3) | \
-                           MSP_SC_TO_SCART2(MSP_SC_IN_DSP_SCART1))
-
-/* Tuner inputs vs. msp version */
-/* Chip      TUNER_1   TUNER_2
-   -------------------------
-   msp34x0b  y         y
-   msp34x0c  y         y
-   msp34x0d  y         y
-   msp34x5d  y         n
-   msp34x7d  y         n
-   msp34x0g  y         y
-   msp34x1g  y         y
-   msp34x2g  y         y
-   msp34x5g  y         n
-   msp34x7g  y         n
-   msp44x0g  y         y
-   msp44x8g  y         y
- */
-
-/* SCART inputs vs. msp version */
-/* Chip      SC1 SC2 SC3 SC4
-   -------------------------
-   msp34x0b  y   y   y   n
-   msp34x0c  y   y   y   n
-   msp34x0d  y   y   y   y
-   msp34x5d  y   y   n   n
-   msp34x7d  y   n   n   n
-   msp34x0g  y   y   y   y
-   msp34x1g  y   y   y   y
-   msp34x2g  y   y   y   y
-   msp34x5g  y   y   n   n
-   msp34x7g  y   n   n   n
-   msp44x0g  y   y   y   y
-   msp44x8g  y   y   y   y
- */
-
-/* DSP inputs vs. msp version (tuner and SCART inputs are always available) */
-/* Chip      I2S1 I2S2 I2S3 MAIN_AVC MAIN AUX
-   ------------------------------------------
-   msp34x0b  y    n    n    n        n    n
-   msp34x0c  y    y    n    n        n    n
-   msp34x0d  y    y    n    n        n    n
-   msp34x5d  y    y    n    n        n    n
-   msp34x7d  n    n    n    n        n    n
-   msp34x0g  y    y    n    n        n    n
-   msp34x1g  y    y    n    n        n    n
-   msp34x2g  y    y    n    y        y    y
-   msp34x5g  y    y    n    n        n    n
-   msp34x7g  n    n    n    n        n    n
-   msp44x0g  y    y    y    y        y    y
-   msp44x8g  y    y    y    n        n    n
- */
-
-/* DSP outputs vs. msp version */
-/* Chip      MAIN AUX SCART1 SCART2 I2S
-   ------------------------------------
-   msp34x0b  y    y   y      n      y
-   msp34x0c  y    y   y      n      y
-   msp34x0d  y    y   y      y      y
-   msp34x5d  y    n   y      n      y
-   msp34x7d  y    n   y      n      n
-   msp34x0g  y    y   y      y      y
-   msp34x1g  y    y   y      y      y
-   msp34x2g  y    y   y      y      y
-   msp34x5g  y    n   y      n      y
-   msp34x7g  y    n   y      n      n
-   msp44x0g  y    y   y      y      y
-   msp44x8g  y    y   y      y      y
- */
-
-#endif /* MSP3400_H */
-
diff --git a/include/media/mt9m032.h b/include/media/mt9m032.h
deleted file mode 100644 (file)
index c3a7811..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Driver for MT9M032 CMOS Image Sensor from Micron
- *
- * Copyright (C) 2010-2011 Lund Engineering
- * Contact: Gil Lund <gwlund@lundeng.com>
- * Author: Martin Hostettler <martin@neutronstar.dyndns.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef MT9M032_H
-#define MT9M032_H
-
-#define MT9M032_NAME           "mt9m032"
-#define MT9M032_I2C_ADDR       (0xb8 >> 1)
-
-struct mt9m032_platform_data {
-       u32 ext_clock;
-       u32 pix_clock;
-       bool invert_pixclock;
-
-};
-#endif /* MT9M032_H */
diff --git a/include/media/mt9p031.h b/include/media/mt9p031.h
deleted file mode 100644 (file)
index 1ba3612..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef MT9P031_H
-#define MT9P031_H
-
-struct v4l2_subdev;
-
-/*
- * struct mt9p031_platform_data - MT9P031 platform data
- * @ext_freq: Input clock frequency
- * @target_freq: Pixel clock frequency
- */
-struct mt9p031_platform_data {
-       int ext_freq;
-       int target_freq;
-};
-
-#endif
diff --git a/include/media/mt9t001.h b/include/media/mt9t001.h
deleted file mode 100644 (file)
index 03fd63e..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _MEDIA_MT9T001_H
-#define _MEDIA_MT9T001_H
-
-struct mt9t001_platform_data {
-       unsigned int clk_pol:1;
-       unsigned int ext_clk;
-};
-
-#endif
diff --git a/include/media/mt9t112.h b/include/media/mt9t112.h
deleted file mode 100644 (file)
index a43c74a..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/* mt9t112 Camera
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __MT9T112_H__
-#define __MT9T112_H__
-
-#define MT9T112_FLAG_PCLK_RISING_EDGE  (1 << 0)
-#define MT9T112_FLAG_DATAWIDTH_8       (1 << 1) /* default width is 10 */
-
-struct mt9t112_pll_divider {
-       u8 m, n;
-       u8 p1, p2, p3, p4, p5, p6, p7;
-};
-
-/*
- * mt9t112 camera info
- */
-struct mt9t112_camera_info {
-       u32 flags;
-       struct mt9t112_pll_divider divider;
-};
-
-#endif /* __MT9T112_H__ */
diff --git a/include/media/mt9v011.h b/include/media/mt9v011.h
deleted file mode 100644 (file)
index ea29fc7..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* mt9v011 sensor
- *
- * Copyright (C) 2011 Hans Verkuil <hverkuil@xs4all.nl>
- *
- * 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 __MT9V011_H__
-#define __MT9V011_H__
-
-struct mt9v011_platform_data {
-       unsigned xtal;  /* Hz */
-};
-
-#endif
diff --git a/include/media/mt9v022.h b/include/media/mt9v022.h
deleted file mode 100644 (file)
index 4056180..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * mt9v022 sensor
- *
- * 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 __MT9V022_H__
-#define __MT9V022_H__
-
-struct mt9v022_platform_data {
-       unsigned short y_skip_top;      /* Lines to skip at the top */
-};
-
-#endif
diff --git a/include/media/mt9v032.h b/include/media/mt9v032.h
deleted file mode 100644 (file)
index 12175a6..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef _MEDIA_MT9V032_H
-#define _MEDIA_MT9V032_H
-
-struct mt9v032_platform_data {
-       unsigned int clk_pol:1;
-
-       const s64 *link_freqs;
-       s64 link_def_freq;
-};
-
-#endif
diff --git a/include/media/noon010pc30.h b/include/media/noon010pc30.h
deleted file mode 100644 (file)
index 58eafee..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Driver header for NOON010PC30L camera sensor chip.
- *
- * Copyright (c) 2010 Samsung Electronics, Co. Ltd
- * Contact: Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef NOON010PC30_H
-#define NOON010PC30_H
-
-/**
- * @clk_rate: the clock frequency in Hz
- * @gpio_nreset: GPIO driving nRESET pin
- * @gpio_nstby: GPIO driving nSTBY pin
- */
-
-struct noon010pc30_platform_data {
-       unsigned long clk_rate;
-       int gpio_nreset;
-       int gpio_nstby;
-};
-
-#endif /* NOON010PC30_H */
diff --git a/include/media/omap1_camera.h b/include/media/omap1_camera.h
deleted file mode 100644 (file)
index 819767c..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Header for V4L2 SoC Camera driver for OMAP1 Camera Interface
- *
- * Copyright (C) 2010, Janusz Krzysztofik <jkrzyszt@tis.icnet.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.
- */
-
-#ifndef __MEDIA_OMAP1_CAMERA_H_
-#define __MEDIA_OMAP1_CAMERA_H_
-
-#include <linux/bitops.h>
-
-#define OMAP1_CAMERA_IOSIZE            0x1c
-
-enum omap1_cam_vb_mode {
-       OMAP1_CAM_DMA_CONTIG = 0,
-       OMAP1_CAM_DMA_SG,
-};
-
-#define OMAP1_CAMERA_MIN_BUF_COUNT(x)  ((x) == OMAP1_CAM_DMA_CONTIG ? 3 : 2)
-
-struct omap1_cam_platform_data {
-       unsigned long   camexclk_khz;
-       unsigned long   lclk_khz_max;
-       unsigned long   flags;
-};
-
-#define OMAP1_CAMERA_LCLK_RISING       BIT(0)
-#define OMAP1_CAMERA_RST_LOW           BIT(1)
-#define OMAP1_CAMERA_RST_HIGH          BIT(2)
-
-#endif /* __MEDIA_OMAP1_CAMERA_H_ */
diff --git a/include/media/omap4iss.h b/include/media/omap4iss.h
deleted file mode 100644 (file)
index 0d7620d..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-#ifndef ARCH_ARM_PLAT_OMAP4_ISS_H
-#define ARCH_ARM_PLAT_OMAP4_ISS_H
-
-#include <linux/i2c.h>
-
-struct iss_device;
-
-enum iss_interface_type {
-       ISS_INTERFACE_CSI2A_PHY1,
-       ISS_INTERFACE_CSI2B_PHY2,
-};
-
-/**
- * struct iss_csiphy_lane: CSI2 lane position and polarity
- * @pos: position of the lane
- * @pol: polarity of the lane
- */
-struct iss_csiphy_lane {
-       u8 pos;
-       u8 pol;
-};
-
-#define ISS_CSIPHY1_NUM_DATA_LANES     4
-#define ISS_CSIPHY2_NUM_DATA_LANES     1
-
-/**
- * struct iss_csiphy_lanes_cfg - CSI2 lane configuration
- * @data: Configuration of one or two data lanes
- * @clk: Clock lane configuration
- */
-struct iss_csiphy_lanes_cfg {
-       struct iss_csiphy_lane data[ISS_CSIPHY1_NUM_DATA_LANES];
-       struct iss_csiphy_lane clk;
-};
-
-/**
- * struct iss_csi2_platform_data - CSI2 interface platform data
- * @crc: Enable the cyclic redundancy check
- * @vpclk_div: Video port output clock control
- */
-struct iss_csi2_platform_data {
-       unsigned crc:1;
-       unsigned vpclk_div:2;
-       struct iss_csiphy_lanes_cfg lanecfg;
-};
-
-struct iss_subdev_i2c_board_info {
-       struct i2c_board_info *board_info;
-       int i2c_adapter_id;
-};
-
-struct iss_v4l2_subdevs_group {
-       struct iss_subdev_i2c_board_info *subdevs;
-       enum iss_interface_type interface;
-       union {
-               struct iss_csi2_platform_data csi2;
-       } bus; /* gcc < 4.6.0 chokes on anonymous union initializers */
-};
-
-struct iss_platform_data {
-       struct iss_v4l2_subdevs_group *subdevs;
-       void (*set_constraints)(struct iss_device *iss, bool enable);
-};
-
-#endif
diff --git a/include/media/ov2659.h b/include/media/ov2659.h
deleted file mode 100644 (file)
index 4216adc..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Omnivision OV2659 CMOS Image Sensor driver
- *
- * Copyright (C) 2015 Texas Instruments, Inc.
- *
- * Benoit Parrot <bparrot@ti.com>
- * Lad, Prabhakar <prabhakar.csengg@gmail.com>
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef OV2659_H
-#define OV2659_H
-
-/**
- * struct ov2659_platform_data - ov2659 driver platform data
- * @link_frequency: target pixel clock frequency
- */
-struct ov2659_platform_data {
-       s64 link_frequency;
-};
-
-#endif /* OV2659_H */
diff --git a/include/media/ov7670.h b/include/media/ov7670.h
deleted file mode 100644 (file)
index 1913d51..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * A V4L2 driver for OmniVision OV7670 cameras.
- *
- * Copyright 2010 One Laptop Per Child
- *
- * This file may be distributed under the terms of the GNU General
- * Public License, version 2.
- */
-
-#ifndef __OV7670_H
-#define __OV7670_H
-
-struct ov7670_config {
-       int min_width;                  /* Filter out smaller sizes */
-       int min_height;                 /* Filter out smaller sizes */
-       int clock_speed;                /* External clock speed (MHz) */
-       bool use_smbus;                 /* Use smbus I/O instead of I2C */
-       bool pll_bypass;                /* Choose whether to bypass the PLL */
-       bool pclk_hb_disable;           /* Disable toggling pixclk during horizontal blanking */
-};
-
-#endif
diff --git a/include/media/ov772x.h b/include/media/ov772x.h
deleted file mode 100644 (file)
index 00dbb7c..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * ov772x Camera
- *
- * Copyright (C) 2008 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __OV772X_H__
-#define __OV772X_H__
-
-/* for flags */
-#define OV772X_FLAG_VFLIP      (1 << 0) /* Vertical flip image */
-#define OV772X_FLAG_HFLIP      (1 << 1) /* Horizontal flip image */
-
-/*
- * for Edge ctrl
- *
- * strength also control Auto or Manual Edge Control Mode
- * see also OV772X_MANUAL_EDGE_CTRL
- */
-struct ov772x_edge_ctrl {
-       unsigned char strength;
-       unsigned char threshold;
-       unsigned char upper;
-       unsigned char lower;
-};
-
-#define OV772X_MANUAL_EDGE_CTRL                0x80 /* un-used bit of strength */
-#define OV772X_EDGE_STRENGTH_MASK      0x1F
-#define OV772X_EDGE_THRESHOLD_MASK     0x0F
-#define OV772X_EDGE_UPPER_MASK         0xFF
-#define OV772X_EDGE_LOWER_MASK         0xFF
-
-#define OV772X_AUTO_EDGECTRL(u, l)     \
-{                                      \
-       .upper = (u & OV772X_EDGE_UPPER_MASK),  \
-       .lower = (l & OV772X_EDGE_LOWER_MASK),  \
-}
-
-#define OV772X_MANUAL_EDGECTRL(s, t)                   \
-{                                                      \
-       .strength  = (s & OV772X_EDGE_STRENGTH_MASK) |  \
-                       OV772X_MANUAL_EDGE_CTRL,        \
-       .threshold = (t & OV772X_EDGE_THRESHOLD_MASK),  \
-}
-
-/*
- * ov772x camera info
- */
-struct ov772x_camera_info {
-       unsigned long           flags;
-       struct ov772x_edge_ctrl edgectrl;
-};
-
-#endif /* __OV772X_H__ */
diff --git a/include/media/ov9650.h b/include/media/ov9650.h
deleted file mode 100644 (file)
index d630cf9..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * OV9650/OV9652 camera sensors driver
- *
- * Copyright (C) 2013 Sylwester Nawrocki <sylvester.nawrocki@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.
- */
-#ifndef OV9650_H_
-#define OV9650_H_
-
-/**
- * struct ov9650_platform_data - ov9650 driver platform data
- * @mclk_frequency: the sensor's master clock frequency in Hz
- * @gpio_pwdn:     number of a GPIO connected to OV965X PWDN pin
- * @gpio_reset:     number of a GPIO connected to OV965X RESET pin
- *
- * If any of @gpio_pwdn or @gpio_reset are unused then they should be
- * set to a negative value. @mclk_frequency must always be specified.
- */
-struct ov9650_platform_data {
-       unsigned long mclk_frequency;
-       int gpio_pwdn;
-       int gpio_reset;
-};
-#endif /* OV9650_H_ */
index ec921f6538c777db5d81deb655ecfdf6facc4b83..f6494709e230d0a34a5486ccb89236494a53edb7 100644 (file)
@@ -239,6 +239,7 @@ static inline void init_ir_raw_event(struct ir_raw_event *ev)
        memset(ev, 0, sizeof(*ev));
 }
 
+#define IR_DEFAULT_TIMEOUT     MS_TO_NS(125)
 #define IR_MAX_DURATION         500000000      /* 500 ms */
 #define US_TO_NS(usec)         ((usec) * 1000)
 #define MS_TO_US(msec)         ((msec) * 1000)
index 7c4bbc4dfab4b72c49e6432dcbf6a42cc94e7d89..7844e9879497efb4350d53a83cb87df6485e3c14 100644 (file)
@@ -33,26 +33,26 @@ enum rc_type {
        RC_TYPE_XMP             = 18,   /* XMP protocol */
 };
 
-#define RC_BIT_NONE            0
-#define RC_BIT_UNKNOWN         (1 << RC_TYPE_UNKNOWN)
-#define RC_BIT_OTHER           (1 << RC_TYPE_OTHER)
-#define RC_BIT_RC5             (1 << RC_TYPE_RC5)
-#define RC_BIT_RC5X            (1 << RC_TYPE_RC5X)
-#define RC_BIT_RC5_SZ          (1 << RC_TYPE_RC5_SZ)
-#define RC_BIT_JVC             (1 << RC_TYPE_JVC)
-#define RC_BIT_SONY12          (1 << RC_TYPE_SONY12)
-#define RC_BIT_SONY15          (1 << RC_TYPE_SONY15)
-#define RC_BIT_SONY20          (1 << RC_TYPE_SONY20)
-#define RC_BIT_NEC             (1 << RC_TYPE_NEC)
-#define RC_BIT_SANYO           (1 << RC_TYPE_SANYO)
-#define RC_BIT_MCE_KBD         (1 << RC_TYPE_MCE_KBD)
-#define RC_BIT_RC6_0           (1 << RC_TYPE_RC6_0)
-#define RC_BIT_RC6_6A_20       (1 << RC_TYPE_RC6_6A_20)
-#define RC_BIT_RC6_6A_24       (1 << RC_TYPE_RC6_6A_24)
-#define RC_BIT_RC6_6A_32       (1 << RC_TYPE_RC6_6A_32)
-#define RC_BIT_RC6_MCE         (1 << RC_TYPE_RC6_MCE)
-#define RC_BIT_SHARP           (1 << RC_TYPE_SHARP)
-#define RC_BIT_XMP             (1 << RC_TYPE_XMP)
+#define RC_BIT_NONE            0ULL
+#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_RC5_SZ          (1ULL << RC_TYPE_RC5_SZ)
+#define RC_BIT_JVC             (1ULL << RC_TYPE_JVC)
+#define RC_BIT_SONY12          (1ULL << RC_TYPE_SONY12)
+#define RC_BIT_SONY15          (1ULL << RC_TYPE_SONY15)
+#define RC_BIT_SONY20          (1ULL << RC_TYPE_SONY20)
+#define RC_BIT_NEC             (1ULL << RC_TYPE_NEC)
+#define RC_BIT_SANYO           (1ULL << RC_TYPE_SANYO)
+#define RC_BIT_MCE_KBD         (1ULL << RC_TYPE_MCE_KBD)
+#define RC_BIT_RC6_0           (1ULL << RC_TYPE_RC6_0)
+#define RC_BIT_RC6_6A_20       (1ULL << RC_TYPE_RC6_6A_20)
+#define RC_BIT_RC6_6A_24       (1ULL << RC_TYPE_RC6_6A_24)
+#define RC_BIT_RC6_6A_32       (1ULL << RC_TYPE_RC6_6A_32)
+#define RC_BIT_RC6_MCE         (1ULL << RC_TYPE_RC6_MCE)
+#define RC_BIT_SHARP           (1ULL << RC_TYPE_SHARP)
+#define RC_BIT_XMP             (1ULL << RC_TYPE_XMP)
 
 #define RC_BIT_ALL     (RC_BIT_UNKNOWN | RC_BIT_OTHER | \
                         RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ | \
diff --git a/include/media/rj54n1cb0c.h b/include/media/rj54n1cb0c.h
deleted file mode 100644 (file)
index 8ae3288..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * RJ54N1CB0C Private data
- *
- * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.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.
- */
-
-#ifndef __RJ54N1CB0C_H__
-#define __RJ54N1CB0C_H__
-
-struct rj54n1_pdata {
-       unsigned int    mclk_freq;
-       bool            ioctl_high;
-};
-
-#endif
diff --git a/include/media/s3c_camif.h b/include/media/s3c_camif.h
deleted file mode 100644 (file)
index df96c2c..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * s3c24xx/s3c64xx SoC series Camera Interface (CAMIF) driver
- *
- * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@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.
-*/
-
-#ifndef MEDIA_S3C_CAMIF_
-#define MEDIA_S3C_CAMIF_
-
-#include <linux/i2c.h>
-#include <media/v4l2-mediabus.h>
-
-/**
- * struct s3c_camif_sensor_info - an image sensor description
- * @i2c_board_info: pointer to an I2C sensor subdevice board info
- * @clock_frequency: frequency of the clock the host provides to a sensor
- * @mbus_type: media bus type
- * @i2c_bus_num: i2c control bus id the sensor is attached to
- * @flags: the parallel bus flags defining signals polarity (V4L2_MBUS_*)
- * @use_field: 1 if parallel bus FIELD signal is used (only s3c64xx)
- */
-struct s3c_camif_sensor_info {
-       struct i2c_board_info i2c_board_info;
-       unsigned long clock_frequency;
-       enum v4l2_mbus_type mbus_type;
-       u16 i2c_bus_num;
-       u16 flags;
-       u8 use_field;
-};
-
-struct s3c_camif_plat_data {
-       struct s3c_camif_sensor_info sensor;
-       int (*gpio_get)(void);
-       int (*gpio_put)(void);
-};
-
-/* Platform default helper functions */
-int s3c_camif_gpio_get(void);
-int s3c_camif_gpio_put(void);
-
-#endif /* MEDIA_S3C_CAMIF_ */
diff --git a/include/media/s5c73m3.h b/include/media/s5c73m3.h
deleted file mode 100644 (file)
index ccb9e54..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Samsung LSI S5C73M3 8M pixel camera driver
- *
- * Copyright (C) 2012, Samsung Electronics, Co., Ltd.
- * Sylwester Nawrocki <s.nawrocki@samsung.com>
- * Andrzej Hajda <a.hajda@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.
- *
- * This program is 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 MEDIA_S5C73M3__
-#define MEDIA_S5C73M3__
-
-#include <linux/videodev2.h>
-#include <media/v4l2-mediabus.h>
-
-/**
- * struct s5c73m3_gpio - data structure describing a GPIO
- * @gpio:  GPIO number
- * @level: indicates active state of the @gpio
- */
-struct s5c73m3_gpio {
-       int gpio;
-       int level;
-};
-
-/**
- * struct s5c73m3_platform_data - s5c73m3 driver platform data
- * @mclk_frequency: sensor's master clock frequency in Hz
- * @gpio_reset:  GPIO driving RESET pin
- * @gpio_stby:   GPIO driving STBY pin
- * @nlanes:      maximum number of MIPI-CSI lanes used
- * @horiz_flip:  default horizontal image flip value, non zero to enable
- * @vert_flip:   default vertical image flip value, non zero to enable
- */
-
-struct s5c73m3_platform_data {
-       unsigned long mclk_frequency;
-
-       struct s5c73m3_gpio gpio_reset;
-       struct s5c73m3_gpio gpio_stby;
-
-       enum v4l2_mbus_type bus_type;
-       u8 nlanes;
-       u8 horiz_flip;
-       u8 vert_flip;
-};
-
-#endif /* MEDIA_S5C73M3__ */
diff --git a/include/media/s5k4ecgx.h b/include/media/s5k4ecgx.h
deleted file mode 100644 (file)
index 90c1be7..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * S5K4ECGX image sensor header file
- *
- * Copyright (C) 2012, Linaro
- * Copyright (C) 2012, Samsung Electronics Co., Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef S5K4ECGX_H
-#define S5K4ECGX_H
-
-/**
- * struct s5k4ecgx_gpio - data structure describing a GPIO
- * @gpio : GPIO number
- * @level: indicates active state of the @gpio
- */
-struct s5k4ecgx_gpio {
-       int gpio;
-       int level;
-};
-
-/**
- * struct ss5k4ecgx_platform_data- s5k4ecgx driver platform data
- * @gpio_reset:         GPIO driving RESET pin
- * @gpio_stby :         GPIO driving STBY pin
- */
-
-struct s5k4ecgx_platform_data {
-       struct s5k4ecgx_gpio gpio_reset;
-       struct s5k4ecgx_gpio gpio_stby;
-};
-
-#endif /* S5K4ECGX_H */
diff --git a/include/media/s5k6aa.h b/include/media/s5k6aa.h
deleted file mode 100644 (file)
index ba34f70..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * S5K6AAFX camera sensor driver header
- *
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef S5K6AA_H
-#define S5K6AA_H
-
-#include <media/v4l2-mediabus.h>
-
-/**
- * struct s5k6aa_gpio - data structure describing a GPIO
- * @gpio:  GPIO number
- * @level: indicates active state of the @gpio
- */
-struct s5k6aa_gpio {
-       int gpio;
-       int level;
-};
-
-/**
- * struct s5k6aa_platform_data - s5k6aa driver platform data
- * @set_power:   an additional callback to the board code, called
- *               after enabling the regulators and before switching
- *               the sensor off
- * @mclk_frequency: sensor's master clock frequency in Hz
- * @gpio_reset:  GPIO driving RESET pin
- * @gpio_stby:   GPIO driving STBY pin
- * @nlanes:      maximum number of MIPI-CSI lanes used
- * @horiz_flip:  default horizontal image flip value, non zero to enable
- * @vert_flip:   default vertical image flip value, non zero to enable
- */
-
-struct s5k6aa_platform_data {
-       int (*set_power)(int enable);
-       unsigned long mclk_frequency;
-       struct s5k6aa_gpio gpio_reset;
-       struct s5k6aa_gpio gpio_stby;
-       enum v4l2_mbus_type bus_type;
-       u8 nlanes;
-       u8 horiz_flip;
-       u8 vert_flip;
-};
-
-#endif /* S5K6AA_H */
diff --git a/include/media/s5p_hdmi.h b/include/media/s5p_hdmi.h
deleted file mode 100644 (file)
index 181642b..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Driver header for S5P HDMI chip.
- *
- * Copyright (c) 2011 Samsung Electronics, Co. Ltd
- * Contact: Tomasz Stanislawski <t.stanislaws@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef S5P_HDMI_H
-#define S5P_HDMI_H
-
-struct i2c_board_info;
-
-/**
- * @hdmiphy_bus: controller id for HDMIPHY bus
- * @hdmiphy_info: template for HDMIPHY I2C device
- * @mhl_bus: controller id for MHL control bus
- * @mhl_info: template for MHL I2C device
- * @hpd_gpio: GPIO for Hot-Plug-Detect pin
- *
- * NULL pointer for *_info fields indicates that
- * the corresponding chip is not present
- */
-struct s5p_hdmi_platform_data {
-       int hdmiphy_bus;
-       struct i2c_board_info *hdmiphy_info;
-       int mhl_bus;
-       struct i2c_board_info *mhl_info;
-       int hpd_gpio;
-};
-
-#endif /* S5P_HDMI_H */
-
diff --git a/include/media/saa6588.h b/include/media/saa6588.h
deleted file mode 100644 (file)
index b5ec1aa..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
-
-    Types and defines needed for RDS. This is included by
-    saa6588.c and every driver (e.g. bttv-driver.c) that wants
-    to use the saa6588 module.
-
-    (c) 2005 by Hans J. Koch
-
-    This program is 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 _SAA6588_H
-#define _SAA6588_H
-
-struct saa6588_command {
-       unsigned int  block_count;
-       bool          nonblocking;
-       int           result;
-       unsigned char __user *buffer;
-       struct file   *instance;
-       poll_table    *event_list;
-};
-
-/* These ioctls are internal to the kernel */
-#define SAA6588_CMD_CLOSE      _IOW('R', 2, int)
-#define SAA6588_CMD_READ       _IOR('R', 3, int)
-#define SAA6588_CMD_POLL       _IOR('R', 4, int)
-
-#endif
diff --git a/include/media/saa7115.h b/include/media/saa7115.h
deleted file mode 100644 (file)
index 76911e7..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
-    saa7115.h - definition for saa7111/3/4/5 inputs and frequency flags
-
-    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
-
-    This program is 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 _SAA7115_H_
-#define _SAA7115_H_
-
-/* s_routing inputs, outputs, and config */
-
-/* SAA7111/3/4/5 HW inputs */
-#define SAA7115_COMPOSITE0 0
-#define SAA7115_COMPOSITE1 1
-#define SAA7115_COMPOSITE2 2
-#define SAA7115_COMPOSITE3 3
-#define SAA7115_COMPOSITE4 4 /* not available for the saa7111/3 */
-#define SAA7115_COMPOSITE5 5 /* not available for the saa7111/3 */
-#define SAA7115_SVIDEO0    6
-#define SAA7115_SVIDEO1    7
-#define SAA7115_SVIDEO2    8
-#define SAA7115_SVIDEO3    9
-
-/* outputs */
-#define SAA7115_IPORT_ON       1
-#define SAA7115_IPORT_OFF      0
-
-/* SAA7111 specific outputs. */
-#define SAA7111_VBI_BYPASS     2
-#define SAA7111_FMT_YUV422      0x00
-#define SAA7111_FMT_RGB        0x40
-#define SAA7111_FMT_CCIR       0x80
-#define SAA7111_FMT_YUV411     0xc0
-
-/* config flags */
-/*
- * Register 0x85 should set bit 0 to 0 (it's 1 by default). This bit
- * controls the IDQ signal polarity which is set to 'inverted' if the bit
- * it 1 and to 'default' if it is 0.
- */
-#define SAA7115_IDQ_IS_DEFAULT  (1 << 0)
-
-/* s_crystal_freq values and flags */
-
-/* SAA7115 v4l2_crystal_freq frequency values */
-#define SAA7115_FREQ_32_11_MHZ  32110000   /* 32.11 MHz crystal, SAA7114/5 only */
-#define SAA7115_FREQ_24_576_MHZ 24576000   /* 24.576 MHz crystal */
-
-/* SAA7115 v4l2_crystal_freq audio clock control flags */
-#define SAA7115_FREQ_FL_UCGC         (1 << 0) /* SA 3A[7], UCGC, SAA7115 only */
-#define SAA7115_FREQ_FL_CGCDIV       (1 << 1) /* SA 3A[6], CGCDIV, SAA7115 only */
-#define SAA7115_FREQ_FL_APLL         (1 << 2) /* SA 3A[3], APLL, SAA7114/5 only */
-#define SAA7115_FREQ_FL_DOUBLE_ASCLK (1 << 3) /* SA 39, LRDIV, SAA7114/5 only */
-
-/* ===== SAA7113 Config enums ===== */
-
-/* Register 0x08 "Horizontal time constant" [Bit 3..4]:
- * Should be set to "Fast Locking Mode" according to the datasheet,
- * and that is the default setting in the gm7113c_init table.
- * saa7113_init sets this value to "VTR Mode". */
-enum saa7113_r08_htc {
-       SAA7113_HTC_TV_MODE = 0x00,
-       SAA7113_HTC_VTR_MODE,                   /* Default for saa7113_init */
-       SAA7113_HTC_FAST_LOCKING_MODE = 0x03    /* Default for gm7113c_init */
-};
-
-/* Register 0x10 "Output format selection" [Bit 6..7]:
- * Defaults to ITU_656 as specified in datasheet. */
-enum saa7113_r10_ofts {
-       SAA7113_OFTS_ITU_656 = 0x0,     /* Default */
-       SAA7113_OFTS_VFLAG_BY_VREF,
-       SAA7113_OFTS_VFLAG_BY_DATA_TYPE
-};
-
-/*
- * Register 0x12 "Output control" [Bit 0..3 Or Bit 4..7]:
- * This is used to select what data is output on the RTS0 and RTS1 pins.
- * RTS1 [Bit 4..7] Defaults to DOT_IN. (This value can not be set for RTS0)
- * RTS0 [Bit 0..3] Defaults to VIPB in gm7113c_init as specified
- * in the datasheet, but is set to HREF_HS in the saa7113_init table.
- */
-enum saa7113_r12_rts {
-       SAA7113_RTS_DOT_IN = 0,         /* OBS: Only for RTS1 (Default RTS1) */
-       SAA7113_RTS_VIPB,               /* Default RTS0 For gm7113c_init */
-       SAA7113_RTS_GPSW,
-       SAA7115_RTS_HL,
-       SAA7113_RTS_VL,
-       SAA7113_RTS_DL,
-       SAA7113_RTS_PLIN,
-       SAA7113_RTS_HREF_HS,            /* Default RTS0 For saa7113_init */
-       SAA7113_RTS_HS,
-       SAA7113_RTS_HQ,
-       SAA7113_RTS_ODD,
-       SAA7113_RTS_VS,
-       SAA7113_RTS_V123,
-       SAA7113_RTS_VGATE,
-       SAA7113_RTS_VREF,
-       SAA7113_RTS_FID
-};
-
-/**
- * struct saa7115_platform_data - Allow overriding default initialization
- *
- * @saa7113_force_gm7113c_init:        Force the use of the gm7113c_init table
- *                             instead of saa7113_init table
- *                             (saa7113 only)
- * @saa7113_r08_htc:           [R_08 - Bit 3..4]
- * @saa7113_r10_vrln:          [R_10 - Bit 3]
- *                             default: Disabled for gm7113c_init
- *                                      Enabled for saa7113c_init
- * @saa7113_r10_ofts:          [R_10 - Bit 6..7]
- * @saa7113_r12_rts0:          [R_12 - Bit 0..3]
- * @saa7113_r12_rts1:          [R_12 - Bit 4..7]
- * @saa7113_r13_adlsb:         [R_13 - Bit 7] - default: disabled
- */
-struct saa7115_platform_data {
-       bool saa7113_force_gm7113c_init;
-       enum saa7113_r08_htc *saa7113_r08_htc;
-       bool *saa7113_r10_vrln;
-       enum saa7113_r10_ofts *saa7113_r10_ofts;
-       enum saa7113_r12_rts *saa7113_r12_rts0;
-       enum saa7113_r12_rts *saa7113_r12_rts1;
-       bool *saa7113_r13_adlsb;
-};
-
-#endif
-
diff --git a/include/media/saa7127.h b/include/media/saa7127.h
deleted file mode 100644 (file)
index bbcf862..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-    saa7127.h - definition for saa7126/7/8/9 inputs/outputs
-
-    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
-
-    This program is 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 _SAA7127_H_
-#define _SAA7127_H_
-
-/* Enumeration for the supported input types */
-enum saa7127_input_type {
-       SAA7127_INPUT_TYPE_NORMAL,
-       SAA7127_INPUT_TYPE_TEST_IMAGE
-};
-
-/* Enumeration for the supported output signal types */
-enum saa7127_output_type {
-       SAA7127_OUTPUT_TYPE_BOTH,
-       SAA7127_OUTPUT_TYPE_COMPOSITE,
-       SAA7127_OUTPUT_TYPE_SVIDEO,
-       SAA7127_OUTPUT_TYPE_RGB,
-       SAA7127_OUTPUT_TYPE_YUV_C,
-       SAA7127_OUTPUT_TYPE_YUV_V
-};
-
-#endif
-
diff --git a/include/media/saa7146.h b/include/media/saa7146.h
deleted file mode 100644 (file)
index 96058a5..0000000
+++ /dev/null
@@ -1,471 +0,0 @@
-#ifndef __SAA7146__
-#define __SAA7146__
-
-#include <linux/delay.h>       /* for delay-stuff */
-#include <linux/slab.h>                /* for kmalloc/kfree */
-#include <linux/pci.h>         /* for pci-config-stuff, vendor ids etc. */
-#include <linux/init.h>                /* for "__init" */
-#include <linux/interrupt.h>   /* for IMMEDIATE_BH */
-#include <linux/kmod.h>                /* for kernel module loader */
-#include <linux/i2c.h>         /* for i2c subsystem */
-#include <asm/io.h>            /* for accessing devices */
-#include <linux/stringify.h>
-#include <linux/mutex.h>
-#include <linux/scatterlist.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ctrls.h>
-
-#include <linux/vmalloc.h>     /* for vmalloc() */
-#include <linux/mm.h>          /* for vmalloc_to_page() */
-
-#define saa7146_write(sxy,adr,dat)    writel((dat),(sxy->mem+(adr)))
-#define saa7146_read(sxy,adr)         readl(sxy->mem+(adr))
-
-extern unsigned int saa7146_debug;
-
-#ifndef DEBUG_VARIABLE
-       #define DEBUG_VARIABLE saa7146_debug
-#endif
-
-#define ERR(fmt, ...)  pr_err("%s: " fmt, __func__, ##__VA_ARGS__)
-
-#define _DBG(mask, fmt, ...)                                           \
-do {                                                                   \
-       if (DEBUG_VARIABLE & mask)                                      \
-               pr_debug("%s(): " fmt, __func__, ##__VA_ARGS__);        \
-} while (0)
-
-/* simple debug messages */
-#define DEB_S(fmt, ...)                _DBG(0x01, fmt, ##__VA_ARGS__)
-/* more detailed debug messages */
-#define DEB_D(fmt, ...)                _DBG(0x02, fmt, ##__VA_ARGS__)
-/* print enter and exit of functions */
-#define DEB_EE(fmt, ...)       _DBG(0x04, fmt, ##__VA_ARGS__)
-/* i2c debug messages */
-#define DEB_I2C(fmt, ...)      _DBG(0x08, fmt, ##__VA_ARGS__)
-/* vbi debug messages */
-#define DEB_VBI(fmt, ...)      _DBG(0x10, fmt, ##__VA_ARGS__)
-/* interrupt debug messages */
-#define DEB_INT(fmt, ...)      _DBG(0x20, fmt, ##__VA_ARGS__)
-/* capture debug messages */
-#define DEB_CAP(fmt, ...)      _DBG(0x40, fmt, ##__VA_ARGS__)
-
-#define SAA7146_ISR_CLEAR(x,y) \
-       saa7146_write(x, ISR, (y));
-
-struct module;
-
-struct saa7146_dev;
-struct saa7146_extension;
-struct saa7146_vv;
-
-/* saa7146 page table */
-struct saa7146_pgtable {
-       unsigned int    size;
-       __le32          *cpu;
-       dma_addr_t      dma;
-       /* used for offsets for u,v planes for planar capture modes */
-       unsigned long   offset;
-       /* used for custom pagetables (used for example by budget dvb cards) */
-       struct scatterlist *slist;
-       int             nents;
-};
-
-struct saa7146_pci_extension_data {
-       struct saa7146_extension *ext;
-       void *ext_priv;                 /* most likely a name string */
-};
-
-#define MAKE_EXTENSION_PCI(x_var, x_vendor, x_device)          \
-       {                                                       \
-               .vendor    = PCI_VENDOR_ID_PHILIPS,             \
-               .device    = PCI_DEVICE_ID_PHILIPS_SAA7146,     \
-               .subvendor = x_vendor,                          \
-               .subdevice = x_device,                          \
-               .driver_data = (unsigned long)& x_var,          \
-       }
-
-struct saa7146_extension
-{
-       char    name[32];               /* name of the device */
-#define SAA7146_USE_I2C_IRQ    0x1
-#define SAA7146_I2C_SHORT_DELAY        0x2
-       int     flags;
-
-       /* pairs of subvendor and subdevice ids for
-          supported devices, last entry 0xffff, 0xfff */
-       struct module *module;
-       struct pci_driver driver;
-       struct pci_device_id *pci_tbl;
-
-       /* extension functions */
-       int (*probe)(struct saa7146_dev *);
-       int (*attach)(struct saa7146_dev *, struct saa7146_pci_extension_data *);
-       int (*detach)(struct saa7146_dev*);
-
-       u32     irq_mask;       /* mask to indicate, which irq-events are handled by the extension */
-       void    (*irq_func)(struct saa7146_dev*, u32* irq_mask);
-};
-
-struct saa7146_dma
-{
-       dma_addr_t      dma_handle;
-       __le32          *cpu_addr;
-};
-
-struct saa7146_dev
-{
-       struct module                   *module;
-
-       struct v4l2_device              v4l2_dev;
-       struct v4l2_ctrl_handler        ctrl_handler;
-
-       /* different device locks */
-       spinlock_t                      slock;
-       struct mutex                    v4l2_lock;
-
-       unsigned char                   __iomem *mem;           /* pointer to mapped IO memory */
-       u32                             revision;       /* chip revision; needed for bug-workarounds*/
-
-       /* pci-device & irq stuff*/
-       char                            name[32];
-       struct pci_dev                  *pci;
-       u32                             int_todo;
-       spinlock_t                      int_slock;
-
-       /* extension handling */
-       struct saa7146_extension        *ext;           /* indicates if handled by extension */
-       void                            *ext_priv;      /* pointer for extension private use (most likely some private data) */
-       struct saa7146_ext_vv           *ext_vv_data;
-
-       /* per device video/vbi informations (if available) */
-       struct saa7146_vv       *vv_data;
-       void (*vv_callback)(struct saa7146_dev *dev, unsigned long status);
-
-       /* i2c-stuff */
-       struct mutex                    i2c_lock;
-
-       u32                             i2c_bitrate;
-       struct saa7146_dma              d_i2c;  /* pointer to i2c memory */
-       wait_queue_head_t               i2c_wq;
-       int                             i2c_op;
-
-       /* memories */
-       struct saa7146_dma              d_rps0;
-       struct saa7146_dma              d_rps1;
-};
-
-static inline struct saa7146_dev *to_saa7146_dev(struct v4l2_device *v4l2_dev)
-{
-       return container_of(v4l2_dev, struct saa7146_dev, v4l2_dev);
-}
-
-/* from saa7146_i2c.c */
-int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate);
-
-/* from saa7146_core.c */
-int saa7146_register_extension(struct saa7146_extension*);
-int saa7146_unregister_extension(struct saa7146_extension*);
-struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc);
-int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt);
-void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt);
-int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, struct scatterlist *list, int length );
-void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt);
-void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt);
-void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data);
-int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop);
-
-/* some memory sizes */
-#define SAA7146_I2C_MEM                ( 1*PAGE_SIZE)
-#define SAA7146_RPS_MEM                ( 1*PAGE_SIZE)
-
-/* some i2c constants */
-#define SAA7146_I2C_TIMEOUT    100     /* i2c-timeout-value in ms */
-#define SAA7146_I2C_RETRIES    3       /* how many times shall we retry an i2c-operation? */
-#define SAA7146_I2C_DELAY      5       /* time we wait after certain i2c-operations */
-
-/* unsorted defines */
-#define ME1    0x0000000800
-#define PV1    0x0000000008
-
-/* gpio defines */
-#define SAA7146_GPIO_INPUT 0x00
-#define SAA7146_GPIO_IRQHI 0x10
-#define SAA7146_GPIO_IRQLO 0x20
-#define SAA7146_GPIO_IRQHL 0x30
-#define SAA7146_GPIO_OUTLO 0x40
-#define SAA7146_GPIO_OUTHI 0x50
-
-/* debi defines */
-#define DEBINOSWAP 0x000e0000
-
-/* define for the register programming sequencer (rps) */
-#define CMD_NOP                0x00000000  /* No operation */
-#define CMD_CLR_EVENT  0x00000000  /* Clear event */
-#define CMD_SET_EVENT  0x10000000  /* Set signal event */
-#define CMD_PAUSE      0x20000000  /* Pause */
-#define CMD_CHECK_LATE 0x30000000  /* Check late */
-#define CMD_UPLOAD     0x40000000  /* Upload */
-#define CMD_STOP       0x50000000  /* Stop */
-#define CMD_INTERRUPT  0x60000000  /* Interrupt */
-#define CMD_JUMP       0x80000000  /* Jump */
-#define CMD_WR_REG     0x90000000  /* Write (load) register */
-#define CMD_RD_REG     0xa0000000  /* Read (store) register */
-#define CMD_WR_REG_MASK        0xc0000000  /* Write register with mask */
-
-#define CMD_OAN                MASK_27
-#define CMD_INV                MASK_26
-#define CMD_SIG4       MASK_25
-#define CMD_SIG3       MASK_24
-#define CMD_SIG2       MASK_23
-#define CMD_SIG1       MASK_22
-#define CMD_SIG0       MASK_21
-#define CMD_O_FID_B    MASK_14
-#define CMD_E_FID_B    MASK_13
-#define CMD_O_FID_A    MASK_12
-#define CMD_E_FID_A    MASK_11
-
-/* some events and command modifiers for rps1 squarewave generator */
-#define EVT_HS          (1<<15)     // Source Line Threshold reached
-#define EVT_VBI_B       (1<<9)      // VSYNC Event
-#define RPS_OAN         (1<<27)     // 1: OR events, 0: AND events
-#define RPS_INV         (1<<26)     // Invert (compound) event
-#define GPIO3_MSK       0xFF000000  // GPIO #3 control bits
-
-/* Bit mask constants */
-#define MASK_00   0x00000001    /* Mask value for bit 0 */
-#define MASK_01   0x00000002    /* Mask value for bit 1 */
-#define MASK_02   0x00000004    /* Mask value for bit 2 */
-#define MASK_03   0x00000008    /* Mask value for bit 3 */
-#define MASK_04   0x00000010    /* Mask value for bit 4 */
-#define MASK_05   0x00000020    /* Mask value for bit 5 */
-#define MASK_06   0x00000040    /* Mask value for bit 6 */
-#define MASK_07   0x00000080    /* Mask value for bit 7 */
-#define MASK_08   0x00000100    /* Mask value for bit 8 */
-#define MASK_09   0x00000200    /* Mask value for bit 9 */
-#define MASK_10   0x00000400    /* Mask value for bit 10 */
-#define MASK_11   0x00000800    /* Mask value for bit 11 */
-#define MASK_12   0x00001000    /* Mask value for bit 12 */
-#define MASK_13   0x00002000    /* Mask value for bit 13 */
-#define MASK_14   0x00004000    /* Mask value for bit 14 */
-#define MASK_15   0x00008000    /* Mask value for bit 15 */
-#define MASK_16   0x00010000    /* Mask value for bit 16 */
-#define MASK_17   0x00020000    /* Mask value for bit 17 */
-#define MASK_18   0x00040000    /* Mask value for bit 18 */
-#define MASK_19   0x00080000    /* Mask value for bit 19 */
-#define MASK_20   0x00100000    /* Mask value for bit 20 */
-#define MASK_21   0x00200000    /* Mask value for bit 21 */
-#define MASK_22   0x00400000    /* Mask value for bit 22 */
-#define MASK_23   0x00800000    /* Mask value for bit 23 */
-#define MASK_24   0x01000000    /* Mask value for bit 24 */
-#define MASK_25   0x02000000    /* Mask value for bit 25 */
-#define MASK_26   0x04000000    /* Mask value for bit 26 */
-#define MASK_27   0x08000000    /* Mask value for bit 27 */
-#define MASK_28   0x10000000    /* Mask value for bit 28 */
-#define MASK_29   0x20000000    /* Mask value for bit 29 */
-#define MASK_30   0x40000000    /* Mask value for bit 30 */
-#define MASK_31   0x80000000    /* Mask value for bit 31 */
-
-#define MASK_B0   0x000000ff    /* Mask value for byte 0 */
-#define MASK_B1   0x0000ff00    /* Mask value for byte 1 */
-#define MASK_B2   0x00ff0000    /* Mask value for byte 2 */
-#define MASK_B3   0xff000000    /* Mask value for byte 3 */
-
-#define MASK_W0   0x0000ffff    /* Mask value for word 0 */
-#define MASK_W1   0xffff0000    /* Mask value for word 1 */
-
-#define MASK_PA   0xfffffffc    /* Mask value for physical address */
-#define MASK_PR   0xfffffffe   /* Mask value for protection register */
-#define MASK_ER   0xffffffff    /* Mask value for the entire register */
-
-#define MASK_NONE 0x00000000    /* No mask */
-
-/* register aliases */
-#define BASE_ODD1         0x00  /* Video DMA 1 registers  */
-#define BASE_EVEN1        0x04
-#define PROT_ADDR1        0x08
-#define PITCH1            0x0C
-#define BASE_PAGE1        0x10  /* Video DMA 1 base page */
-#define NUM_LINE_BYTE1    0x14
-
-#define BASE_ODD2         0x18  /* Video DMA 2 registers */
-#define BASE_EVEN2        0x1C
-#define PROT_ADDR2        0x20
-#define PITCH2            0x24
-#define BASE_PAGE2        0x28  /* Video DMA 2 base page */
-#define NUM_LINE_BYTE2    0x2C
-
-#define BASE_ODD3         0x30  /* Video DMA 3 registers */
-#define BASE_EVEN3        0x34
-#define PROT_ADDR3        0x38
-#define PITCH3            0x3C
-#define BASE_PAGE3        0x40  /* Video DMA 3 base page */
-#define NUM_LINE_BYTE3    0x44
-
-#define PCI_BT_V1         0x48  /* Video/FIFO 1 */
-#define PCI_BT_V2         0x49  /* Video/FIFO 2 */
-#define PCI_BT_V3         0x4A  /* Video/FIFO 3 */
-#define PCI_BT_DEBI       0x4B  /* DEBI */
-#define PCI_BT_A          0x4C  /* Audio */
-
-#define DD1_INIT          0x50  /* Init setting of DD1 interface */
-
-#define DD1_STREAM_B      0x54  /* DD1 B video data stream handling */
-#define DD1_STREAM_A      0x56  /* DD1 A video data stream handling */
-
-#define BRS_CTRL          0x58  /* BRS control register */
-#define HPS_CTRL          0x5C  /* HPS control register */
-#define HPS_V_SCALE       0x60  /* HPS vertical scale */
-#define HPS_V_GAIN        0x64  /* HPS vertical ACL and gain */
-#define HPS_H_PRESCALE    0x68  /* HPS horizontal prescale   */
-#define HPS_H_SCALE       0x6C  /* HPS horizontal scale */
-#define BCS_CTRL          0x70  /* BCS control */
-#define CHROMA_KEY_RANGE  0x74
-#define CLIP_FORMAT_CTRL  0x78  /* HPS outputs formats & clipping */
-
-#define DEBI_CONFIG       0x7C
-#define DEBI_COMMAND      0x80
-#define DEBI_PAGE         0x84
-#define DEBI_AD           0x88
-
-#define I2C_TRANSFER      0x8C
-#define I2C_STATUS        0x90
-
-#define BASE_A1_IN        0x94 /* Audio 1 input DMA */
-#define PROT_A1_IN        0x98
-#define PAGE_A1_IN        0x9C
-
-#define BASE_A1_OUT       0xA0  /* Audio 1 output DMA */
-#define PROT_A1_OUT       0xA4
-#define PAGE_A1_OUT       0xA8
-
-#define BASE_A2_IN        0xAC  /* Audio 2 input DMA */
-#define PROT_A2_IN        0xB0
-#define PAGE_A2_IN        0xB4
-
-#define BASE_A2_OUT       0xB8  /* Audio 2 output DMA */
-#define PROT_A2_OUT       0xBC
-#define PAGE_A2_OUT       0xC0
-
-#define RPS_PAGE0         0xC4  /* RPS task 0 page register */
-#define RPS_PAGE1         0xC8  /* RPS task 1 page register */
-
-#define RPS_THRESH0       0xCC  /* HBI threshold for task 0 */
-#define RPS_THRESH1       0xD0  /* HBI threshold for task 1 */
-
-#define RPS_TOV0          0xD4  /* RPS timeout for task 0 */
-#define RPS_TOV1          0xD8  /* RPS timeout for task 1 */
-
-#define IER               0xDC  /* Interrupt enable register */
-
-#define GPIO_CTRL         0xE0  /* GPIO 0-3 register */
-
-#define EC1SSR            0xE4  /* Event cnt set 1 source select */
-#define EC2SSR            0xE8  /* Event cnt set 2 source select */
-#define ECT1R             0xEC  /* Event cnt set 1 thresholds */
-#define ECT2R             0xF0  /* Event cnt set 2 thresholds */
-
-#define ACON1             0xF4
-#define ACON2             0xF8
-
-#define MC1               0xFC   /* Main control register 1 */
-#define MC2               0x100  /* Main control register 2  */
-
-#define RPS_ADDR0         0x104  /* RPS task 0 address register */
-#define RPS_ADDR1         0x108  /* RPS task 1 address register */
-
-#define ISR               0x10C  /* Interrupt status register */
-#define PSR               0x110  /* Primary status register */
-#define SSR               0x114  /* Secondary status register */
-
-#define EC1R              0x118  /* Event counter set 1 register */
-#define EC2R              0x11C  /* Event counter set 2 register */
-
-#define PCI_VDP1          0x120  /* Video DMA pointer of FIFO 1 */
-#define PCI_VDP2          0x124  /* Video DMA pointer of FIFO 2 */
-#define PCI_VDP3          0x128  /* Video DMA pointer of FIFO 3 */
-#define PCI_ADP1          0x12C  /* Audio DMA pointer of audio out 1 */
-#define PCI_ADP2          0x130  /* Audio DMA pointer of audio in 1 */
-#define PCI_ADP3          0x134  /* Audio DMA pointer of audio out 2 */
-#define PCI_ADP4          0x138  /* Audio DMA pointer of audio in 2 */
-#define PCI_DMA_DDP       0x13C  /* DEBI DMA pointer */
-
-#define LEVEL_REP         0x140,
-#define A_TIME_SLOT1      0x180,  /* from 180 - 1BC */
-#define A_TIME_SLOT2      0x1C0,  /* from 1C0 - 1FC */
-
-/* isr masks */
-#define SPCI_PPEF       0x80000000  /* PCI parity error */
-#define SPCI_PABO       0x40000000  /* PCI access error (target or master abort) */
-#define SPCI_PPED       0x20000000  /* PCI parity error on 'real time data' */
-#define SPCI_RPS_I1     0x10000000  /* Interrupt issued by RPS1 */
-#define SPCI_RPS_I0     0x08000000  /* Interrupt issued by RPS0 */
-#define SPCI_RPS_LATE1  0x04000000  /* RPS task 1 is late */
-#define SPCI_RPS_LATE0  0x02000000  /* RPS task 0 is late */
-#define SPCI_RPS_E1     0x01000000  /* RPS error from task 1 */
-#define SPCI_RPS_E0     0x00800000  /* RPS error from task 0 */
-#define SPCI_RPS_TO1    0x00400000  /* RPS timeout task 1 */
-#define SPCI_RPS_TO0    0x00200000  /* RPS timeout task 0 */
-#define SPCI_UPLD       0x00100000  /* RPS in upload */
-#define SPCI_DEBI_S     0x00080000  /* DEBI status */
-#define SPCI_DEBI_E     0x00040000  /* DEBI error */
-#define SPCI_IIC_S      0x00020000  /* I2C status */
-#define SPCI_IIC_E      0x00010000  /* I2C error */
-#define SPCI_A2_IN      0x00008000  /* Audio 2 input DMA protection / limit */
-#define SPCI_A2_OUT     0x00004000  /* Audio 2 output DMA protection / limit */
-#define SPCI_A1_IN      0x00002000  /* Audio 1 input DMA protection / limit */
-#define SPCI_A1_OUT     0x00001000  /* Audio 1 output DMA protection / limit */
-#define SPCI_AFOU       0x00000800  /* Audio FIFO over- / underflow */
-#define SPCI_V_PE       0x00000400  /* Video protection address */
-#define SPCI_VFOU       0x00000200  /* Video FIFO over- / underflow */
-#define SPCI_FIDA       0x00000100  /* Field ID video port A */
-#define SPCI_FIDB       0x00000080  /* Field ID video port B */
-#define SPCI_PIN3       0x00000040  /* GPIO pin 3 */
-#define SPCI_PIN2       0x00000020  /* GPIO pin 2 */
-#define SPCI_PIN1       0x00000010  /* GPIO pin 1 */
-#define SPCI_PIN0       0x00000008  /* GPIO pin 0 */
-#define SPCI_ECS        0x00000004  /* Event counter 1, 2, 4, 5 */
-#define SPCI_EC3S       0x00000002  /* Event counter 3 */
-#define SPCI_EC0S       0x00000001  /* Event counter 0 */
-
-/* i2c */
-#define        SAA7146_I2C_ABORT       (1<<7)
-#define        SAA7146_I2C_SPERR       (1<<6)
-#define        SAA7146_I2C_APERR       (1<<5)
-#define        SAA7146_I2C_DTERR       (1<<4)
-#define        SAA7146_I2C_DRERR       (1<<3)
-#define        SAA7146_I2C_AL          (1<<2)
-#define        SAA7146_I2C_ERR         (1<<1)
-#define        SAA7146_I2C_BUSY        (1<<0)
-
-#define        SAA7146_I2C_START       (0x3)
-#define        SAA7146_I2C_CONT        (0x2)
-#define        SAA7146_I2C_STOP        (0x1)
-#define        SAA7146_I2C_NOP         (0x0)
-
-#define SAA7146_I2C_BUS_BIT_RATE_6400  (0x500)
-#define SAA7146_I2C_BUS_BIT_RATE_3200  (0x100)
-#define SAA7146_I2C_BUS_BIT_RATE_480   (0x400)
-#define SAA7146_I2C_BUS_BIT_RATE_320   (0x600)
-#define SAA7146_I2C_BUS_BIT_RATE_240   (0x700)
-#define SAA7146_I2C_BUS_BIT_RATE_120   (0x000)
-#define SAA7146_I2C_BUS_BIT_RATE_80    (0x200)
-#define SAA7146_I2C_BUS_BIT_RATE_60    (0x300)
-
-static inline void SAA7146_IER_DISABLE(struct saa7146_dev *x, unsigned y)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&x->int_slock, flags);
-       saa7146_write(x, IER, saa7146_read(x, IER) & ~y);
-       spin_unlock_irqrestore(&x->int_slock, flags);
-}
-
-static inline void SAA7146_IER_ENABLE(struct saa7146_dev *x, unsigned y)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&x->int_slock, flags);
-       saa7146_write(x, IER, saa7146_read(x, IER) | y);
-       spin_unlock_irqrestore(&x->int_slock, flags);
-}
-
-#endif
diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h
deleted file mode 100644 (file)
index 92766f7..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-#ifndef __SAA7146_VV__
-#define __SAA7146_VV__
-
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-fh.h>
-#include <media/saa7146.h>
-#include <media/videobuf-dma-sg.h>
-
-#define MAX_SAA7146_CAPTURE_BUFFERS    32      /* arbitrary */
-#define BUFFER_TIMEOUT     (HZ/2)  /* 0.5 seconds */
-
-#define WRITE_RPS0(x) do { \
-       dev->d_rps0.cpu_addr[ count++ ] = cpu_to_le32(x); \
-       } while (0);
-
-#define WRITE_RPS1(x) do { \
-       dev->d_rps1.cpu_addr[ count++ ] = cpu_to_le32(x); \
-       } while (0);
-
-struct saa7146_video_dma {
-       u32 base_odd;
-       u32 base_even;
-       u32 prot_addr;
-       u32 pitch;
-       u32 base_page;
-       u32 num_line_byte;
-};
-
-#define FORMAT_BYTE_SWAP       0x1
-#define FORMAT_IS_PLANAR       0x2
-
-struct saa7146_format {
-       char    *name;
-       u32     pixelformat;
-       u32     trans;
-       u8      depth;
-       u8      flags;
-       u8      swap;
-};
-
-struct saa7146_standard
-{
-       char          *name;
-       v4l2_std_id   id;
-
-       int v_offset;   /* number of lines of vertical offset before processing */
-       int v_field;    /* number of lines in a field for HPS to process */
-
-       int h_offset;   /* horizontal offset of processing window */
-       int h_pixels;   /* number of horizontal pixels to process */
-
-       int v_max_out;
-       int h_max_out;
-};
-
-/* buffer for one video/vbi frame */
-struct saa7146_buf {
-       /* common v4l buffer stuff -- must be first */
-       struct videobuf_buffer vb;
-
-       /* saa7146 specific */
-       struct v4l2_pix_format  *fmt;
-       int (*activate)(struct saa7146_dev *dev,
-                       struct saa7146_buf *buf,
-                       struct saa7146_buf *next);
-
-       /* page tables */
-       struct saa7146_pgtable  pt[3];
-};
-
-struct saa7146_dmaqueue {
-       struct saa7146_dev      *dev;
-       struct saa7146_buf      *curr;
-       struct list_head        queue;
-       struct timer_list       timeout;
-};
-
-struct saa7146_overlay {
-       struct saa7146_fh       *fh;
-       struct v4l2_window      win;
-       struct v4l2_clip        clips[16];
-       int                     nclips;
-};
-
-/* per open data */
-struct saa7146_fh {
-       /* Must be the first field! */
-       struct v4l2_fh          fh;
-       struct saa7146_dev      *dev;
-
-       /* video capture */
-       struct videobuf_queue   video_q;
-
-       /* vbi capture */
-       struct videobuf_queue   vbi_q;
-
-       unsigned int resources; /* resource management for device open */
-};
-
-#define STATUS_OVERLAY 0x01
-#define STATUS_CAPTURE 0x02
-
-struct saa7146_vv
-{
-       /* vbi capture */
-       struct saa7146_dmaqueue         vbi_dmaq;
-       struct v4l2_vbi_format          vbi_fmt;
-       struct timer_list               vbi_read_timeout;
-       /* vbi workaround interrupt queue */
-       wait_queue_head_t               vbi_wq;
-       int                             vbi_fieldcount;
-       struct saa7146_fh               *vbi_streaming;
-
-       int                             video_status;
-       struct saa7146_fh               *video_fh;
-
-       /* video overlay */
-       struct saa7146_overlay          ov;
-       struct v4l2_framebuffer         ov_fb;
-       struct saa7146_format           *ov_fmt;
-       struct saa7146_fh               *ov_suspend;
-
-       /* video capture */
-       struct saa7146_dmaqueue         video_dmaq;
-       struct v4l2_pix_format          video_fmt;
-       enum v4l2_field                 last_field;
-
-       /* common: fixme? shouldn't this be in saa7146_fh?
-          (this leads to a more complicated question: shall the driver
-          store the different settings (for example S_INPUT) for every open
-          and restore it appropriately, or should all settings be common for
-          all opens? currently, we do the latter, like all other
-          drivers do... */
-       struct saa7146_standard *standard;
-
-       int     vflip;
-       int     hflip;
-       int     current_hps_source;
-       int     current_hps_sync;
-
-       struct saa7146_dma      d_clipping;     /* pointer to clipping memory */
-
-       unsigned int resources; /* resource management for device */
-};
-
-/* flags */
-#define SAA7146_USE_PORT_B_FOR_VBI     0x2     /* use input port b for vbi hardware bug workaround */
-
-struct saa7146_ext_vv
-{
-       /* informations about the video capabilities of the device */
-       int     inputs;
-       int     audios;
-       u32     capabilities;
-       int     flags;
-
-       /* additionally supported transmission standards */
-       struct saa7146_standard *stds;
-       int num_stds;
-       int (*std_callback)(struct saa7146_dev*, struct saa7146_standard *);
-
-       /* the extension can override this */
-       struct v4l2_ioctl_ops vid_ops;
-       struct v4l2_ioctl_ops vbi_ops;
-       /* pointer to the saa7146 core ops */
-       const struct v4l2_ioctl_ops *core_ops;
-
-       struct v4l2_file_operations vbi_fops;
-};
-
-struct saa7146_use_ops  {
-       void (*init)(struct saa7146_dev *, struct saa7146_vv *);
-       int(*open)(struct saa7146_dev *, struct file *);
-       void (*release)(struct saa7146_dev *, struct file *);
-       void (*irq_done)(struct saa7146_dev *, unsigned long status);
-       ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
-};
-
-/* from saa7146_fops.c */
-int saa7146_register_device(struct video_device *vid, struct saa7146_dev *dev, char *name, int type);
-int saa7146_unregister_device(struct video_device *vid, struct saa7146_dev *dev);
-void saa7146_buffer_finish(struct saa7146_dev *dev, struct saa7146_dmaqueue *q, int state);
-void saa7146_buffer_next(struct saa7146_dev *dev, struct saa7146_dmaqueue *q,int vbi);
-int saa7146_buffer_queue(struct saa7146_dev *dev, struct saa7146_dmaqueue *q, struct saa7146_buf *buf);
-void saa7146_buffer_timeout(unsigned long data);
-void saa7146_dma_free(struct saa7146_dev* dev,struct videobuf_queue *q,
-                                               struct saa7146_buf *buf);
-
-int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv);
-int saa7146_vv_release(struct saa7146_dev* dev);
-
-/* from saa7146_hlp.c */
-int saa7146_enable_overlay(struct saa7146_fh *fh);
-void saa7146_disable_overlay(struct saa7146_fh *fh);
-
-void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next);
-void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma) ;
-void saa7146_set_hps_source_and_sync(struct saa7146_dev *saa, int source, int sync);
-void saa7146_set_gpio(struct saa7146_dev *saa, u8 pin, u8 data);
-
-/* from saa7146_video.c */
-extern const struct v4l2_ioctl_ops saa7146_video_ioctl_ops;
-extern const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops;
-extern struct saa7146_use_ops saa7146_video_uops;
-int saa7146_start_preview(struct saa7146_fh *fh);
-int saa7146_stop_preview(struct saa7146_fh *fh);
-long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg);
-int saa7146_s_ctrl(struct v4l2_ctrl *ctrl);
-
-/* from saa7146_vbi.c */
-extern struct saa7146_use_ops saa7146_vbi_uops;
-
-/* resource management functions */
-int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit);
-void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits);
-
-#define RESOURCE_DMA1_HPS      0x1
-#define RESOURCE_DMA2_CLP      0x2
-#define RESOURCE_DMA3_BRS      0x4
-
-/* saa7146 source inputs */
-#define SAA7146_HPS_SOURCE_PORT_A      0x00
-#define SAA7146_HPS_SOURCE_PORT_B      0x01
-#define SAA7146_HPS_SOURCE_YPB_CPA     0x02
-#define SAA7146_HPS_SOURCE_YPA_CPB     0x03
-
-/* sync inputs */
-#define SAA7146_HPS_SYNC_PORT_A                0x00
-#define SAA7146_HPS_SYNC_PORT_B                0x01
-
-/* some memory sizes */
-/* max. 16 clipping rectangles */
-#define SAA7146_CLIPPING_MEM   (16 * 4 * sizeof(u32))
-
-/* some defines for the various clipping-modes */
-#define SAA7146_CLIPPING_RECT          0x4
-#define SAA7146_CLIPPING_RECT_INVERTED 0x5
-#define SAA7146_CLIPPING_MASK          0x6
-#define SAA7146_CLIPPING_MASK_INVERTED 0x7
-
-/* output formats: each entry holds four informations */
-#define RGB08_COMPOSED 0x0217 /* composed is used in the sense of "not-planar" */
-/* this means: planar?=0, yuv2rgb-conversation-mode=2, dither=yes(=1), format-mode = 7 */
-#define RGB15_COMPOSED 0x0213
-#define RGB16_COMPOSED 0x0210
-#define RGB24_COMPOSED 0x0201
-#define RGB32_COMPOSED 0x0202
-
-#define Y8                     0x0006
-#define YUV411_COMPOSED                0x0003
-#define YUV422_COMPOSED                0x0000
-/* this means: planar?=1, yuv2rgb-conversion-mode=0, dither=no(=0), format-mode = b */
-#define YUV411_DECOMPOSED      0x100b
-#define YUV422_DECOMPOSED      0x1009
-#define YUV420_DECOMPOSED      0x100a
-
-#define IS_PLANAR(x) (x & 0xf000)
-
-/* misc defines */
-#define SAA7146_NO_SWAP                (0x0)
-#define SAA7146_TWO_BYTE_SWAP  (0x1)
-#define SAA7146_FOUR_BYTE_SWAP (0x2)
-
-#endif
diff --git a/include/media/sh_mobile_ceu.h b/include/media/sh_mobile_ceu.h
deleted file mode 100644 (file)
index 7f57056..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef __ASM_SH_MOBILE_CEU_H__
-#define __ASM_SH_MOBILE_CEU_H__
-
-#define SH_CEU_FLAG_USE_8BIT_BUS       (1 << 0) /* use  8bit bus width */
-#define SH_CEU_FLAG_USE_16BIT_BUS      (1 << 1) /* use 16bit bus width */
-#define SH_CEU_FLAG_HSYNC_LOW          (1 << 2) /* default High if possible */
-#define SH_CEU_FLAG_VSYNC_LOW          (1 << 3) /* default High if possible */
-#define SH_CEU_FLAG_LOWER_8BIT         (1 << 4) /* default upper 8bit */
-
-struct device;
-struct resource;
-
-struct sh_mobile_ceu_companion {
-       u32             num_resources;
-       struct resource *resource;
-       int             id;
-       void            *platform_data;
-};
-
-struct sh_mobile_ceu_info {
-       unsigned long flags;
-       int max_width;
-       int max_height;
-       struct sh_mobile_ceu_companion *csi2;
-       struct v4l2_async_subdev **asd; /* Flat array, arranged in groups */
-       unsigned int *asd_sizes;        /* 0-terminated array pf asd group sizes */
-};
-
-#endif /* __ASM_SH_MOBILE_CEU_H__ */
diff --git a/include/media/sh_mobile_csi2.h b/include/media/sh_mobile_csi2.h
deleted file mode 100644 (file)
index 14030db..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Driver header for the SH-Mobile MIPI CSI-2 unit
- *
- * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.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.
- */
-
-#ifndef SH_MIPI_CSI
-#define SH_MIPI_CSI
-
-#include <linux/list.h>
-
-enum sh_csi2_phy {
-       SH_CSI2_PHY_MAIN,
-       SH_CSI2_PHY_SUB,
-};
-
-enum sh_csi2_type {
-       SH_CSI2C,
-       SH_CSI2I,
-};
-
-#define SH_CSI2_CRC    (1 << 0)
-#define SH_CSI2_ECC    (1 << 1)
-
-struct platform_device;
-
-struct sh_csi2_client_config {
-       enum sh_csi2_phy phy;
-       unsigned char lanes;            /* bitmask[3:0] */
-       unsigned char channel;          /* 0..3 */
-       struct platform_device *pdev;   /* client platform device */
-       const char *name;               /* async matching: client name */
-};
-
-struct v4l2_device;
-
-struct sh_csi2_pdata {
-       enum sh_csi2_type type;
-       unsigned int flags;
-       struct sh_csi2_client_config *clients;
-       int num_clients;
-};
-
-#endif
diff --git a/include/media/sh_vou.h b/include/media/sh_vou.h
deleted file mode 100644 (file)
index ec3ba9a..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SuperH Video Output Unit (VOU) driver header
- *
- * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.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.
- */
-#ifndef SH_VOU_H
-#define SH_VOU_H
-
-#include <linux/i2c.h>
-
-/* Bus flags */
-#define SH_VOU_PCLK_FALLING    (1 << 0)
-#define SH_VOU_HSYNC_LOW       (1 << 1)
-#define SH_VOU_VSYNC_LOW       (1 << 2)
-
-enum sh_vou_bus_fmt {
-       SH_VOU_BUS_8BIT,
-       SH_VOU_BUS_16BIT,
-       SH_VOU_BUS_BT656,
-};
-
-struct sh_vou_pdata {
-       enum sh_vou_bus_fmt bus_fmt;
-       int i2c_adap;
-       struct i2c_board_info *board_info;
-       unsigned long flags;
-};
-
-#endif
diff --git a/include/media/si4713.h b/include/media/si4713.h
deleted file mode 100644 (file)
index be4f58e..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * include/media/si4713.h
- *
- * Board related data definitions for Si4713 i2c device driver.
- *
- * Copyright (c) 2009 Nokia Corporation
- * Contact: Eduardo Valentin <eduardo.valentin@nokia.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.
- *
- */
-
-#ifndef SI4713_H
-#define SI4713_H
-
-/* The SI4713 I2C sensor chip has a fixed slave address of 0xc6 or 0x22. */
-#define SI4713_I2C_ADDR_BUSEN_HIGH     0x63
-#define SI4713_I2C_ADDR_BUSEN_LOW      0x11
-
-/*
- * Platform dependent definition
- */
-struct si4713_platform_data {
-       bool is_platform_device;
-};
-
-/*
- * Structure to query for Received Noise Level (RNL).
- */
-struct si4713_rnl {
-       __u32 index;            /* modulator index */
-       __u32 frequency;        /* frequency to peform rnl measurement */
-       __s32 rnl;              /* result of measurement in dBuV */
-       __u32 reserved[4];      /* drivers and apps must init this to 0 */
-};
-
-/*
- * This is the ioctl number to query for rnl. Users must pass a
- * struct si4713_rnl pointer specifying desired frequency in 'frequency' field
- * following driver capabilities (i.e V4L2_TUNER_CAP_LOW).
- * Driver must return measured value in the same struture, filling 'rnl' field.
- */
-#define SI4713_IOC_MEASURE_RNL _IOWR('V', BASE_VIDIOC_PRIVATE + 0, \
-                                               struct si4713_rnl)
-
-#endif /* ifndef SI4713_H*/
diff --git a/include/media/si476x.h b/include/media/si476x.h
deleted file mode 100644 (file)
index e02e241..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * include/media/si476x.h -- Common definitions for si476x driver
- *
- * Copyright (C) 2012 Innovative Converged Devices(ICD)
- * Copyright (C) 2013 Andrey Smirnov
- *
- * Author: Andrey Smirnov <andrew.smirnov@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; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- */
-
-#ifndef SI476X_H
-#define SI476X_H
-
-#include <linux/types.h>
-#include <linux/videodev2.h>
-
-#include <linux/mfd/si476x-reports.h>
-
-enum si476x_ctrl_id {
-       V4L2_CID_SI476X_RSSI_THRESHOLD  = (V4L2_CID_USER_SI476X_BASE + 1),
-       V4L2_CID_SI476X_SNR_THRESHOLD   = (V4L2_CID_USER_SI476X_BASE + 2),
-       V4L2_CID_SI476X_MAX_TUNE_ERROR  = (V4L2_CID_USER_SI476X_BASE + 3),
-       V4L2_CID_SI476X_HARMONICS_COUNT = (V4L2_CID_USER_SI476X_BASE + 4),
-       V4L2_CID_SI476X_DIVERSITY_MODE  = (V4L2_CID_USER_SI476X_BASE + 5),
-       V4L2_CID_SI476X_INTERCHIP_LINK  = (V4L2_CID_USER_SI476X_BASE + 6),
-};
-
-#endif /* SI476X_H*/
diff --git a/include/media/sii9234.h b/include/media/sii9234.h
deleted file mode 100644 (file)
index 6a4a809..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Driver header for SII9234 MHL converter chip.
- *
- * Copyright (c) 2011 Samsung Electronics, Co. Ltd
- * Contact: Tomasz Stanislawski <t.stanislaws@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef SII9234_H
-#define SII9234_H
-
-/**
- * @gpio_n_reset: GPIO driving nRESET pin
- */
-
-struct sii9234_platform_data {
-       int gpio_n_reset;
-};
-
-#endif /* SII9234_H */
diff --git a/include/media/smiapp.h b/include/media/smiapp.h
deleted file mode 100644 (file)
index 268a3cd..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * include/media/smiapp.h
- *
- * Generic driver for SMIA/SMIA++ compliant camera modules
- *
- * Copyright (C) 2011--2012 Nokia Corporation
- * Contact: Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __SMIAPP_H_
-#define __SMIAPP_H_
-
-#include <media/v4l2-subdev.h>
-
-#define SMIAPP_NAME            "smiapp"
-
-#define SMIAPP_DFL_I2C_ADDR    (0x20 >> 1) /* Default I2C Address */
-#define SMIAPP_ALT_I2C_ADDR    (0x6e >> 1) /* Alternate I2C Address */
-
-#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK     0
-#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE    1
-#define SMIAPP_CSI_SIGNALLING_MODE_CSI2                        2
-
-#define SMIAPP_NO_XSHUTDOWN    -1
-
-/*
- * Sometimes due to board layout considerations the camera module can be
- * mounted rotated. The typical rotation used is 180 degrees which can be
- * corrected by giving a default H-FLIP and V-FLIP in the sensor readout.
- * FIXME: rotation also changes the bayer pattern.
- */
-enum smiapp_module_board_orient {
-       SMIAPP_MODULE_BOARD_ORIENT_0 = 0,
-       SMIAPP_MODULE_BOARD_ORIENT_180,
-};
-
-struct smiapp_flash_strobe_parms {
-       u8 mode;
-       u32 strobe_width_high_us;
-       u16 strobe_delay;
-       u16 stobe_start_point;
-       u8 trigger;
-};
-
-struct smiapp_platform_data {
-       /*
-        * Change the cci address if i2c_addr_alt is set.
-        * Both default and alternate cci addr need to be present
-        */
-       unsigned short i2c_addr_dfl;    /* Default i2c addr */
-       unsigned short i2c_addr_alt;    /* Alternate i2c addr */
-
-       uint32_t nvm_size;              /* bytes */
-       uint32_t ext_clk;               /* sensor external clk */
-
-       unsigned int lanes;             /* Number of CSI-2 lanes */
-       uint32_t csi_signalling_mode;   /* SMIAPP_CSI_SIGNALLING_MODE_* */
-       uint64_t *op_sys_clock;
-
-       enum smiapp_module_board_orient module_board_orient;
-
-       struct smiapp_flash_strobe_parms *strobe_setup;
-
-       int (*set_xclk)(struct v4l2_subdev *sd, int hz);
-       int32_t xshutdown;              /* gpio or SMIAPP_NO_XSHUTDOWN */
-};
-
-#endif /* __SMIAPP_H_  */
diff --git a/include/media/soc_camera_platform.h b/include/media/soc_camera_platform.h
deleted file mode 100644 (file)
index 1e5065d..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Generic Platform Camera Driver Header
- *
- * Copyright (C) 2008 Magnus Damm
- *
- * 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 __SOC_CAMERA_H__
-#define __SOC_CAMERA_H__
-
-#include <linux/videodev2.h>
-#include <media/soc_camera.h>
-#include <media/v4l2-mediabus.h>
-
-struct device;
-
-struct soc_camera_platform_info {
-       const char *format_name;
-       unsigned long format_depth;
-       struct v4l2_mbus_framefmt format;
-       unsigned long mbus_param;
-       enum v4l2_mbus_type mbus_type;
-       struct soc_camera_device *icd;
-       int (*set_capture)(struct soc_camera_platform_info *info, int enable);
-};
-
-static inline void soc_camera_platform_release(struct platform_device **pdev)
-{
-       *pdev = NULL;
-}
-
-static inline int soc_camera_platform_add(struct soc_camera_device *icd,
-                                         struct platform_device **pdev,
-                                         struct soc_camera_link *plink,
-                                         void (*release)(struct device *dev),
-                                         int id)
-{
-       struct soc_camera_subdev_desc *ssdd =
-               (struct soc_camera_subdev_desc *)plink;
-       struct soc_camera_platform_info *info = ssdd->drv_priv;
-       int ret;
-
-       if (&icd->sdesc->subdev_desc != ssdd)
-               return -ENODEV;
-
-       if (*pdev)
-               return -EBUSY;
-
-       *pdev = platform_device_alloc("soc_camera_platform", id);
-       if (!*pdev)
-               return -ENOMEM;
-
-       info->icd = icd;
-
-       (*pdev)->dev.platform_data = info;
-       (*pdev)->dev.release = release;
-
-       ret = platform_device_add(*pdev);
-       if (ret < 0) {
-               platform_device_put(*pdev);
-               *pdev = NULL;
-               info->icd = NULL;
-       }
-
-       return ret;
-}
-
-static inline void soc_camera_platform_del(const struct soc_camera_device *icd,
-                                          struct platform_device *pdev,
-                                          const struct soc_camera_link *plink)
-{
-       const struct soc_camera_subdev_desc *ssdd =
-               (const struct soc_camera_subdev_desc *)plink;
-       if (&icd->sdesc->subdev_desc != ssdd || !pdev)
-               return;
-
-       platform_device_unregister(pdev);
-}
-
-#endif /* __SOC_CAMERA_H__ */
diff --git a/include/media/soc_mediabus.h b/include/media/soc_mediabus.h
deleted file mode 100644 (file)
index 2ff7737..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * SoC-camera Media Bus API extensions
- *
- * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.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.
- */
-
-#ifndef SOC_MEDIABUS_H
-#define SOC_MEDIABUS_H
-
-#include <linux/videodev2.h>
-#include <linux/v4l2-mediabus.h>
-
-/**
- * enum soc_mbus_packing - data packing types on the media-bus
- * @SOC_MBUS_PACKING_NONE:     no packing, bit-for-bit transfer to RAM, one
- *                             sample represents one pixel
- * @SOC_MBUS_PACKING_2X8_PADHI:        16 bits transferred in 2 8-bit samples, in the
- *                             possibly incomplete byte high bits are padding
- * @SOC_MBUS_PACKING_2X8_PADLO:        as above, but low bits are padding
- * @SOC_MBUS_PACKING_EXTEND16: sample width (e.g., 10 bits) has to be extended
- *                             to 16 bits
- * @SOC_MBUS_PACKING_VARIABLE: compressed formats with variable packing
- * @SOC_MBUS_PACKING_1_5X8:    used for packed YUV 4:2:0 formats, where 4
- *                             pixels occupy 6 bytes in RAM
- * @SOC_MBUS_PACKING_EXTEND32: sample width (e.g., 24 bits) has to be extended
- *                             to 32 bits
- */
-enum soc_mbus_packing {
-       SOC_MBUS_PACKING_NONE,
-       SOC_MBUS_PACKING_2X8_PADHI,
-       SOC_MBUS_PACKING_2X8_PADLO,
-       SOC_MBUS_PACKING_EXTEND16,
-       SOC_MBUS_PACKING_VARIABLE,
-       SOC_MBUS_PACKING_1_5X8,
-       SOC_MBUS_PACKING_EXTEND32,
-};
-
-/**
- * enum soc_mbus_order - sample order on the media bus
- * @SOC_MBUS_ORDER_LE:         least significant sample first
- * @SOC_MBUS_ORDER_BE:         most significant sample first
- */
-enum soc_mbus_order {
-       SOC_MBUS_ORDER_LE,
-       SOC_MBUS_ORDER_BE,
-};
-
-/**
- * enum soc_mbus_layout - planes layout in memory
- * @SOC_MBUS_LAYOUT_PACKED:            color components packed
- * @SOC_MBUS_LAYOUT_PLANAR_2Y_U_V:     YUV components stored in 3 planes (4:2:2)
- * @SOC_MBUS_LAYOUT_PLANAR_2Y_C:       YUV components stored in a luma and a
- *                                     chroma plane (C plane is half the size
- *                                     of Y plane)
- * @SOC_MBUS_LAYOUT_PLANAR_Y_C:                YUV components stored in a luma and a
- *                                     chroma plane (C plane is the same size
- *                                     as Y plane)
- */
-enum soc_mbus_layout {
-       SOC_MBUS_LAYOUT_PACKED = 0,
-       SOC_MBUS_LAYOUT_PLANAR_2Y_U_V,
-       SOC_MBUS_LAYOUT_PLANAR_2Y_C,
-       SOC_MBUS_LAYOUT_PLANAR_Y_C,
-};
-
-/**
- * struct soc_mbus_pixelfmt - Data format on the media bus
- * @name:              Name of the format
- * @fourcc:            Fourcc code, that will be obtained if the data is
- *                     stored in memory in the following way:
- * @packing:           Type of sample-packing, that has to be used
- * @order:             Sample order when storing in memory
- * @bits_per_sample:   How many bits the bridge has to sample
- */
-struct soc_mbus_pixelfmt {
-       const char              *name;
-       u32                     fourcc;
-       enum soc_mbus_packing   packing;
-       enum soc_mbus_order     order;
-       enum soc_mbus_layout    layout;
-       u8                      bits_per_sample;
-};
-
-/**
- * struct soc_mbus_lookup - Lookup FOURCC IDs by mediabus codes for pass-through
- * @code:      mediabus pixel-code
- * @fmt:       pixel format description
- */
-struct soc_mbus_lookup {
-       u32     code;
-       struct soc_mbus_pixelfmt        fmt;
-};
-
-const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc(
-       u32 code,
-       const struct soc_mbus_lookup *lookup,
-       int n);
-const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc(
-       u32 code);
-s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf);
-s32 soc_mbus_image_size(const struct soc_mbus_pixelfmt *mf,
-                       u32 bytes_per_line, u32 height);
-int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf,
-                       unsigned int *numerator, unsigned int *denominator);
-unsigned int soc_mbus_config_compatible(const struct v4l2_mbus_config *cfg,
-                                       unsigned int flags);
-
-#endif
diff --git a/include/media/sr030pc30.h b/include/media/sr030pc30.h
deleted file mode 100644 (file)
index 6f901a6..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Driver header for SR030PC30 camera sensor
- *
- * Copyright (c) 2010 Samsung Electronics, Co. Ltd
- * Contact: Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef SR030PC30_H
-#define SR030PC30_H
-
-struct sr030pc30_platform_data {
-       unsigned long clk_rate; /* master clock frequency in Hz */
-       int (*set_power)(struct device *dev, int on);
-};
-
-#endif /* SR030PC30_H */
diff --git a/include/media/tc358743.h b/include/media/tc358743.h
deleted file mode 100644 (file)
index 4513f2f..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * tc358743 - Toshiba HDMI to CSI-2 bridge
- *
- * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights
- * reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-/*
- * References (c = chapter, p = page):
- * REF_01 - Toshiba, TC358743XBG (H2C), Functional Specification, Rev 0.60
- * REF_02 - Toshiba, TC358743XBG_HDMI-CSI_Tv11p_nm.xls
- */
-
-#ifndef _TC358743_
-#define _TC358743_
-
-enum tc358743_ddc5v_delays {
-       DDC5V_DELAY_0_MS,
-       DDC5V_DELAY_50_MS,
-       DDC5V_DELAY_100_MS,
-       DDC5V_DELAY_200_MS,
-};
-
-enum tc358743_hdmi_detection_delay {
-       HDMI_MODE_DELAY_0_MS,
-       HDMI_MODE_DELAY_25_MS,
-       HDMI_MODE_DELAY_50_MS,
-       HDMI_MODE_DELAY_100_MS,
-};
-
-struct tc358743_platform_data {
-       /* System clock connected to REFCLK (pin H5) */
-       u32 refclk_hz; /* 26 MHz, 27 MHz or 42 MHz */
-
-       /* DDC +5V debounce delay to avoid spurious interrupts when the cable
-        * is connected.
-        * Sets DDC5V_MODE in register DDC_CTL.
-        * Default: DDC5V_DELAY_0_MS
-        */
-       enum tc358743_ddc5v_delays ddc5v_delay;
-
-       bool enable_hdcp;
-
-       /*
-        * The FIFO size is 512x32, so Toshiba recommend to set the default FIFO
-        * level to somewhere in the middle (e.g. 300), so it can cover speed
-        * mismatches in input and output ports.
-        */
-       u16 fifo_level;
-
-       /* Bps pr lane is (refclk_hz / pll_prd) * pll_fbd */
-       u16 pll_prd;
-       u16 pll_fbd;
-
-       /* CSI
-        * Calculate CSI parameters with REF_02 for the highest resolution your
-        * CSI interface can handle. The driver will adjust the number of CSI
-        * lanes in use according to the pixel clock.
-        *
-        * The values in brackets are calculated with REF_02 when the number of
-        * bps pr lane is 823.5 MHz, and can serve as a starting point.
-        */
-       u32 lineinitcnt;        /* (0x00001770) */
-       u32 lptxtimecnt;        /* (0x00000005) */
-       u32 tclk_headercnt;     /* (0x00001d04) */
-       u32 tclk_trailcnt;      /* (0x00000000) */
-       u32 ths_headercnt;      /* (0x00000505) */
-       u32 twakeup;            /* (0x00004650) */
-       u32 tclk_postcnt;       /* (0x00000000) */
-       u32 ths_trailcnt;       /* (0x00000004) */
-       u32 hstxvregcnt;        /* (0x00000005) */
-
-       /* DVI->HDMI detection delay to avoid unnecessary switching between DVI
-        * and HDMI mode.
-        * Sets HDMI_DET_V in register HDMI_DET.
-        * Default: HDMI_MODE_DELAY_0_MS
-        */
-       enum tc358743_hdmi_detection_delay hdmi_detection_delay;
-
-       /* Reset PHY automatically when TMDS clock goes from DC to AC.
-        * Sets PHY_AUTO_RST2 in register PHY_CTL2.
-        * Default: false
-        */
-       bool hdmi_phy_auto_reset_tmds_detected;
-
-       /* Reset PHY automatically when TMDS clock passes 21 MHz.
-        * Sets PHY_AUTO_RST3 in register PHY_CTL2.
-        * Default: false
-        */
-       bool hdmi_phy_auto_reset_tmds_in_range;
-
-       /* Reset PHY automatically when TMDS clock is detected.
-        * Sets PHY_AUTO_RST4 in register PHY_CTL2.
-        * Default: false
-        */
-       bool hdmi_phy_auto_reset_tmds_valid;
-
-       /* Reset HDMI PHY automatically when hsync period is out of range.
-        * Sets H_PI_RST in register HV_RST.
-        * Default: false
-        */
-       bool hdmi_phy_auto_reset_hsync_out_of_range;
-
-       /* Reset HDMI PHY automatically when vsync period is out of range.
-        * Sets V_PI_RST in register HV_RST.
-        * Default: false
-        */
-       bool hdmi_phy_auto_reset_vsync_out_of_range;
-};
-
-/* custom controls */
-/* Audio sample rate in Hz */
-#define TC358743_CID_AUDIO_SAMPLING_RATE (V4L2_CID_USER_TC358743_BASE + 0)
-/* Audio present status */
-#define TC358743_CID_AUDIO_PRESENT       (V4L2_CID_USER_TC358743_BASE + 1)
-
-#endif
diff --git a/include/media/tea575x.h b/include/media/tea575x.h
deleted file mode 100644 (file)
index 5d09657..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-#ifndef __SOUND_TEA575X_TUNER_H
-#define __SOUND_TEA575X_TUNER_H
-
-/*
- *   ALSA driver for TEA5757/5759 Philips AM/FM tuner chips
- *
- *     Copyright (c) 2004 Jaroslav Kysela <perex@perex.cz>
- *
- *   This program is 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
- *
- */
-
-#include <linux/videodev2.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-dev.h>
-#include <media/v4l2-device.h>
-
-#define TEA575X_FMIF   10700
-#define TEA575X_AMIF     450
-
-#define TEA575X_DATA   (1 << 0)
-#define TEA575X_CLK    (1 << 1)
-#define TEA575X_WREN   (1 << 2)
-#define TEA575X_MOST   (1 << 3)
-
-struct snd_tea575x;
-
-struct snd_tea575x_ops {
-       /* Drivers using snd_tea575x must either define read_ and write_val */
-       void (*write_val)(struct snd_tea575x *tea, u32 val);
-       u32 (*read_val)(struct snd_tea575x *tea);
-       /* Or define the 3 pin functions */
-       void (*set_pins)(struct snd_tea575x *tea, u8 pins);
-       u8 (*get_pins)(struct snd_tea575x *tea);
-       void (*set_direction)(struct snd_tea575x *tea, bool output);
-};
-
-struct snd_tea575x {
-       struct v4l2_device *v4l2_dev;
-       struct v4l2_file_operations fops;
-       struct video_device vd;         /* video device */
-       int radio_nr;                   /* radio_nr */
-       bool tea5759;                   /* 5759 chip is present */
-       bool has_am;                    /* Device can tune to AM freqs */
-       bool cannot_read_data;          /* Device cannot read the data pin */
-       bool cannot_mute;               /* Device cannot mute */
-       bool mute;                      /* Device is muted? */
-       bool stereo;                    /* receiving stereo */
-       bool tuned;                     /* tuned to a station */
-       unsigned int val;               /* hw value */
-       u32 band;                       /* 0: FM, 1: FM-Japan, 2: AM */
-       u32 freq;                       /* frequency */
-       struct mutex mutex;
-       struct snd_tea575x_ops *ops;
-       void *private_data;
-       u8 card[32];
-       u8 bus_info[32];
-       struct v4l2_ctrl_handler ctrl_handler;
-       int (*ext_init)(struct snd_tea575x *tea);
-};
-
-int snd_tea575x_enum_freq_bands(struct snd_tea575x *tea,
-                                       struct v4l2_frequency_band *band);
-int snd_tea575x_g_tuner(struct snd_tea575x *tea, struct v4l2_tuner *v);
-int snd_tea575x_s_hw_freq_seek(struct file *file, struct snd_tea575x *tea,
-                               const struct v4l2_hw_freq_seek *a);
-int snd_tea575x_hw_init(struct snd_tea575x *tea);
-int snd_tea575x_init(struct snd_tea575x *tea, struct module *owner);
-void snd_tea575x_exit(struct snd_tea575x *tea);
-void snd_tea575x_set_freq(struct snd_tea575x *tea);
-
-#endif /* __SOUND_TEA575X_TUNER_H */
diff --git a/include/media/ths7303.h b/include/media/ths7303.h
deleted file mode 100644 (file)
index a7b4929..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2013 Texas Instruments Inc
- *
- * Copyright 2013 Cisco Systems, Inc. and/or its affiliates.
- *
- * Contributors:
- *     Hans Verkuil <hans.verkuil@cisco.com>
- *     Lad, Prabhakar <prabhakar.lad@ti.com>
- *     Martin Bugge <marbugge@cisco.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public 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
-#define THS7353_H
-
-/**
- * struct ths7303_platform_data - Platform dependent data
- * @ch_1: Bias value for channel one.
- * @ch_2: Bias value for channel two.
- * @ch_3: Bias value for channel three.
- */
-struct ths7303_platform_data {
-       u8 ch_1;
-       u8 ch_2;
-       u8 ch_3;
-};
-
-#endif
diff --git a/include/media/timb_radio.h b/include/media/timb_radio.h
deleted file mode 100644 (file)
index a40a6a3..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * timb_radio.h Platform struct for the Timberdale radio driver
- * Copyright (c) 2009 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the 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 _TIMB_RADIO_
-#define _TIMB_RADIO_ 1
-
-#include <linux/i2c.h>
-
-struct timb_radio_platform_data {
-       int i2c_adapter; /* I2C adapter where the tuner and dsp are attached */
-       struct i2c_board_info *tuner;
-       struct i2c_board_info *dsp;
-};
-
-#endif
diff --git a/include/media/timb_video.h b/include/media/timb_video.h
deleted file mode 100644 (file)
index 70ae439..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * timb_video.h Platform struct for the Timberdale video driver
- * Copyright (c) 2009-2010 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the 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 _TIMB_VIDEO_
-#define _TIMB_VIDEO_ 1
-
-#include <linux/i2c.h>
-
-struct timb_video_platform_data {
-       int dma_channel;
-       int i2c_adapter; /* The I2C adapter where the encoder is attached */
-       struct {
-               const char *module_name;
-               struct i2c_board_info *info;
-       } encoder;
-};
-
-#endif
diff --git a/include/media/tvaudio.h b/include/media/tvaudio.h
deleted file mode 100644 (file)
index 1ac8184..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-    tvaudio.h - definition for tvaudio inputs
-
-    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
-
-    This program is 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 _TVAUDIO_H
-#define _TVAUDIO_H
-
-#include <media/i2c-addr.h>
-
-/* The tvaudio module accepts the following inputs: */
-#define TVAUDIO_INPUT_TUNER  0
-#define TVAUDIO_INPUT_RADIO  1
-#define TVAUDIO_INPUT_EXTERN 2
-#define TVAUDIO_INPUT_INTERN 3
-
-static inline const unsigned short *tvaudio_addrs(void)
-{
-       static const unsigned short addrs[] = {
-               I2C_ADDR_TDA8425   >> 1,
-               I2C_ADDR_TEA6300   >> 1,
-               I2C_ADDR_TEA6420   >> 1,
-               I2C_ADDR_TDA9840   >> 1,
-               I2C_ADDR_TDA985x_L >> 1,
-               I2C_ADDR_TDA985x_H >> 1,
-               I2C_ADDR_TDA9874   >> 1,
-               I2C_ADDR_PIC16C54  >> 1,
-               I2C_CLIENT_END
-       };
-
-       return addrs;
-}
-
-#endif
diff --git a/include/media/tvp514x.h b/include/media/tvp514x.h
deleted file mode 100644 (file)
index 86ed7e8..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * drivers/media/video/tvp514x.h
- *
- * Copyright (C) 2008 Texas Instruments Inc
- * Author: Vaibhav Hiremath <hvaibhav@ti.com>
- *
- * Contributors:
- *     Sivaraj R <sivaraj@ti.com>
- *     Brijesh R Jadav <brijesh.j@ti.com>
- *     Hardik Shah <hardik.shah@ti.com>
- *     Manjunath Hadli <mrh@ti.com>
- *     Karicheri Muralidharan <m-karicheri2@ti.com>
- *
- * This package 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, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef _TVP514X_H
-#define _TVP514X_H
-
-/*
- * Other macros
- */
-#define TVP514X_MODULE_NAME            "tvp514x"
-
-#define TVP514X_XCLK_BT656             (27000000)
-
-/* Number of pixels and number of lines per frame for different standards */
-#define NTSC_NUM_ACTIVE_PIXELS         (720)
-#define NTSC_NUM_ACTIVE_LINES          (480)
-#define PAL_NUM_ACTIVE_PIXELS          (720)
-#define PAL_NUM_ACTIVE_LINES           (576)
-
-/**
- * enum tvp514x_input - enum for different decoder input pin
- *             configuration.
- */
-enum tvp514x_input {
-       /*
-        * CVBS input selection
-        */
-       INPUT_CVBS_VI1A = 0x0,
-       INPUT_CVBS_VI1B,
-       INPUT_CVBS_VI1C,
-       INPUT_CVBS_VI2A = 0x04,
-       INPUT_CVBS_VI2B,
-       INPUT_CVBS_VI2C,
-       INPUT_CVBS_VI3A = 0x08,
-       INPUT_CVBS_VI3B,
-       INPUT_CVBS_VI3C,
-       INPUT_CVBS_VI4A = 0x0C,
-       /*
-        * S-Video input selection
-        */
-       INPUT_SVIDEO_VI2A_VI1A = 0x44,
-       INPUT_SVIDEO_VI2B_VI1B,
-       INPUT_SVIDEO_VI2C_VI1C,
-       INPUT_SVIDEO_VI2A_VI3A = 0x54,
-       INPUT_SVIDEO_VI2B_VI3B,
-       INPUT_SVIDEO_VI2C_VI3C,
-       INPUT_SVIDEO_VI4A_VI1A = 0x4C,
-       INPUT_SVIDEO_VI4A_VI1B,
-       INPUT_SVIDEO_VI4A_VI1C,
-       INPUT_SVIDEO_VI4A_VI3A = 0x5C,
-       INPUT_SVIDEO_VI4A_VI3B,
-       INPUT_SVIDEO_VI4A_VI3C,
-
-       /* Need to add entries for
-        * RGB, YPbPr and SCART.
-        */
-       INPUT_INVALID
-};
-
-/**
- * enum tvp514x_output - enum for output format
- *                     supported.
- *
- */
-enum tvp514x_output {
-       OUTPUT_10BIT_422_EMBEDDED_SYNC = 0,
-       OUTPUT_20BIT_422_SEPERATE_SYNC,
-       OUTPUT_10BIT_422_SEPERATE_SYNC = 3,
-       OUTPUT_INVALID
-};
-
-/**
- * struct tvp514x_platform_data - Platform data values and access functions.
- * @clk_polarity: Clock polarity of the current interface.
- * @hs_polarity: HSYNC Polarity configuration for current interface.
- * @vs_polarity: VSYNC Polarity configuration for current interface.
- */
-struct tvp514x_platform_data {
-       /* Interface control params */
-       bool clk_polarity;
-       bool hs_polarity;
-       bool vs_polarity;
-};
-
-
-#endif                         /* ifndef _TVP514X_H */
diff --git a/include/media/tvp5150.h b/include/media/tvp5150.h
deleted file mode 100644 (file)
index 72bd2a2..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-    tvp5150.h - definition for tvp5150 inputs
-
-    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
-
-    This program is 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 _TVP5150_H_
-#define _TVP5150_H_
-
-/* TVP5150 HW inputs */
-#define TVP5150_COMPOSITE0 0
-#define TVP5150_COMPOSITE1 1
-#define TVP5150_SVIDEO     2
-
-/* TVP5150 HW outputs */
-#define TVP5150_NORMAL       0
-#define TVP5150_BLACK_SCREEN 1
-
-#endif
-
diff --git a/include/media/tvp7002.h b/include/media/tvp7002.h
deleted file mode 100644 (file)
index fadb6af..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Texas Instruments Triple 8-/10-BIT 165-/110-MSPS Video and Graphics
- * Digitizer with Horizontal PLL registers
- *
- * Copyright (C) 2009 Texas Instruments Inc
- * Author: Santiago Nunez-Corrales <santiago.nunez@ridgerun.com>
- *
- * This code is partially based upon the TVP5150 driver
- * written by Mauro Carvalho Chehab (mchehab@infradead.org),
- * the TVP514x driver written by Vaibhav Hiremath <hvaibhav@ti.com>
- * and the TVP7002 driver in the TI LSP 2.10.00.14
- *
- * This program is 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 _TVP7002_H_
-#define _TVP7002_H_
-
-#define TVP7002_MODULE_NAME "tvp7002"
-
-/**
- * struct tvp7002_config - Platform dependent data
- *@clk_polarity: Clock polarity
- *             0 - Data clocked out on rising edge of DATACLK signal
- *             1 - Data clocked out on falling edge of DATACLK signal
- *@hs_polarity:  HSYNC polarity
- *             0 - Active low HSYNC output, 1 - Active high HSYNC output
- *@vs_polarity: VSYNC Polarity
- *             0 - Active low VSYNC output, 1 - Active high VSYNC output
- *@fid_polarity: Active-high Field ID polarity.
- *             0 - The field ID output is set to logic 1 for an odd field
- *                 (field 1) and set to logic 0 for an even field (field 0).
- *             1 - Operation with polarity inverted.
- *@sog_polarity: Active high Sync on Green output polarity.
- *             0 - Normal operation, 1 - Operation with polarity inverted
- */
-struct tvp7002_config {
-       bool clk_polarity;
-       bool hs_polarity;
-       bool vs_polarity;
-       bool fid_polarity;
-       bool sog_polarity;
-};
-#endif
diff --git a/include/media/tw9910.h b/include/media/tw9910.h
deleted file mode 100644 (file)
index 90bcf1f..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * tw9910 Driver header
- *
- * Copyright (C) 2008 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on ov772x.h
- *
- * Copyright (C) Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __TW9910_H__
-#define __TW9910_H__
-
-#include <media/soc_camera.h>
-
-enum tw9910_mpout_pin {
-       TW9910_MPO_VLOSS,
-       TW9910_MPO_HLOCK,
-       TW9910_MPO_SLOCK,
-       TW9910_MPO_VLOCK,
-       TW9910_MPO_MONO,
-       TW9910_MPO_DET50,
-       TW9910_MPO_FIELD,
-       TW9910_MPO_RTCO,
-};
-
-struct tw9910_video_info {
-       unsigned long           buswidth;
-       enum tw9910_mpout_pin   mpout;
-};
-
-
-#endif /* __TW9910_H__ */
diff --git a/include/media/uda1342.h b/include/media/uda1342.h
deleted file mode 100644 (file)
index cd15640..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * uda1342.h - definition for uda1342 inputs
- *
- * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#ifndef _UDA1342_H_
-#define _UDA1342_H_
-
-/* The UDA1342 has 2 inputs */
-
-#define UDA1342_IN1 1
-#define UDA1342_IN2 2
-
-#endif
diff --git a/include/media/upd64031a.h b/include/media/upd64031a.h
deleted file mode 100644 (file)
index 3ad6a32..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * upd64031a - NEC Electronics Ghost Reduction input defines
- *
- * 2006 by Hans Verkuil (hverkuil@xs4all.nl)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#ifndef _UPD64031A_H_
-#define _UPD64031A_H_
-
-/* Ghost reduction modes */
-#define UPD64031A_GR_ON        0
-#define UPD64031A_GR_OFF       1
-#define UPD64031A_GR_THROUGH   3
-
-/* Direct 3D/YCS Connection */
-#define UPD64031A_3DYCS_DISABLE   (0 << 2)
-#define UPD64031A_3DYCS_COMPOSITE (2 << 2)
-#define UPD64031A_3DYCS_SVIDEO    (3 << 2)
-
-/* Composite sync digital separation circuit */
-#define UPD64031A_COMPOSITE_EXTERNAL (1 << 4)
-
-/* Vertical sync digital separation circuit */
-#define UPD64031A_VERTICAL_EXTERNAL (1 << 5)
-
-#endif
diff --git a/include/media/upd64083.h b/include/media/upd64083.h
deleted file mode 100644 (file)
index 59b6f32..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * upd6408x - NEC Electronics 3-Dimensional Y/C separation input defines
- *
- * 2006 by Hans Verkuil (hverkuil@xs4all.nl)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#ifndef _UPD64083_H_
-#define _UPD64083_H_
-
-/* There are two bits of information that the driver needs in order
-   to select the correct routing: the operating mode and the selection
-   of the Y input (external or internal).
-
-   The first two operating modes expect a composite signal on the Y input,
-   the second two operating modes use both the Y and C inputs.
-
-   Normally YCS_MODE is used for tuner and composite inputs, and the
-   YCNR mode is used for S-Video inputs.
-
-   The external Y-ADC is selected when the composite input comes from a
-   upd64031a ghost reduction device. If this device is not present, or
-   the input is a S-Video signal, then the internal Y-ADC input should
-   be used. */
-
-/* Operating modes: */
-
-/* YCS mode: Y/C separation (burst locked clocking) */
-#define UPD64083_YCS_MODE      0
-/* YCS+ mode: 2D Y/C separation and YCNR (burst locked clocking) */
-#define UPD64083_YCS_PLUS_MODE 1
-
-/* Note: the following two modes cannot be used in combination with the
-   external Y-ADC. */
-/* MNNR mode: frame comb type YNR+C delay (line locked clocking) */
-#define UPD64083_MNNR_MODE     2
-/* YCNR mode: frame recursive YCNR (burst locked clocking) */
-#define UPD64083_YCNR_MODE     3
-
-/* Select external Y-ADC: this should be set if this device is used in
-   combination with the upd64031a ghost reduction device.
-   Otherwise leave at 0 (use internal Y-ADC). */
-#define UPD64083_EXT_Y_ADC     (1 << 2)
-
-#endif
index 3ef6e3d5ed6c6f6eb90fa177f6eccc20ee7a9c83..2b94662d005c4991094096751a635220bdbb15f4 100644 (file)
@@ -65,7 +65,12 @@ static inline struct v4l2_clk *v4l2_clk_register_fixed(const char *dev_id,
        return __v4l2_clk_register_fixed(dev_id, rate, THIS_MODULE);
 }
 
+#define V4L2_CLK_NAME_SIZE 64
+
 #define v4l2_clk_name_i2c(name, size, adap, client) snprintf(name, size, \
                          "%d-%04x", adap, client)
 
+#define v4l2_clk_name_of(name, size, of_full_name) snprintf(name, size, \
+                         "of-%s", of_full_name)
+
 #endif
index a209526b6014b11fe15fae9b39565e34996980fb..1113c8874c26be127eb51dfccd43642ceac8c4e4 100644 (file)
@@ -107,12 +107,14 @@ bool v4l2_find_dv_timings_cap(struct v4l2_dv_timings *t,
  * @standard:    the timings according to the standard.
  * @pclock_delta: maximum delta in Hz between standard->pixelclock and
  *             the measured timings.
+ * @match_reduced_fps: if true, then fail if V4L2_DV_FL_REDUCED_FPS does not
+ * match.
  *
  * Returns true if the two timings match, returns false otherwise.
  */
 bool v4l2_match_dv_timings(const struct v4l2_dv_timings *measured,
                           const struct v4l2_dv_timings *standard,
-                          unsigned pclock_delta);
+                          unsigned pclock_delta, bool match_reduced_fps);
 
 /**
  * v4l2_print_dv_timings() - log the contents of a dv_timings struct
@@ -183,4 +185,25 @@ bool v4l2_detect_gtf(unsigned frame_height, unsigned hfreq, unsigned vsync,
  */
 struct v4l2_fract v4l2_calc_aspect_ratio(u8 hor_landscape, u8 vert_portrait);
 
+/*
+ * reduce_fps - check if conditions for reduced fps are true.
+ * bt - v4l2 timing structure
+ * For different timings reduced fps is allowed if following conditions
+ * are met -
+ * For CVT timings: if reduced blanking v2 (vsync == 8) is true.
+ * For CEA861 timings: if V4L2_DV_FL_CAN_REDUCE_FPS flag is true.
+ */
+static inline  bool can_reduce_fps(struct v4l2_bt_timings *bt)
+{
+       if ((bt->standards & V4L2_DV_BT_STD_CVT) && (bt->vsync == 8))
+               return true;
+
+       if ((bt->standards & V4L2_DV_BT_STD_CEA861) &&
+           (bt->flags & V4L2_DV_FL_CAN_REDUCE_FPS))
+               return true;
+
+       return false;
+}
+
+
 #endif
index 647ebfe5174f623b27723924a521cc3f483329dd..ef03ae56b1c1cc18d9541697b353a01842b50210 100644 (file)
@@ -129,6 +129,8 @@ struct vb2_mem_ops {
  * @dbuf_mapped:       flag to show whether dbuf is mapped or not
  * @bytesused: number of bytes occupied by data in the plane (payload)
  * @length:    size of this plane (NOT the payload) in bytes
+ * @min_length:        minimum required size of this plane (NOT the payload) in bytes.
+ *             @length is always greater or equal to @min_length.
  * @offset:    when memory in the associated struct vb2_buffer is
  *             VB2_MEMORY_MMAP, equals the offset from the start of
  *             the device memory for this plane (or is a "cookie" that
@@ -150,6 +152,7 @@ struct vb2_plane {
        unsigned int            dbuf_mapped;
        unsigned int            bytesused;
        unsigned int            length;
+       unsigned int            min_length;
        union {
                unsigned int    offset;
                unsigned long   userptr;
@@ -211,6 +214,7 @@ struct vb2_queue;
  * @num_planes:                number of planes in the buffer
  *                     on an internal driver queue
  * @planes:            private per-plane information; do not change
+ * @timestamp:         frame timestamp in ns
  */
 struct vb2_buffer {
        struct vb2_queue        *vb2_queue;
@@ -219,6 +223,7 @@ struct vb2_buffer {
        unsigned int            memory;
        unsigned int            num_planes;
        struct vb2_plane        planes[VB2_MAX_PLANES];
+       u64                     timestamp;
 
        /* private: internal use only
         *
@@ -268,21 +273,26 @@ struct vb2_buffer {
  * struct vb2_ops - driver-specific callbacks
  *
  * @queue_setup:       called from VIDIOC_REQBUFS and VIDIOC_CREATE_BUFS
- *                     handlers before memory allocation, or, if
- *                     *num_planes != 0, after the allocation to verify a
- *                     smaller number of buffers. Driver should return
- *                     the required number of buffers in *num_buffers, the
- *                     required number of planes per buffer in *num_planes; the
- *                     size of each plane should be set in the sizes[] array
- *                     and optional per-plane allocator specific context in the
- *                     alloc_ctxs[] array. When called from VIDIOC_REQBUFS,
- *                     fmt == NULL, the driver has to use the currently
- *                     configured format and *num_buffers is the total number
- *                     of buffers, that are being allocated. When called from
- *                     VIDIOC_CREATE_BUFS, fmt != NULL and it describes the
- *                     target frame format (if the format isn't valid the
- *                     callback must return -EINVAL). In this case *num_buffers
- *                     are being allocated additionally to q->num_buffers.
+ *                     handlers before memory allocation. It can be called
+ *                     twice: if the original number of requested buffers
+ *                     could not be allocated, then it will be called a
+ *                     second time with the actually allocated number of
+ *                     buffers to verify if that is OK.
+ *                     The driver should return the required number of buffers
+ *                     in *num_buffers, the required number of planes per
+ *                     buffer in *num_planes, the size of each plane should be
+ *                     set in the sizes[] array and optional per-plane
+ *                     allocator specific context in the alloc_ctxs[] array.
+ *                     When called from VIDIOC_REQBUFS, *num_planes == 0, the
+ *                     driver has to use the currently configured format to
+ *                     determine the plane sizes and *num_buffers is the total
+ *                     number of buffers that are being allocated. When called
+ *                     from VIDIOC_CREATE_BUFS, *num_planes != 0 and it
+ *                     describes the requested number of planes and sizes[]
+ *                     contains the requested plane sizes. If either
+ *                     *num_planes or the requested sizes are invalid callback
+ *                     must return -EINVAL. In this case *num_buffers are
+ *                     being allocated additionally to q->num_buffers.
  * @wait_prepare:      release any locks taken while calling vb2 functions;
  *                     it is called before an ioctl needs to wait for a new
  *                     buffer to arrive; required to avoid a deadlock in
@@ -344,7 +354,7 @@ struct vb2_buffer {
  *                     pre-queued buffers before calling STREAMON.
  */
 struct vb2_ops {
-       int (*queue_setup)(struct vb2_queue *q, const void *parg,
+       int (*queue_setup)(struct vb2_queue *q,
                           unsigned int *num_buffers, unsigned int *num_planes,
                           unsigned int sizes[], void *alloc_ctxs[]);
 
@@ -362,11 +372,22 @@ struct vb2_ops {
        void (*buf_queue)(struct vb2_buffer *vb);
 };
 
+/**
+ * struct vb2_ops - driver-specific callbacks
+ *
+ * @fill_user_buffer:  given a vb2_buffer fill in the userspace structure.
+ *                     For V4L2 this is a struct v4l2_buffer.
+ * @fill_vb2_buffer:   given a userspace structure, fill in the vb2_buffer.
+ *                     If the userspace structure is invalid, then this op
+ *                     will return an error.
+ * @copy_timestamp:    copy the timestamp from a userspace structure to
+ *                     the vb2_buffer struct.
+ */
 struct vb2_buf_ops {
-       int (*fill_user_buffer)(struct vb2_buffer *vb, void *pb);
+       void (*fill_user_buffer)(struct vb2_buffer *vb, void *pb);
        int (*fill_vb2_buffer)(struct vb2_buffer *vb, const void *pb,
                                struct vb2_plane *planes);
-       int (*set_timestamp)(struct vb2_buffer *vb, const void *pb);
+       void (*copy_timestamp)(struct vb2_buffer *vb, const void *pb);
 };
 
 /**
@@ -429,6 +450,7 @@ struct vb2_buf_ops {
  *             called since poll() needs to return POLLERR in that situation.
  * @is_multiplanar: set if buffer type is multiplanar
  * @is_output: set if buffer type is output
+ * @copy_timestamp: set if vb2-core should set timestamps
  * @last_buffer_dequeued: used in poll() and DQBUF to immediately return if the
  *             last decoded buffer was already dequeued. Set for capture queues
  *             when a buffer with the V4L2_BUF_FLAG_LAST is dequeued.
@@ -470,7 +492,6 @@ struct vb2_queue {
        wait_queue_head_t               done_wq;
 
        void                            *alloc_ctx[VB2_MAX_PLANES];
-       unsigned int                    plane_sizes[VB2_MAX_PLANES];
 
        unsigned int                    streaming:1;
        unsigned int                    start_streaming_called:1;
@@ -478,6 +499,7 @@ struct vb2_queue {
        unsigned int                    waiting_for_buffers:1;
        unsigned int                    is_multiplanar:1;
        unsigned int                    is_output:1;
+       unsigned int                    copy_timestamp:1;
        unsigned int                    last_buffer_dequeued:1;
 
        struct vb2_fileio_data          *fileio;
@@ -503,11 +525,12 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state);
 void vb2_discard_done(struct vb2_queue *q);
 int vb2_wait_for_all_buffers(struct vb2_queue *q);
 
-int vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb);
+void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb);
 int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
                unsigned int *count);
 int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
-               unsigned int *count, const void *parg);
+               unsigned int *count, unsigned requested_planes,
+               const unsigned int requested_sizes[]);
 int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb);
 int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb);
 int vb2_core_dqbuf(struct vb2_queue *q, void *pb, bool nonblocking);
@@ -531,6 +554,42 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
                                    unsigned long pgoff,
                                    unsigned long flags);
 #endif
+unsigned int vb2_core_poll(struct vb2_queue *q, struct file *file,
+               poll_table *wait);
+size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
+               loff_t *ppos, int nonblock);
+size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count,
+               loff_t *ppos, int nonblock);
+
+/*
+ * vb2_thread_fnc - callback function for use with vb2_thread
+ *
+ * This is called whenever a buffer is dequeued in the thread.
+ */
+typedef int (*vb2_thread_fnc)(struct vb2_buffer *vb, void *priv);
+
+/**
+ * vb2_thread_start() - start a thread for the given queue.
+ * @q:         videobuf queue
+ * @fnc:       callback function
+ * @priv:      priv pointer passed to the callback function
+ * @thread_name:the name of the thread. This will be prefixed with "vb2-".
+ *
+ * This starts a thread that will queue and dequeue until an error occurs
+ * or @vb2_thread_stop is called.
+ *
+ * This function should not be used for anything else but the videobuf2-dvb
+ * support. If you think you have another good use-case for this, then please
+ * contact the linux-media mailinglist first.
+ */
+int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv,
+                    const char *thread_name);
+
+/**
+ * vb2_thread_stop() - stop the thread for the given queue.
+ * @q:         videobuf queue
+ */
+int vb2_thread_stop(struct vb2_queue *q);
 
 /**
  * vb2_is_streaming() - return streaming status of the queue
@@ -635,4 +694,11 @@ static inline void vb2_clear_last_buffer_dequeued(struct vb2_queue *q)
        q->last_buffer_dequeued = false;
 }
 
+/*
+ * The following functions are not part of the vb2 core API, but are useful
+ * functions for videobuf2-*.
+ */
+bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb);
+int vb2_verify_memory_type(struct vb2_queue *q,
+               enum vb2_memory memory, unsigned int type);
 #endif /* _MEDIA_VIDEOBUF2_CORE_H */
index 5abab1e7c7e869225bd546b363e54400444fc1fe..3cc836f76675faff08593bc004328d6fe7543a35 100644 (file)
@@ -28,7 +28,6 @@
  * @vb2_buf:   video buffer 2
  * @flags:     buffer informational flags
  * @field:     enum v4l2_field; field order of the image in the buffer
- * @timestamp: frame timestamp
  * @timecode:  frame timecode
  * @sequence:  sequence count of this frame
  * Should contain enough information to be able to cover all the fields
@@ -39,7 +38,6 @@ struct vb2_v4l2_buffer {
 
        __u32                   flags;
        __u32                   field;
-       struct timeval          timestamp;
        struct v4l2_timecode    timecode;
        __u32                   sequence;
 };
@@ -65,42 +63,8 @@ int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type);
 
 int __must_check vb2_queue_init(struct vb2_queue *q);
 void vb2_queue_release(struct vb2_queue *q);
-
-unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait);
-size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
-               loff_t *ppos, int nonblock);
-size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count,
-               loff_t *ppos, int nonblock);
-
-/*
- * vb2_thread_fnc - callback function for use with vb2_thread
- *
- * This is called whenever a buffer is dequeued in the thread.
- */
-typedef int (*vb2_thread_fnc)(struct vb2_buffer *vb, void *priv);
-
-/**
- * vb2_thread_start() - start a thread for the given queue.
- * @q:         videobuf queue
- * @fnc:       callback function
- * @priv:      priv pointer passed to the callback function
- * @thread_name:the name of the thread. This will be prefixed with "vb2-".
- *
- * This starts a thread that will queue and dequeue until an error occurs
- * or @vb2_thread_stop is called.
- *
- * This function should not be used for anything else but the videobuf2-dvb
- * support. If you think you have another good use-case for this, then please
- * contact the linux-media mailinglist first.
- */
-int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv,
-                    const char *thread_name);
-
-/**
- * vb2_thread_stop() - stop the thread for the given queue.
- * @q:         videobuf queue
- */
-int vb2_thread_stop(struct vb2_queue *q);
+unsigned int vb2_poll(struct vb2_queue *q, struct file *file,
+               poll_table *wait);
 
 /*
  * The following functions are not part of the vb2 core API, but are simple
diff --git a/include/media/wm8775.h b/include/media/wm8775.h
deleted file mode 100644 (file)
index d0e801a..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-    wm8775.h - definition for wm8775 inputs and outputs
-
-    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
-
-    This program is 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 _WM8775_H_
-#define _WM8775_H_
-
-/* The WM8775 has 4 inputs and one output. Zero or more inputs
-   are multiplexed together to the output. Hence there are
-   16 combinations.
-   If only one input is active (the normal case) then the
-   input values 1, 2, 4 or 8 should be used. */
-
-#define WM8775_AIN1 1
-#define WM8775_AIN2 2
-#define WM8775_AIN3 4
-#define WM8775_AIN4 8
-
-
-struct wm8775_platform_data {
-       /*
-        * FIXME: Instead, we should parametrize the params
-        * that need different settings between ivtv, pvrusb2, and Nova-S
-        */
-       bool is_nova_s;
-};
-
-#endif
index 774d85b2d5d97734b79eadea20f090ebf684b057..5689a0c749f76cd7ce5810b6ac165e43ddb0b59d 100644 (file)
@@ -29,7 +29,7 @@ struct l3mdev_ops {
        /* IPv4 ops */
        struct rtable * (*l3mdev_get_rtable)(const struct net_device *dev,
                                             const struct flowi4 *fl4);
-       void            (*l3mdev_get_saddr)(struct net_device *dev,
+       int             (*l3mdev_get_saddr)(struct net_device *dev,
                                            struct flowi4 *fl4);
 
        /* IPv6 ops */
@@ -112,10 +112,11 @@ static inline bool netif_index_is_l3_master(struct net *net, int ifindex)
        return rc;
 }
 
-static inline void l3mdev_get_saddr(struct net *net, int ifindex,
-                                   struct flowi4 *fl4)
+static inline int l3mdev_get_saddr(struct net *net, int ifindex,
+                                  struct flowi4 *fl4)
 {
        struct net_device *dev;
+       int rc = 0;
 
        if (ifindex) {
 
@@ -124,11 +125,13 @@ static inline void l3mdev_get_saddr(struct net *net, int ifindex,
                dev = dev_get_by_index_rcu(net, ifindex);
                if (dev && netif_is_l3_master(dev) &&
                    dev->l3mdev_ops->l3mdev_get_saddr) {
-                       dev->l3mdev_ops->l3mdev_get_saddr(dev, fl4);
+                       rc = dev->l3mdev_ops->l3mdev_get_saddr(dev, fl4);
                }
 
                rcu_read_unlock();
        }
+
+       return rc;
 }
 
 static inline struct dst_entry *l3mdev_get_rt6_dst(const struct net_device *dev,
@@ -200,9 +203,10 @@ static inline bool netif_index_is_l3_master(struct net *net, int ifindex)
        return false;
 }
 
-static inline void l3mdev_get_saddr(struct net *net, int ifindex,
-                                   struct flowi4 *fl4)
+static inline int l3mdev_get_saddr(struct net *net, int ifindex,
+                                  struct flowi4 *fl4)
 {
+       return 0;
 }
 
 static inline
index ee81307863d56329c097bb3ec30d06b07828b2d0..a3b9ef74a3895dbce95b0eba9b4bb298f7be9d71 100644 (file)
@@ -283,7 +283,12 @@ static inline struct rtable *ip_route_connect(struct flowi4 *fl4,
                              sport, dport, sk);
 
        if (!src && oif) {
-               l3mdev_get_saddr(net, oif, fl4);
+               int rc;
+
+               rc = l3mdev_get_saddr(net, oif, fl4);
+               if (rc < 0)
+                       return ERR_PTR(rc);
+
                src = fl4->saddr;
        }
        if (!dst || !src) {
index a8b4b9c8b1d2415e7220913715fc2cd4bd95212c..fb955e69a78ea29f79bd4382b492bca009cd6fe7 100644 (file)
@@ -1655,7 +1655,7 @@ extern const struct dev_pm_ops snd_soc_pm_ops;
 /* Helper functions */
 static inline void snd_soc_dapm_mutex_lock(struct snd_soc_dapm_context *dapm)
 {
-       mutex_lock(&dapm->card->dapm_mutex);
+       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 }
 
 static inline void snd_soc_dapm_mutex_unlock(struct snd_soc_dapm_context *dapm)
index 22afa26e34b2f69f9df1dbf26eb95cd78bfe5986..ee7754c6e4a1279e87974f62c8d9c7c3fa3d152c 100644 (file)
@@ -184,7 +184,7 @@ DECLARE_EVENT_CLASS(vb2_v4l2_event_class,
                __field(int, minor)
                __field(u32, flags)
                __field(u32, field)
-               __field(s64, timestamp)
+               __field(u64, timestamp)
                __field(u32, timecode_type)
                __field(u32, timecode_flags)
                __field(u8, timecode_frames)
@@ -205,7 +205,7 @@ DECLARE_EVENT_CLASS(vb2_v4l2_event_class,
                __entry->minor = owner ? owner->vdev->minor : -1;
                __entry->flags = vbuf->flags;
                __entry->field = vbuf->field;
-               __entry->timestamp = timeval_to_ns(&vbuf->timestamp);
+               __entry->timestamp = vb->timestamp;
                __entry->timecode_type = vbuf->timecode.type;
                __entry->timecode_flags = vbuf->timecode.flags;
                __entry->timecode_frames = vbuf->timecode.frames;
index bfeceeba37448d4ef2525deb8eeb23990e7fdd91..c1a22416ed0551b36f0467d320d511c8eb95dbf5 100644 (file)
@@ -18,6 +18,7 @@ DECLARE_EVENT_CLASS(vb2_event_class,
                __field(u32, index)
                __field(u32, type)
                __field(u32, bytesused)
+               __field(u64, timestamp)
        ),
 
        TP_fast_assign(
@@ -28,14 +29,16 @@ DECLARE_EVENT_CLASS(vb2_event_class,
                __entry->index = vb->index;
                __entry->type = vb->type;
                __entry->bytesused = vb->planes[0].bytesused;
+               __entry->timestamp = vb->timestamp;
        ),
 
        TP_printk("owner = %p, queued = %u, owned_by_drv = %d, index = %u, "
-                 "type = %u, bytesused = %u", __entry->owner,
+                 "type = %u, bytesused = %u, timestamp = %llu", __entry->owner,
                  __entry->queued_count,
                  __entry->owned_by_drv_count,
                  __entry->index, __entry->type,
-                 __entry->bytesused
+                 __entry->bytesused,
+                 __entry->timestamp
        )
 )
 
index 0b69a7753558ff27a07748f2d5ca7f3f054b2ba2..ee2d542c65f5f91f9e7114900420bc391c0d6830 100644 (file)
  * - multiple of 128 pixels for the width
  * - multiple of  32 pixels for the height
  *
- * For more information: see http://linuxtv.org/downloads/v4l-dvb-apis/re32.html
+ * For more information: see https://linuxtv.org/downloads/v4l-dvb-apis/re32.html
  */
 #define DRM_FORMAT_MOD_SAMSUNG_64_32_TILE      fourcc_mod_code(SAMSUNG, 1)
 
index d3d14a59d2d5b834a153a7b56b91e933164f68f7..49392564f9d6fc0c7c105887818a5dcf0e955e90 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <linux/types.h>
 #ifndef __KERNEL__
-#include <stdint.h>
 #include <time.h>
 #endif
 
index 03f3618612aa5e1dfe97c1ad2dab0d7ee031fa31..9da905157ceeebcb5afbd9e73b8ac56195954929 100644 (file)
@@ -154,6 +154,20 @@ struct kvm_s390_skeys {
        __u32 flags;
        __u32 reserved[9];
 };
+
+struct kvm_hyperv_exit {
+#define KVM_EXIT_HYPERV_SYNIC          1
+       __u32 type;
+       union {
+               struct {
+                       __u32 msr;
+                       __u64 control;
+                       __u64 evt_page;
+                       __u64 msg_page;
+               } synic;
+       } u;
+};
+
 #define KVM_S390_GET_SKEYS_NONE   1
 #define KVM_S390_SKEYS_MAX        1048576
 
@@ -184,6 +198,7 @@ struct kvm_s390_skeys {
 #define KVM_EXIT_SYSTEM_EVENT     24
 #define KVM_EXIT_S390_STSI        25
 #define KVM_EXIT_IOAPIC_EOI       26
+#define KVM_EXIT_HYPERV           27
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 /* Emulate instruction failed. */
@@ -338,6 +353,8 @@ struct kvm_run {
                struct {
                        __u8 vector;
                } eoi;
+               /* KVM_EXIT_HYPERV */
+               struct kvm_hyperv_exit hyperv;
                /* Fix the size of the union. */
                char padding[256];
        };
@@ -831,6 +848,8 @@ struct kvm_ppc_smmu_info {
 #define KVM_CAP_GUEST_DEBUG_HW_WPS 120
 #define KVM_CAP_SPLIT_IRQCHIP 121
 #define KVM_CAP_IOEVENTFD_ANY_LENGTH 122
+#define KVM_CAP_HYPERV_SYNIC 123
+#define KVM_CAP_S390_RI 124
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -854,10 +873,16 @@ struct kvm_irq_routing_s390_adapter {
        __u32 adapter_id;
 };
 
+struct kvm_irq_routing_hv_sint {
+       __u32 vcpu;
+       __u32 sint;
+};
+
 /* gsi routing entry types */
 #define KVM_IRQ_ROUTING_IRQCHIP 1
 #define KVM_IRQ_ROUTING_MSI 2
 #define KVM_IRQ_ROUTING_S390_ADAPTER 3
+#define KVM_IRQ_ROUTING_HV_SINT 4
 
 struct kvm_irq_routing_entry {
        __u32 gsi;
@@ -868,6 +893,7 @@ struct kvm_irq_routing_entry {
                struct kvm_irq_routing_irqchip irqchip;
                struct kvm_irq_routing_msi msi;
                struct kvm_irq_routing_s390_adapter adapter;
+               struct kvm_irq_routing_hv_sint hv_sint;
                __u32 pad[8];
        } u;
 };
diff --git a/include/uapi/linux/lirc.h b/include/uapi/linux/lirc.h
new file mode 100644 (file)
index 0000000..4b3ab29
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * lirc.h - linux infrared remote control header file
+ * last modified 2010/07/13 by Jarod Wilson
+ */
+
+#ifndef _LINUX_LIRC_H
+#define _LINUX_LIRC_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define PULSE_BIT       0x01000000
+#define PULSE_MASK      0x00FFFFFF
+
+#define LIRC_MODE2_SPACE     0x00000000
+#define LIRC_MODE2_PULSE     0x01000000
+#define LIRC_MODE2_FREQUENCY 0x02000000
+#define LIRC_MODE2_TIMEOUT   0x03000000
+
+#define LIRC_VALUE_MASK      0x00FFFFFF
+#define LIRC_MODE2_MASK      0xFF000000
+
+#define LIRC_SPACE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_SPACE)
+#define LIRC_PULSE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_PULSE)
+#define LIRC_FREQUENCY(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_FREQUENCY)
+#define LIRC_TIMEOUT(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_TIMEOUT)
+
+#define LIRC_VALUE(val) ((val)&LIRC_VALUE_MASK)
+#define LIRC_MODE2(val) ((val)&LIRC_MODE2_MASK)
+
+#define LIRC_IS_SPACE(val) (LIRC_MODE2(val) == LIRC_MODE2_SPACE)
+#define LIRC_IS_PULSE(val) (LIRC_MODE2(val) == LIRC_MODE2_PULSE)
+#define LIRC_IS_FREQUENCY(val) (LIRC_MODE2(val) == LIRC_MODE2_FREQUENCY)
+#define LIRC_IS_TIMEOUT(val) (LIRC_MODE2(val) == LIRC_MODE2_TIMEOUT)
+
+/* used heavily by lirc userspace */
+#define lirc_t int
+
+/*** lirc compatible hardware features ***/
+
+#define LIRC_MODE2SEND(x) (x)
+#define LIRC_SEND2MODE(x) (x)
+#define LIRC_MODE2REC(x) ((x) << 16)
+#define LIRC_REC2MODE(x) ((x) >> 16)
+
+#define LIRC_MODE_RAW                  0x00000001
+#define LIRC_MODE_PULSE                0x00000002
+#define LIRC_MODE_MODE2                0x00000004
+#define LIRC_MODE_LIRCCODE             0x00000010
+
+
+#define LIRC_CAN_SEND_RAW              LIRC_MODE2SEND(LIRC_MODE_RAW)
+#define LIRC_CAN_SEND_PULSE            LIRC_MODE2SEND(LIRC_MODE_PULSE)
+#define LIRC_CAN_SEND_MODE2            LIRC_MODE2SEND(LIRC_MODE_MODE2)
+#define LIRC_CAN_SEND_LIRCCODE         LIRC_MODE2SEND(LIRC_MODE_LIRCCODE)
+
+#define LIRC_CAN_SEND_MASK             0x0000003f
+
+#define LIRC_CAN_SET_SEND_CARRIER      0x00000100
+#define LIRC_CAN_SET_SEND_DUTY_CYCLE   0x00000200
+#define LIRC_CAN_SET_TRANSMITTER_MASK  0x00000400
+
+#define LIRC_CAN_REC_RAW               LIRC_MODE2REC(LIRC_MODE_RAW)
+#define LIRC_CAN_REC_PULSE             LIRC_MODE2REC(LIRC_MODE_PULSE)
+#define LIRC_CAN_REC_MODE2             LIRC_MODE2REC(LIRC_MODE_MODE2)
+#define LIRC_CAN_REC_LIRCCODE          LIRC_MODE2REC(LIRC_MODE_LIRCCODE)
+
+#define LIRC_CAN_REC_MASK              LIRC_MODE2REC(LIRC_CAN_SEND_MASK)
+
+#define LIRC_CAN_SET_REC_CARRIER       (LIRC_CAN_SET_SEND_CARRIER << 16)
+#define LIRC_CAN_SET_REC_DUTY_CYCLE    (LIRC_CAN_SET_SEND_DUTY_CYCLE << 16)
+
+#define LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE 0x40000000
+#define LIRC_CAN_SET_REC_CARRIER_RANGE    0x80000000
+#define LIRC_CAN_GET_REC_RESOLUTION       0x20000000
+#define LIRC_CAN_SET_REC_TIMEOUT          0x10000000
+#define LIRC_CAN_SET_REC_FILTER           0x08000000
+
+#define LIRC_CAN_MEASURE_CARRIER          0x02000000
+#define LIRC_CAN_USE_WIDEBAND_RECEIVER    0x04000000
+
+#define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK)
+#define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK)
+
+#define LIRC_CAN_NOTIFY_DECODE            0x01000000
+
+/*** IOCTL commands for lirc driver ***/
+
+#define LIRC_GET_FEATURES              _IOR('i', 0x00000000, __u32)
+
+#define LIRC_GET_SEND_MODE             _IOR('i', 0x00000001, __u32)
+#define LIRC_GET_REC_MODE              _IOR('i', 0x00000002, __u32)
+#define LIRC_GET_SEND_CARRIER          _IOR('i', 0x00000003, __u32)
+#define LIRC_GET_REC_CARRIER           _IOR('i', 0x00000004, __u32)
+#define LIRC_GET_SEND_DUTY_CYCLE       _IOR('i', 0x00000005, __u32)
+#define LIRC_GET_REC_DUTY_CYCLE        _IOR('i', 0x00000006, __u32)
+#define LIRC_GET_REC_RESOLUTION        _IOR('i', 0x00000007, __u32)
+
+#define LIRC_GET_MIN_TIMEOUT           _IOR('i', 0x00000008, __u32)
+#define LIRC_GET_MAX_TIMEOUT           _IOR('i', 0x00000009, __u32)
+
+#define LIRC_GET_MIN_FILTER_PULSE      _IOR('i', 0x0000000a, __u32)
+#define LIRC_GET_MAX_FILTER_PULSE      _IOR('i', 0x0000000b, __u32)
+#define LIRC_GET_MIN_FILTER_SPACE      _IOR('i', 0x0000000c, __u32)
+#define LIRC_GET_MAX_FILTER_SPACE      _IOR('i', 0x0000000d, __u32)
+
+/* code length in bits, currently only for LIRC_MODE_LIRCCODE */
+#define LIRC_GET_LENGTH                _IOR('i', 0x0000000f, __u32)
+
+#define LIRC_SET_SEND_MODE             _IOW('i', 0x00000011, __u32)
+#define LIRC_SET_REC_MODE              _IOW('i', 0x00000012, __u32)
+/* Note: these can reset the according pulse_width */
+#define LIRC_SET_SEND_CARRIER          _IOW('i', 0x00000013, __u32)
+#define LIRC_SET_REC_CARRIER           _IOW('i', 0x00000014, __u32)
+#define LIRC_SET_SEND_DUTY_CYCLE       _IOW('i', 0x00000015, __u32)
+#define LIRC_SET_REC_DUTY_CYCLE        _IOW('i', 0x00000016, __u32)
+#define LIRC_SET_TRANSMITTER_MASK      _IOW('i', 0x00000017, __u32)
+
+/*
+ * when a timeout != 0 is set the driver will send a
+ * LIRC_MODE2_TIMEOUT data packet, otherwise LIRC_MODE2_TIMEOUT is
+ * never sent, timeout is disabled by default
+ */
+#define LIRC_SET_REC_TIMEOUT           _IOW('i', 0x00000018, __u32)
+
+/* 1 enables, 0 disables timeout reports in MODE2 */
+#define LIRC_SET_REC_TIMEOUT_REPORTS   _IOW('i', 0x00000019, __u32)
+
+/*
+ * pulses shorter than this are filtered out by hardware (software
+ * emulation in lirc_dev?)
+ */
+#define LIRC_SET_REC_FILTER_PULSE      _IOW('i', 0x0000001a, __u32)
+/*
+ * spaces shorter than this are filtered out by hardware (software
+ * emulation in lirc_dev?)
+ */
+#define LIRC_SET_REC_FILTER_SPACE      _IOW('i', 0x0000001b, __u32)
+/*
+ * if filter cannot be set independently for pulse/space, this should
+ * be used
+ */
+#define LIRC_SET_REC_FILTER            _IOW('i', 0x0000001c, __u32)
+
+/*
+ * if enabled from the next key press on the driver will send
+ * LIRC_MODE2_FREQUENCY packets
+ */
+#define LIRC_SET_MEASURE_CARRIER_MODE  _IOW('i', 0x0000001d, __u32)
+
+/*
+ * to set a range use
+ * LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE with the
+ * lower bound first and later
+ * LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER with the upper bound
+ */
+
+#define LIRC_SET_REC_DUTY_CYCLE_RANGE  _IOW('i', 0x0000001e, __u32)
+#define LIRC_SET_REC_CARRIER_RANGE     _IOW('i', 0x0000001f, __u32)
+
+#define LIRC_NOTIFY_DECODE             _IO('i', 0x00000020)
+
+#define LIRC_SETUP_START               _IO('i', 0x00000021)
+#define LIRC_SETUP_END                 _IO('i', 0x00000022)
+
+#define LIRC_SET_WIDEBAND_RECEIVER     _IOW('i', 0x00000023, __u32)
+
+#endif
index d801bb0d9f6d2b08b6be600565716d045d8b85ca..1afe9623c1a7268cd2ef8949a248ef79216fe2e9 100644 (file)
@@ -171,6 +171,9 @@ enum perf_branch_sample_type_shift {
        PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT       = 12, /* indirect jumps */
        PERF_SAMPLE_BRANCH_CALL_SHIFT           = 13, /* direct call */
 
+       PERF_SAMPLE_BRANCH_NO_FLAGS_SHIFT       = 14, /* no flags */
+       PERF_SAMPLE_BRANCH_NO_CYCLES_SHIFT      = 15, /* no cycles */
+
        PERF_SAMPLE_BRANCH_MAX_SHIFT            /* non-ABI */
 };
 
@@ -192,6 +195,9 @@ enum perf_branch_sample_type {
        PERF_SAMPLE_BRANCH_IND_JUMP     = 1U << PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT,
        PERF_SAMPLE_BRANCH_CALL         = 1U << PERF_SAMPLE_BRANCH_CALL_SHIFT,
 
+       PERF_SAMPLE_BRANCH_NO_FLAGS     = 1U << PERF_SAMPLE_BRANCH_NO_FLAGS_SHIFT,
+       PERF_SAMPLE_BRANCH_NO_CYCLES    = 1U << PERF_SAMPLE_BRANCH_NO_CYCLES_SHIFT,
+
        PERF_SAMPLE_BRANCH_MAX          = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT,
 };
 
index 3b3b95e01f71b338542cd7844811e3e0ee7fc240..69ab695fad2e2729bd68921ff934ec095ae07121 100644 (file)
@@ -28,6 +28,7 @@
 
 /* A.3. Video Interface Protocol Codes */
 #define UVC_PC_PROTOCOL_UNDEFINED                      0x00
+#define UVC_PC_PROTOCOL_15                             0x01
 
 /* A.5. Video Class-Specific VC Interface Descriptor Subtypes */
 #define UVC_VC_DESCRIPTOR_UNDEFINED                    0x00
index 1bdce501ad6baca443258afc0f8e6210491f9e7d..2d225bcdb83149aac3407b6c21777b76bcec98d8 100644 (file)
@@ -158,8 +158,10 @@ enum v4l2_colorfx {
  * We reserve 16 controls for this driver. */
 #define V4L2_CID_USER_S2255_BASE               (V4L2_CID_USER_BASE + 0x1030)
 
-/* The base for the si476x driver controls. See include/media/si476x.h for the list
- * of controls. Total of 16 controls is reserved for this driver */
+/*
+ * The base for the si476x driver controls. See include/media/drv-intf/si476x.h
+ * for the list of controls. Total of 16 controls is reserved for this driver
+ */
 #define V4L2_CID_USER_SI476X_BASE              (V4L2_CID_USER_BASE + 0x1040)
 
 /* The base for the TI VPE driver controls. Total of 16 controls is reserved for
index a0e87d16b72672d4f7e688a319a08a455824094d..14cd5ebfee6d40e852b50881826b3e2bb8f1b980 100644 (file)
@@ -46,7 +46,7 @@
  * All kernel-specific stuff were moved to media/v4l2-dev.h, so
  * no #if __KERNEL tests are allowed here
  *
- *     See http://linuxtv.org for more info
+ *     See https://linuxtv.org for more info
  *
  *     Author: Bill Dirks <bill@thedirks.org>
  *             Justin Schoeman
@@ -1476,7 +1476,12 @@ struct v4l2_ext_control {
 } __attribute__ ((packed));
 
 struct v4l2_ext_controls {
-       __u32 ctrl_class;
+       union {
+#ifndef __KERNEL__
+               __u32 ctrl_class;
+#endif
+               __u32 which;
+       };
        __u32 count;
        __u32 error_idx;
        __u32 reserved[2];
@@ -1484,9 +1489,14 @@ struct v4l2_ext_controls {
 };
 
 #define V4L2_CTRL_ID_MASK                (0x0fffffff)
+#ifndef __KERNEL__
 #define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
+#endif
+#define V4L2_CTRL_ID2WHICH(id)    ((id) & 0x0fff0000UL)
 #define V4L2_CTRL_DRIVER_PRIV(id) (((id) & 0xffff) >= 0x1000)
 #define V4L2_CTRL_MAX_DIMS       (4)
+#define V4L2_CTRL_WHICH_CUR_VAL   0
+#define V4L2_CTRL_WHICH_DEF_VAL   0x0f000000
 
 enum v4l2_ctrl_type {
        V4L2_CTRL_TYPE_INTEGER       = 1,
index aa7610a9b86765945c052215473262dfa95450d5..d0661977667e00c57f485954a79119f3cea49ca4 100644 (file)
@@ -144,6 +144,56 @@ struct ioctl_gntdev_unmap_notify {
        __u32 event_channel_port;
 };
 
+struct gntdev_grant_copy_segment {
+       union {
+               void __user *virt;
+               struct {
+                       grant_ref_t ref;
+                       __u16 offset;
+                       domid_t domid;
+               } foreign;
+       } source, dest;
+       __u16 len;
+
+       __u16 flags;  /* GNTCOPY_* */
+       __s16 status; /* GNTST_* */
+};
+
+/*
+ * Copy between grant references and local buffers.
+ *
+ * The copy is split into @count @segments, each of which can copy
+ * to/from one grant reference.
+ *
+ * Each segment is similar to struct gnttab_copy in the hypervisor ABI
+ * except the local buffer is specified using a virtual address
+ * (instead of a GFN and offset).
+ *
+ * The local buffer may cross a Xen page boundary -- the driver will
+ * split segments into multiple ops if required.
+ *
+ * Returns 0 if all segments have been processed and @status in each
+ * segment is valid.  Note that one or more segments may have failed
+ * (status != GNTST_okay).
+ *
+ * If the driver had to split a segment into two or more ops, @status
+ * includes the status of the first failed op for that segment (or
+ * GNTST_okay if all ops were successful).
+ *
+ * If -1 is returned, the status of all segments is undefined.
+ *
+ * EINVAL: A segment has local buffers for both source and
+ *         destination.
+ * EINVAL: A segment crosses the boundary of a foreign page.
+ * EFAULT: A segment's local buffer is not accessible.
+ */
+#define IOCTL_GNTDEV_GRANT_COPY \
+       _IOC(_IOC_NONE, 'G', 8, sizeof(struct ioctl_gntdev_grant_copy))
+struct ioctl_gntdev_grant_copy {
+       unsigned int count;
+       struct gntdev_grant_copy_segment __user *segments;
+};
+
 /* Clear (set to zero) the byte specified by index */
 #define UNMAP_NOTIFY_CLEAR_BYTE 0x1
 /* Send an interrupt on the indicated event channel */
index 8e035871360e15e0593a026d151088a8d7482347..732efb08c3e17ecb422c4df84eb3aeed4472d5eb 100644 (file)
  * Set clock such that it would read <secs,nsecs> after 00:00:00 UTC,
  * 1 January, 1970 if the current system time was <system_time>.
  */
-#define XENPF_settime             17
-struct xenpf_settime {
+#define XENPF_settime32             17
+struct xenpf_settime32 {
        /* IN variables. */
        uint32_t secs;
        uint32_t nsecs;
        uint64_t system_time;
 };
-DEFINE_GUEST_HANDLE_STRUCT(xenpf_settime_t);
+DEFINE_GUEST_HANDLE_STRUCT(xenpf_settime32_t);
+#define XENPF_settime64           62
+struct xenpf_settime64 {
+    /* IN variables. */
+    uint64_t secs;
+    uint32_t nsecs;
+    uint32_t mbz;
+    uint64_t system_time;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xenpf_settime64_t);
 
 /*
  * Request memory range (@mfn, @mfn+@nr_mfns-1) to have type @type.
@@ -495,7 +504,8 @@ struct xen_platform_op {
        uint32_t cmd;
        uint32_t interface_version; /* XENPF_INTERFACE_VERSION */
        union {
-               struct xenpf_settime           settime;
+               struct xenpf_settime32         settime32;
+               struct xenpf_settime64         settime64;
                struct xenpf_add_memtype       add_memtype;
                struct xenpf_del_memtype       del_memtype;
                struct xenpf_read_memtype      read_memtype;
index 167071c290b3d2afbb8fe949cf668dd19077367e..d1331121c0bd8c31a4f2b0e3e9a85b37078b30bf 100644 (file)
@@ -48,7 +48,7 @@
 #define __HYPERVISOR_set_callbacks         4
 #define __HYPERVISOR_fpu_taskswitch        5
 #define __HYPERVISOR_sched_op_compat       6
-#define __HYPERVISOR_dom0_op               7
+#define __HYPERVISOR_platform_op           7
 #define __HYPERVISOR_set_debugreg          8
 #define __HYPERVISOR_get_debugreg          9
 #define __HYPERVISOR_update_descriptor    10
index e4e214a5abd531b0fa1805186ac32a5cb8576253..86abe07b20ec71459e7d5d0613b92886f2655980 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/notifier.h>
 #include <linux/efi.h>
 #include <asm/xen/interface.h>
+#include <xen/interface/vcpu.h>
 
 DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu);
 
@@ -18,6 +19,10 @@ void xen_arch_suspend(void);
 void xen_resume_notifier_register(struct notifier_block *nb);
 void xen_resume_notifier_unregister(struct notifier_block *nb);
 
+bool xen_vcpu_stolen(int vcpu);
+void xen_setup_runstate_info(int cpu);
+void xen_get_runstate_snapshot(struct vcpu_runstate_info *res);
+
 int xen_setup_shutdown_event(void);
 
 extern unsigned long *xen_contiguous_bitmap;
index 9e64d7097f1ad4d5744755c977cac583debbaf38..c6ebefafa496106fbb398656245d75f4d59f1f8d 100644 (file)
@@ -943,6 +943,8 @@ static int __ref kernel_init(void *unused)
 
        flush_delayed_fput();
 
+       rcu_end_inkernel_boot();
+
        if (ramdisk_execute_command) {
                ret = run_init_process(ramdisk_execute_command);
                if (!ret)
index d8560ee3bab788c15be6d1be8eb610473fc5c4b5..9ad37b9e44a7034d887fe1eda6650070490ee2d5 100644 (file)
@@ -24,7 +24,7 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/context_tracking.h>
 
-struct static_key context_tracking_enabled = STATIC_KEY_INIT_FALSE;
+DEFINE_STATIC_KEY_FALSE(context_tracking_enabled);
 EXPORT_SYMBOL_GPL(context_tracking_enabled);
 
 DEFINE_PER_CPU(struct context_tracking, context_tracking);
@@ -191,7 +191,7 @@ void __init context_tracking_cpu_set(int cpu)
 
        if (!per_cpu(context_tracking.active, cpu)) {
                per_cpu(context_tracking.active, cpu) = true;
-               static_key_slow_inc(&context_tracking_enabled);
+               static_branch_inc(&context_tracking_enabled);
        }
 
        if (initialized)
index ef2d6ea10736e4805e758cae83524dc13c2f06e9..bf8244190d0faa696336c4d4ae9b609a95d5c50b 100644 (file)
@@ -126,6 +126,37 @@ static int cpu_function_call(int cpu, remote_function_f func, void *info)
        return data.ret;
 }
 
+static void event_function_call(struct perf_event *event,
+                               int (*active)(void *),
+                               void (*inactive)(void *),
+                               void *data)
+{
+       struct perf_event_context *ctx = event->ctx;
+       struct task_struct *task = ctx->task;
+
+       if (!task) {
+               cpu_function_call(event->cpu, active, data);
+               return;
+       }
+
+again:
+       if (!task_function_call(task, active, data))
+               return;
+
+       raw_spin_lock_irq(&ctx->lock);
+       if (ctx->is_active) {
+               /*
+                * Reload the task pointer, it might have been changed by
+                * a concurrent perf_event_context_sched_out().
+                */
+               task = ctx->task;
+               raw_spin_unlock_irq(&ctx->lock);
+               goto again;
+       }
+       inactive(data);
+       raw_spin_unlock_irq(&ctx->lock);
+}
+
 #define EVENT_OWNER_KERNEL ((void *) -1)
 
 static bool is_kernel_event(struct perf_event *event)
@@ -1629,6 +1660,17 @@ struct remove_event {
        bool detach_group;
 };
 
+static void ___perf_remove_from_context(void *info)
+{
+       struct remove_event *re = info;
+       struct perf_event *event = re->event;
+       struct perf_event_context *ctx = event->ctx;
+
+       if (re->detach_group)
+               perf_group_detach(event);
+       list_del_event(event, ctx);
+}
+
 /*
  * Cross CPU call to remove a performance event
  *
@@ -1656,7 +1698,6 @@ static int __perf_remove_from_context(void *info)
        return 0;
 }
 
-
 /*
  * Remove the event from a task's (or a CPU's) list of events.
  *
@@ -1673,7 +1714,6 @@ static int __perf_remove_from_context(void *info)
 static void perf_remove_from_context(struct perf_event *event, bool detach_group)
 {
        struct perf_event_context *ctx = event->ctx;
-       struct task_struct *task = ctx->task;
        struct remove_event re = {
                .event = event,
                .detach_group = detach_group,
@@ -1681,44 +1721,8 @@ static void perf_remove_from_context(struct perf_event *event, bool detach_group
 
        lockdep_assert_held(&ctx->mutex);
 
-       if (!task) {
-               /*
-                * Per cpu events are removed via an smp call. The removal can
-                * fail if the CPU is currently offline, but in that case we
-                * already called __perf_remove_from_context from
-                * perf_event_exit_cpu.
-                */
-               cpu_function_call(event->cpu, __perf_remove_from_context, &re);
-               return;
-       }
-
-retry:
-       if (!task_function_call(task, __perf_remove_from_context, &re))
-               return;
-
-       raw_spin_lock_irq(&ctx->lock);
-       /*
-        * If we failed to find a running task, but find the context active now
-        * that we've acquired the ctx->lock, retry.
-        */
-       if (ctx->is_active) {
-               raw_spin_unlock_irq(&ctx->lock);
-               /*
-                * Reload the task pointer, it might have been changed by
-                * a concurrent perf_event_context_sched_out().
-                */
-               task = ctx->task;
-               goto retry;
-       }
-
-       /*
-        * Since the task isn't running, its safe to remove the event, us
-        * holding the ctx->lock ensures the task won't get scheduled in.
-        */
-       if (detach_group)
-               perf_group_detach(event);
-       list_del_event(event, ctx);
-       raw_spin_unlock_irq(&ctx->lock);
+       event_function_call(event, __perf_remove_from_context,
+                           ___perf_remove_from_context, &re);
 }
 
 /*
@@ -1762,6 +1766,20 @@ int __perf_event_disable(void *info)
        return 0;
 }
 
+void ___perf_event_disable(void *info)
+{
+       struct perf_event *event = info;
+
+       /*
+        * Since we have the lock this context can't be scheduled
+        * in, so we can change the state safely.
+        */
+       if (event->state == PERF_EVENT_STATE_INACTIVE) {
+               update_group_times(event);
+               event->state = PERF_EVENT_STATE_OFF;
+       }
+}
+
 /*
  * Disable a event.
  *
@@ -1778,43 +1796,16 @@ int __perf_event_disable(void *info)
 static void _perf_event_disable(struct perf_event *event)
 {
        struct perf_event_context *ctx = event->ctx;
-       struct task_struct *task = ctx->task;
-
-       if (!task) {
-               /*
-                * Disable the event on the cpu that it's on
-                */
-               cpu_function_call(event->cpu, __perf_event_disable, event);
-               return;
-       }
-
-retry:
-       if (!task_function_call(task, __perf_event_disable, event))
-               return;
 
        raw_spin_lock_irq(&ctx->lock);
-       /*
-        * If the event is still active, we need to retry the cross-call.
-        */
-       if (event->state == PERF_EVENT_STATE_ACTIVE) {
+       if (event->state <= PERF_EVENT_STATE_OFF) {
                raw_spin_unlock_irq(&ctx->lock);
-               /*
-                * Reload the task pointer, it might have been changed by
-                * a concurrent perf_event_context_sched_out().
-                */
-               task = ctx->task;
-               goto retry;
-       }
-
-       /*
-        * Since we have the lock this context can't be scheduled
-        * in, so we can change the state safely.
-        */
-       if (event->state == PERF_EVENT_STATE_INACTIVE) {
-               update_group_times(event);
-               event->state = PERF_EVENT_STATE_OFF;
+               return;
        }
        raw_spin_unlock_irq(&ctx->lock);
+
+       event_function_call(event, __perf_event_disable,
+                           ___perf_event_disable, event);
 }
 
 /*
@@ -2067,6 +2058,18 @@ static void perf_event_sched_in(struct perf_cpu_context *cpuctx,
                ctx_sched_in(ctx, cpuctx, EVENT_FLEXIBLE, task);
 }
 
+static void ___perf_install_in_context(void *info)
+{
+       struct perf_event *event = info;
+       struct perf_event_context *ctx = event->ctx;
+
+       /*
+        * Since the task isn't running, its safe to add the event, us holding
+        * the ctx->lock ensures the task won't get scheduled in.
+        */
+       add_event_to_ctx(event, ctx);
+}
+
 /*
  * Cross CPU call to install and enable a performance event
  *
@@ -2143,48 +2146,14 @@ perf_install_in_context(struct perf_event_context *ctx,
                        struct perf_event *event,
                        int cpu)
 {
-       struct task_struct *task = ctx->task;
-
        lockdep_assert_held(&ctx->mutex);
 
        event->ctx = ctx;
        if (event->cpu != -1)
                event->cpu = cpu;
 
-       if (!task) {
-               /*
-                * Per cpu events are installed via an smp call and
-                * the install is always successful.
-                */
-               cpu_function_call(cpu, __perf_install_in_context, event);
-               return;
-       }
-
-retry:
-       if (!task_function_call(task, __perf_install_in_context, event))
-               return;
-
-       raw_spin_lock_irq(&ctx->lock);
-       /*
-        * If we failed to find a running task, but find the context active now
-        * that we've acquired the ctx->lock, retry.
-        */
-       if (ctx->is_active) {
-               raw_spin_unlock_irq(&ctx->lock);
-               /*
-                * Reload the task pointer, it might have been changed by
-                * a concurrent perf_event_context_sched_out().
-                */
-               task = ctx->task;
-               goto retry;
-       }
-
-       /*
-        * Since the task isn't running, its safe to add the event, us holding
-        * the ctx->lock ensures the task won't get scheduled in.
-        */
-       add_event_to_ctx(event, ctx);
-       raw_spin_unlock_irq(&ctx->lock);
+       event_function_call(event, __perf_install_in_context,
+                           ___perf_install_in_context, event);
 }
 
 /*
@@ -2287,6 +2256,11 @@ unlock:
        return 0;
 }
 
+void ___perf_event_enable(void *info)
+{
+       __perf_event_mark_enabled((struct perf_event *)info);
+}
+
 /*
  * Enable a event.
  *
@@ -2299,58 +2273,26 @@ unlock:
 static void _perf_event_enable(struct perf_event *event)
 {
        struct perf_event_context *ctx = event->ctx;
-       struct task_struct *task = ctx->task;
 
-       if (!task) {
-               /*
-                * Enable the event on the cpu that it's on
-                */
-               cpu_function_call(event->cpu, __perf_event_enable, event);
+       raw_spin_lock_irq(&ctx->lock);
+       if (event->state >= PERF_EVENT_STATE_INACTIVE) {
+               raw_spin_unlock_irq(&ctx->lock);
                return;
        }
 
-       raw_spin_lock_irq(&ctx->lock);
-       if (event->state >= PERF_EVENT_STATE_INACTIVE)
-               goto out;
-
        /*
         * If the event is in error state, clear that first.
-        * That way, if we see the event in error state below, we
-        * know that it has gone back into error state, as distinct
-        * from the task having been scheduled away before the
-        * cross-call arrived.
+        *
+        * That way, if we see the event in error state below, we know that it
+        * has gone back into error state, as distinct from the task having
+        * been scheduled away before the cross-call arrived.
         */
        if (event->state == PERF_EVENT_STATE_ERROR)
                event->state = PERF_EVENT_STATE_OFF;
-
-retry:
-       if (!ctx->is_active) {
-               __perf_event_mark_enabled(event);
-               goto out;
-       }
-
        raw_spin_unlock_irq(&ctx->lock);
 
-       if (!task_function_call(task, __perf_event_enable, event))
-               return;
-
-       raw_spin_lock_irq(&ctx->lock);
-
-       /*
-        * If the context is active and the event is still off,
-        * we need to retry the cross-call.
-        */
-       if (ctx->is_active && event->state == PERF_EVENT_STATE_OFF) {
-               /*
-                * task could have been flipped by a concurrent
-                * perf_event_context_sched_out()
-                */
-               task = ctx->task;
-               goto retry;
-       }
-
-out:
-       raw_spin_unlock_irq(&ctx->lock);
+       event_function_call(event, __perf_event_enable,
+                           ___perf_event_enable, event);
 }
 
 /*
@@ -3154,15 +3096,16 @@ static int event_enable_on_exec(struct perf_event *event,
  * Enable all of a task's events that have been marked enable-on-exec.
  * This expects task == current.
  */
-static void perf_event_enable_on_exec(struct perf_event_context *ctx)
+static void perf_event_enable_on_exec(int ctxn)
 {
-       struct perf_event_context *clone_ctx = NULL;
+       struct perf_event_context *ctx, *clone_ctx = NULL;
        struct perf_event *event;
        unsigned long flags;
        int enabled = 0;
        int ret;
 
        local_irq_save(flags);
+       ctx = current->perf_event_ctxp[ctxn];
        if (!ctx || !ctx->nr_events)
                goto out;
 
@@ -3205,17 +3148,11 @@ out:
 
 void perf_event_exec(void)
 {
-       struct perf_event_context *ctx;
        int ctxn;
 
        rcu_read_lock();
-       for_each_task_context_nr(ctxn) {
-               ctx = current->perf_event_ctxp[ctxn];
-               if (!ctx)
-                       continue;
-
-               perf_event_enable_on_exec(ctx);
-       }
+       for_each_task_context_nr(ctxn)
+               perf_event_enable_on_exec(ctxn);
        rcu_read_unlock();
 }
 
@@ -4154,6 +4091,22 @@ struct period_event {
        u64 value;
 };
 
+static void ___perf_event_period(void *info)
+{
+       struct period_event *pe = info;
+       struct perf_event *event = pe->event;
+       u64 value = pe->value;
+
+       if (event->attr.freq) {
+               event->attr.sample_freq = value;
+       } else {
+               event->attr.sample_period = value;
+               event->hw.sample_period = value;
+       }
+
+       local64_set(&event->hw.period_left, 0);
+}
+
 static int __perf_event_period(void *info)
 {
        struct period_event *pe = info;
@@ -4190,8 +4143,6 @@ static int __perf_event_period(void *info)
 static int perf_event_period(struct perf_event *event, u64 __user *arg)
 {
        struct period_event pe = { .event = event, };
-       struct perf_event_context *ctx = event->ctx;
-       struct task_struct *task;
        u64 value;
 
        if (!is_sampling_event(event))
@@ -4206,34 +4157,10 @@ static int perf_event_period(struct perf_event *event, u64 __user *arg)
        if (event->attr.freq && value > sysctl_perf_event_sample_rate)
                return -EINVAL;
 
-       task = ctx->task;
        pe.value = value;
 
-       if (!task) {
-               cpu_function_call(event->cpu, __perf_event_period, &pe);
-               return 0;
-       }
-
-retry:
-       if (!task_function_call(task, __perf_event_period, &pe))
-               return 0;
-
-       raw_spin_lock_irq(&ctx->lock);
-       if (ctx->is_active) {
-               raw_spin_unlock_irq(&ctx->lock);
-               task = ctx->task;
-               goto retry;
-       }
-
-       if (event->attr.freq) {
-               event->attr.sample_freq = value;
-       } else {
-               event->attr.sample_period = value;
-               event->hw.sample_period = value;
-       }
-
-       local64_set(&event->hw.period_left, 0);
-       raw_spin_unlock_irq(&ctx->lock);
+       event_function_call(event, __perf_event_period,
+                           ___perf_event_period, &pe);
 
        return 0;
 }
@@ -6493,9 +6420,6 @@ struct swevent_htable {
 
        /* Recursion avoidance in each contexts */
        int                             recursion[PERF_NR_CONTEXTS];
-
-       /* Keeps track of cpu being initialized/exited */
-       bool                            online;
 };
 
 static DEFINE_PER_CPU(struct swevent_htable, swevent_htable);
@@ -6753,14 +6677,8 @@ static int perf_swevent_add(struct perf_event *event, int flags)
        hwc->state = !(flags & PERF_EF_START);
 
        head = find_swevent_head(swhash, event);
-       if (!head) {
-               /*
-                * We can race with cpu hotplug code. Do not
-                * WARN if the cpu just got unplugged.
-                */
-               WARN_ON_ONCE(swhash->online);
+       if (WARN_ON_ONCE(!head))
                return -EINVAL;
-       }
 
        hlist_add_head_rcu(&event->hlist_entry, head);
        perf_event_update_userpage(event);
@@ -6828,7 +6746,6 @@ static int swevent_hlist_get_cpu(struct perf_event *event, int cpu)
        int err = 0;
 
        mutex_lock(&swhash->hlist_mutex);
-
        if (!swevent_hlist_deref(swhash) && cpu_online(cpu)) {
                struct swevent_hlist *hlist;
 
@@ -9291,7 +9208,6 @@ static void perf_event_init_cpu(int cpu)
        struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
 
        mutex_lock(&swhash->hlist_mutex);
-       swhash->online = true;
        if (swhash->hlist_refcount > 0) {
                struct swevent_hlist *hlist;
 
@@ -9333,14 +9249,7 @@ static void perf_event_exit_cpu_context(int cpu)
 
 static void perf_event_exit_cpu(int cpu)
 {
-       struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
-
        perf_event_exit_cpu_context(cpu);
-
-       mutex_lock(&swhash->hlist_mutex);
-       swhash->online = false;
-       swevent_hlist_release(swhash);
-       mutex_unlock(&swhash->hlist_mutex);
 }
 #else
 static inline void perf_event_exit_cpu(int cpu) { }
index fce002ee3ddffbab7613d0f9ec390683901f3c67..291b08cc817bc8dd84320d03d4cf7b9517902ff9 100644 (file)
@@ -380,6 +380,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
 #endif
        tsk->splice_pipe = NULL;
        tsk->task_frag.page = NULL;
+       tsk->wake_q.next = NULL;
 
        account_kernel_stack(ti, 1);
 
@@ -1348,9 +1349,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        prev_cputime_init(&p->prev_cputime);
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
-       seqlock_init(&p->vtime_seqlock);
+       seqcount_init(&p->vtime_seqcount);
        p->vtime_snap = 0;
-       p->vtime_snap_whence = VTIME_SLEEPING;
+       p->vtime_snap_whence = VTIME_INACTIVE;
 #endif
 
 #if defined(SPLIT_RSS_COUNTING)
index 684d7549825a4300ced2002a3fbec0a5698a18d1..8a310e240cdaf60b27aaff432c5837bbd3e61d90 100644 (file)
@@ -725,9 +725,12 @@ static struct futex_pi_state * alloc_pi_state(void)
 }
 
 /*
+ * Drops a reference to the pi_state object and frees or caches it
+ * when the last reference is gone.
+ *
  * Must be called with the hb lock held.
  */
-static void free_pi_state(struct futex_pi_state *pi_state)
+static void put_pi_state(struct futex_pi_state *pi_state)
 {
        if (!pi_state)
                return;
@@ -1706,31 +1709,35 @@ retry_private:
                 * exist yet, look it up one more time to ensure we have a
                 * reference to it. If the lock was taken, ret contains the
                 * vpid of the top waiter task.
+                * If the lock was not taken, we have pi_state and an initial
+                * refcount on it. In case of an error we have nothing.
                 */
                if (ret > 0) {
                        WARN_ON(pi_state);
                        drop_count++;
                        task_count++;
                        /*
-                        * If we acquired the lock, then the user
-                        * space value of uaddr2 should be vpid. It
-                        * cannot be changed by the top waiter as it
-                        * is blocked on hb2 lock if it tries to do
-                        * so. If something fiddled with it behind our
-                        * back the pi state lookup might unearth
-                        * it. So we rather use the known value than
-                        * rereading and handing potential crap to
-                        * lookup_pi_state.
+                        * If we acquired the lock, then the user space value
+                        * of uaddr2 should be vpid. It cannot be changed by
+                        * the top waiter as it is blocked on hb2 lock if it
+                        * tries to do so. If something fiddled with it behind
+                        * our back the pi state lookup might unearth it. So
+                        * we rather use the known value than rereading and
+                        * handing potential crap to lookup_pi_state.
+                        *
+                        * If that call succeeds then we have pi_state and an
+                        * initial refcount on it.
                         */
                        ret = lookup_pi_state(ret, hb2, &key2, &pi_state);
                }
 
                switch (ret) {
                case 0:
+                       /* We hold a reference on the pi state. */
                        break;
+
+                       /* If the above failed, then pi_state is NULL */
                case -EFAULT:
-                       free_pi_state(pi_state);
-                       pi_state = NULL;
                        double_unlock_hb(hb1, hb2);
                        hb_waiters_dec(hb2);
                        put_futex_key(&key2);
@@ -1746,8 +1753,6 @@ retry_private:
                         *   exit to complete.
                         * - The user space value changed.
                         */
-                       free_pi_state(pi_state);
-                       pi_state = NULL;
                        double_unlock_hb(hb1, hb2);
                        hb_waiters_dec(hb2);
                        put_futex_key(&key2);
@@ -1801,30 +1806,58 @@ retry_private:
                 * of requeue_pi if we couldn't acquire the lock atomically.
                 */
                if (requeue_pi) {
-                       /* Prepare the waiter to take the rt_mutex. */
+                       /*
+                        * Prepare the waiter to take the rt_mutex. Take a
+                        * refcount on the pi_state and store the pointer in
+                        * the futex_q object of the waiter.
+                        */
                        atomic_inc(&pi_state->refcount);
                        this->pi_state = pi_state;
                        ret = rt_mutex_start_proxy_lock(&pi_state->pi_mutex,
                                                        this->rt_waiter,
                                                        this->task);
                        if (ret == 1) {
-                               /* We got the lock. */
+                               /*
+                                * We got the lock. We do neither drop the
+                                * refcount on pi_state nor clear
+                                * this->pi_state because the waiter needs the
+                                * pi_state for cleaning up the user space
+                                * value. It will drop the refcount after
+                                * doing so.
+                                */
                                requeue_pi_wake_futex(this, &key2, hb2);
                                drop_count++;
                                continue;
                        } else if (ret) {
-                               /* -EDEADLK */
+                               /*
+                                * rt_mutex_start_proxy_lock() detected a
+                                * potential deadlock when we tried to queue
+                                * that waiter. Drop the pi_state reference
+                                * which we took above and remove the pointer
+                                * to the state from the waiters futex_q
+                                * object.
+                                */
                                this->pi_state = NULL;
-                               free_pi_state(pi_state);
-                               goto out_unlock;
+                               put_pi_state(pi_state);
+                               /*
+                                * We stop queueing more waiters and let user
+                                * space deal with the mess.
+                                */
+                               break;
                        }
                }
                requeue_futex(this, hb1, hb2, &key2);
                drop_count++;
        }
 
+       /*
+        * We took an extra initial reference to the pi_state either
+        * in futex_proxy_trylock_atomic() or in lookup_pi_state(). We
+        * need to drop it here again.
+        */
+       put_pi_state(pi_state);
+
 out_unlock:
-       free_pi_state(pi_state);
        double_unlock_hb(hb1, hb2);
        wake_up_q(&wake_q);
        hb_waiters_dec(hb2);
@@ -1973,7 +2006,7 @@ static void unqueue_me_pi(struct futex_q *q)
        __unqueue_futex(q);
 
        BUG_ON(!q->pi_state);
-       free_pi_state(q->pi_state);
+       put_pi_state(q->pi_state);
        q->pi_state = NULL;
 
        spin_unlock(q->lock_ptr);
@@ -2755,6 +2788,11 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
                if (q.pi_state && (q.pi_state->owner != current)) {
                        spin_lock(q.lock_ptr);
                        ret = fixup_pi_state_owner(uaddr2, &q, current);
+                       /*
+                        * Drop the reference to the pi state which
+                        * the requeue_pi() code acquired for us.
+                        */
+                       put_pi_state(q.pi_state);
                        spin_unlock(q.lock_ptr);
                }
        } else {
@@ -3046,7 +3084,8 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
 
        if (op & FUTEX_CLOCK_REALTIME) {
                flags |= FLAGS_CLOCKRT;
-               if (cmd != FUTEX_WAIT_BITSET && cmd != FUTEX_WAIT_REQUEUE_PI)
+               if (cmd != FUTEX_WAIT && cmd != FUTEX_WAIT_BITSET && \
+                   cmd != FUTEX_WAIT_REQUEUE_PI)
                        return -ENOSYS;
        }
 
index 15206453b12aab09cf96dd09cc3fa2da92fd9c14..5797909f4e5b1b52cc0b2ecc61b9c393dc7a8bee 100644 (file)
@@ -338,7 +338,6 @@ void handle_nested_irq(unsigned int irq)
        raw_spin_lock_irq(&desc->lock);
 
        desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
-       kstat_incr_irqs_this_cpu(desc);
 
        action = desc->action;
        if (unlikely(!action || irqd_irq_disabled(&desc->irq_data))) {
@@ -346,6 +345,7 @@ void handle_nested_irq(unsigned int irq)
                goto out_unlock;
        }
 
+       kstat_incr_irqs_this_cpu(desc);
        irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS);
        raw_spin_unlock_irq(&desc->lock);
 
@@ -412,13 +412,13 @@ void handle_simple_irq(struct irq_desc *desc)
                goto out_unlock;
 
        desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
-       kstat_incr_irqs_this_cpu(desc);
 
        if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {
                desc->istate |= IRQS_PENDING;
                goto out_unlock;
        }
 
+       kstat_incr_irqs_this_cpu(desc);
        handle_irq_event(desc);
 
 out_unlock:
@@ -462,7 +462,6 @@ void handle_level_irq(struct irq_desc *desc)
                goto out_unlock;
 
        desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
-       kstat_incr_irqs_this_cpu(desc);
 
        /*
         * If its disabled or no action available
@@ -473,6 +472,7 @@ void handle_level_irq(struct irq_desc *desc)
                goto out_unlock;
        }
 
+       kstat_incr_irqs_this_cpu(desc);
        handle_irq_event(desc);
 
        cond_unmask_irq(desc);
@@ -532,7 +532,6 @@ void handle_fasteoi_irq(struct irq_desc *desc)
                goto out;
 
        desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
-       kstat_incr_irqs_this_cpu(desc);
 
        /*
         * If its disabled or no action available
@@ -544,6 +543,7 @@ void handle_fasteoi_irq(struct irq_desc *desc)
                goto out;
        }
 
+       kstat_incr_irqs_this_cpu(desc);
        if (desc->istate & IRQS_ONESHOT)
                mask_irq(desc);
 
@@ -950,6 +950,7 @@ void irq_chip_ack_parent(struct irq_data *data)
        data = data->parent_data;
        data->chip->irq_ack(data);
 }
+EXPORT_SYMBOL_GPL(irq_chip_ack_parent);
 
 /**
  * irq_chip_mask_parent - Mask the parent interrupt
index 239e2ae2c947df31d26def1d26da430d144165e8..0409da0bcc3358b6b49ba6a79a339cf2176897ff 100644 (file)
@@ -159,6 +159,7 @@ static struct irq_desc *alloc_desc(int irq, int node, struct module *owner)
 
        raw_spin_lock_init(&desc->lock);
        lockdep_set_class(&desc->lock, &irq_desc_lock_class);
+       init_rcu_head(&desc->rcu);
 
        desc_set_defaults(irq, desc, node, owner);
 
@@ -171,6 +172,15 @@ err_desc:
        return NULL;
 }
 
+static void delayed_free_desc(struct rcu_head *rhp)
+{
+       struct irq_desc *desc = container_of(rhp, struct irq_desc, rcu);
+
+       free_masks(desc);
+       free_percpu(desc->kstat_irqs);
+       kfree(desc);
+}
+
 static void free_desc(unsigned int irq)
 {
        struct irq_desc *desc = irq_to_desc(irq);
@@ -187,9 +197,12 @@ static void free_desc(unsigned int irq)
        delete_irq_desc(irq);
        mutex_unlock(&sparse_irq_lock);
 
-       free_masks(desc);
-       free_percpu(desc->kstat_irqs);
-       kfree(desc);
+       /*
+        * We free the descriptor, masks and stat fields via RCU. That
+        * allows demultiplex interrupts to do rcu based management of
+        * the child interrupts.
+        */
+       call_rcu(&desc->rcu, delayed_free_desc);
 }
 
 static int alloc_descs(unsigned int start, unsigned int cnt, int node,
index 22aa9612ef7ca98cd8796188a7021810cc86d05a..8cf95de1ab3fe802cbab478c0850f10bc1e27d37 100644 (file)
@@ -60,6 +60,7 @@ struct fwnode_handle *irq_domain_alloc_fwnode(void *data)
        fwid->fwnode.type = FWNODE_IRQCHIP;
        return &fwid->fwnode;
 }
+EXPORT_SYMBOL_GPL(irq_domain_alloc_fwnode);
 
 /**
  * irq_domain_free_fwnode - Free a non-OF-backed fwnode_handle
@@ -70,13 +71,14 @@ void irq_domain_free_fwnode(struct fwnode_handle *fwnode)
 {
        struct irqchip_fwid *fwid;
 
-       if (WARN_ON(fwnode->type != FWNODE_IRQCHIP))
+       if (WARN_ON(!is_fwnode_irqchip(fwnode)))
                return;
 
        fwid = container_of(fwnode, struct irqchip_fwid, fwnode);
        kfree(fwid->name);
        kfree(fwid);
 }
+EXPORT_SYMBOL_GPL(irq_domain_free_fwnode);
 
 /**
  * __irq_domain_add() - Allocate a new irq_domain data structure
@@ -1013,6 +1015,7 @@ struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain,
 
        return NULL;
 }
+EXPORT_SYMBOL_GPL(irq_domain_get_irq_data);
 
 /**
  * irq_domain_set_hwirq_and_chip - Set hwirq and irqchip of @virq at @domain
@@ -1125,9 +1128,9 @@ static void irq_domain_free_irqs_recursive(struct irq_domain *domain,
        }
 }
 
-static int irq_domain_alloc_irqs_recursive(struct irq_domain *domain,
-                                          unsigned int irq_base,
-                                          unsigned int nr_irqs, void *arg)
+int irq_domain_alloc_irqs_recursive(struct irq_domain *domain,
+                                   unsigned int irq_base,
+                                   unsigned int nr_irqs, void *arg)
 {
        int ret = 0;
        struct irq_domain *parent = domain->parent;
@@ -1343,6 +1346,7 @@ struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain,
 
        return (irq_data && irq_data->domain == domain) ? irq_data : NULL;
 }
+EXPORT_SYMBOL_GPL(irq_domain_get_irq_data);
 
 /**
  * irq_domain_set_info - Set the complete data for a @virq in @domain
index 0eebaeef317bc990e3ee1b1bd1719b9e89211685..841187239adc8e3bb0f72fb4ab0ca6a7fec2f618 100644 (file)
@@ -1434,6 +1434,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
        if (!desc)
                return NULL;
 
+       chip_bus_lock(desc);
        raw_spin_lock_irqsave(&desc->lock, flags);
 
        /*
@@ -1447,7 +1448,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
                if (!action) {
                        WARN(1, "Trying to free already-free IRQ %d\n", irq);
                        raw_spin_unlock_irqrestore(&desc->lock, flags);
-
+                       chip_bus_sync_unlock(desc);
                        return NULL;
                }
 
@@ -1475,6 +1476,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
 #endif
 
        raw_spin_unlock_irqrestore(&desc->lock, flags);
+       chip_bus_sync_unlock(desc);
 
        unregister_handler_proc(irq, action);
 
@@ -1553,9 +1555,7 @@ void free_irq(unsigned int irq, void *dev_id)
                desc->affinity_notify = NULL;
 #endif
 
-       chip_bus_lock(desc);
        kfree(__free_irq(irq, dev_id));
-       chip_bus_sync_unlock(desc);
 }
 EXPORT_SYMBOL(free_irq);
 
@@ -1743,6 +1743,31 @@ out:
 }
 EXPORT_SYMBOL_GPL(enable_percpu_irq);
 
+/**
+ * irq_percpu_is_enabled - Check whether the per cpu irq is enabled
+ * @irq:       Linux irq number to check for
+ *
+ * Must be called from a non migratable context. Returns the enable
+ * state of a per cpu interrupt on the current cpu.
+ */
+bool irq_percpu_is_enabled(unsigned int irq)
+{
+       unsigned int cpu = smp_processor_id();
+       struct irq_desc *desc;
+       unsigned long flags;
+       bool is_enabled;
+
+       desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_PERCPU);
+       if (!desc)
+               return false;
+
+       is_enabled = cpumask_test_cpu(cpu, desc->percpu_enabled);
+       irq_put_desc_unlock(desc, flags);
+
+       return is_enabled;
+}
+EXPORT_SYMBOL_GPL(irq_percpu_is_enabled);
+
 void disable_percpu_irq(unsigned int irq)
 {
        unsigned int cpu = smp_processor_id();
index 6b0c0b74a2a1a88c0d3f81519fea7c520b290967..15b249e7c67321007305d64bfcd2c69fd6206ddb 100644 (file)
@@ -252,6 +252,60 @@ struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode,
                                           &msi_domain_ops, info);
 }
 
+int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev,
+                           int nvec, msi_alloc_info_t *arg)
+{
+       struct msi_domain_info *info = domain->host_data;
+       struct msi_domain_ops *ops = info->ops;
+       int ret;
+
+       ret = ops->msi_check(domain, info, dev);
+       if (ret == 0)
+               ret = ops->msi_prepare(domain, dev, nvec, arg);
+
+       return ret;
+}
+
+int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev,
+                            int virq, int nvec, msi_alloc_info_t *arg)
+{
+       struct msi_domain_info *info = domain->host_data;
+       struct msi_domain_ops *ops = info->ops;
+       struct msi_desc *desc;
+       int ret = 0;
+
+       for_each_msi_entry(desc, dev) {
+               /* Don't even try the multi-MSI brain damage. */
+               if (WARN_ON(!desc->irq || desc->nvec_used != 1)) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (!(desc->irq >= virq && desc->irq < (virq + nvec)))
+                       continue;
+
+               ops->set_desc(arg, desc);
+               /* Assumes the domain mutex is held! */
+               ret = irq_domain_alloc_irqs_recursive(domain, virq, 1, arg);
+               if (ret)
+                       break;
+
+               irq_set_msi_desc_off(virq, 0, desc);
+       }
+
+       if (ret) {
+               /* Mop up the damage */
+               for_each_msi_entry(desc, dev) {
+                       if (!(desc->irq >= virq && desc->irq < (virq + nvec)))
+                               continue;
+
+                       irq_domain_free_irqs_common(domain, desc->irq, 1);
+               }
+       }
+
+       return ret;
+}
+
 /**
  * msi_domain_alloc_irqs - Allocate interrupts from a MSI interrupt domain
  * @domain:    The domain to allocate from
@@ -270,9 +324,7 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
        struct msi_desc *desc;
        int i, ret, virq = -1;
 
-       ret = ops->msi_check(domain, info, dev);
-       if (ret == 0)
-               ret = ops->msi_prepare(domain, dev, nvec, &arg);
+       ret = msi_domain_prepare_irqs(domain, dev, nvec, &arg);
        if (ret)
                return ret;
 
index 11b64a63c0f88817b80a2c35117d70bcfe446fa1..c823f3001e121d0c51352befe941271c803cb108 100644 (file)
@@ -853,7 +853,12 @@ struct kimage *kexec_image;
 struct kimage *kexec_crash_image;
 int kexec_load_disabled;
 
-void crash_kexec(struct pt_regs *regs)
+/*
+ * No panic_cpu check version of crash_kexec().  This function is called
+ * only when panic_cpu holds the current CPU number; this is the only CPU
+ * which processes crash_kexec routines.
+ */
+void __crash_kexec(struct pt_regs *regs)
 {
        /* Take the kexec_mutex here to prevent sys_kexec_load
         * running on one cpu from replacing the crash kernel
@@ -876,6 +881,29 @@ void crash_kexec(struct pt_regs *regs)
        }
 }
 
+void crash_kexec(struct pt_regs *regs)
+{
+       int old_cpu, this_cpu;
+
+       /*
+        * Only one CPU is allowed to execute the crash_kexec() code as with
+        * panic().  Otherwise parallel calls of panic() and crash_kexec()
+        * may stop each other.  To exclude them, we use panic_cpu here too.
+        */
+       this_cpu = raw_smp_processor_id();
+       old_cpu = atomic_cmpxchg(&panic_cpu, PANIC_CPU_INVALID, this_cpu);
+       if (old_cpu == PANIC_CPU_INVALID) {
+               /* This is the 1st CPU which comes here, so go ahead. */
+               __crash_kexec(regs);
+
+               /*
+                * Reset panic_cpu to allow another panic()/crash_kexec()
+                * call.
+                */
+               atomic_set(&panic_cpu, PANIC_CPU_INVALID);
+       }
+}
+
 size_t crash_get_memory_size(void)
 {
        size_t size = 0;
index e83b264640615c47c31cce539f31014dc11b0776..152da4a48867c4e32df888aac674fd7a42d49799 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/capability.h>
 #include <linux/compiler.h>
 
-#include <linux/rcupdate.h>    /* rcu_expedited */
+#include <linux/rcupdate.h>    /* rcu_expedited and rcu_normal */
 
 #define KERNEL_ATTR_RO(_name) \
 static struct kobj_attribute _name##_attr = __ATTR_RO(_name)
@@ -144,11 +144,12 @@ static ssize_t fscaps_show(struct kobject *kobj,
 }
 KERNEL_ATTR_RO(fscaps);
 
+#ifndef CONFIG_TINY_RCU
 int rcu_expedited;
 static ssize_t rcu_expedited_show(struct kobject *kobj,
                                  struct kobj_attribute *attr, char *buf)
 {
-       return sprintf(buf, "%d\n", rcu_expedited);
+       return sprintf(buf, "%d\n", READ_ONCE(rcu_expedited));
 }
 static ssize_t rcu_expedited_store(struct kobject *kobj,
                                   struct kobj_attribute *attr,
@@ -161,6 +162,24 @@ static ssize_t rcu_expedited_store(struct kobject *kobj,
 }
 KERNEL_ATTR_RW(rcu_expedited);
 
+int rcu_normal;
+static ssize_t rcu_normal_show(struct kobject *kobj,
+                              struct kobj_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", READ_ONCE(rcu_normal));
+}
+static ssize_t rcu_normal_store(struct kobject *kobj,
+                               struct kobj_attribute *attr,
+                               const char *buf, size_t count)
+{
+       if (kstrtoint(buf, 0, &rcu_normal))
+               return -EINVAL;
+
+       return count;
+}
+KERNEL_ATTR_RW(rcu_normal);
+#endif /* #ifndef CONFIG_TINY_RCU */
+
 /*
  * Make /sys/kernel/notes give the raw contents of our kernel .notes section.
  */
@@ -202,7 +221,10 @@ static struct attribute * kernel_attrs[] = {
        &kexec_crash_size_attr.attr,
        &vmcoreinfo_attr.attr,
 #endif
+#ifndef CONFIG_TINY_RCU
        &rcu_expedited_attr.attr,
+       &rcu_normal_attr.attr,
+#endif
        NULL
 };
 
index 87e9ce6a63c5d0e78a17977e2e9271ffaf0bb946..393d1874b9e0c81d44ef9d0447ded22a03bccd81 100644 (file)
@@ -14,8 +14,9 @@
  * (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
  * (C) Copyright 2013-2014 Red Hat, Inc.
  * (C) Copyright 2015 Intel Corp.
+ * (C) Copyright 2015 Hewlett-Packard Enterprise Development LP
  *
- * Authors: Waiman Long <waiman.long@hp.com>
+ * Authors: Waiman Long <waiman.long@hpe.com>
  *          Peter Zijlstra <peterz@infradead.org>
  */
 
@@ -176,7 +177,12 @@ static __always_inline u32 xchg_tail(struct qspinlock *lock, u32 tail)
 {
        struct __qspinlock *l = (void *)lock;
 
-       return (u32)xchg(&l->tail, tail >> _Q_TAIL_OFFSET) << _Q_TAIL_OFFSET;
+       /*
+        * Use release semantics to make sure that the MCS node is properly
+        * initialized before changing the tail code.
+        */
+       return (u32)xchg_release(&l->tail,
+                                tail >> _Q_TAIL_OFFSET) << _Q_TAIL_OFFSET;
 }
 
 #else /* _Q_PENDING_BITS == 8 */
@@ -208,7 +214,11 @@ static __always_inline u32 xchg_tail(struct qspinlock *lock, u32 tail)
 
        for (;;) {
                new = (val & _Q_LOCKED_PENDING_MASK) | tail;
-               old = atomic_cmpxchg(&lock->val, val, new);
+               /*
+                * Use release semantics to make sure that the MCS node is
+                * properly initialized before changing the tail code.
+                */
+               old = atomic_cmpxchg_release(&lock->val, val, new);
                if (old == val)
                        break;
 
@@ -238,18 +248,20 @@ static __always_inline void set_locked(struct qspinlock *lock)
  */
 
 static __always_inline void __pv_init_node(struct mcs_spinlock *node) { }
-static __always_inline void __pv_wait_node(struct mcs_spinlock *node) { }
+static __always_inline void __pv_wait_node(struct mcs_spinlock *node,
+                                          struct mcs_spinlock *prev) { }
 static __always_inline void __pv_kick_node(struct qspinlock *lock,
                                           struct mcs_spinlock *node) { }
-static __always_inline void __pv_wait_head(struct qspinlock *lock,
-                                          struct mcs_spinlock *node) { }
+static __always_inline u32  __pv_wait_head_or_lock(struct qspinlock *lock,
+                                                  struct mcs_spinlock *node)
+                                                  { return 0; }
 
 #define pv_enabled()           false
 
 #define pv_init_node           __pv_init_node
 #define pv_wait_node           __pv_wait_node
 #define pv_kick_node           __pv_kick_node
-#define pv_wait_head           __pv_wait_head
+#define pv_wait_head_or_lock   __pv_wait_head_or_lock
 
 #ifdef CONFIG_PARAVIRT_SPINLOCKS
 #define queued_spin_lock_slowpath      native_queued_spin_lock_slowpath
@@ -319,7 +331,11 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)
                if (val == new)
                        new |= _Q_PENDING_VAL;
 
-               old = atomic_cmpxchg(&lock->val, val, new);
+               /*
+                * Acquire semantic is required here as the function may
+                * return immediately if the lock was free.
+                */
+               old = atomic_cmpxchg_acquire(&lock->val, val, new);
                if (old == val)
                        break;
 
@@ -382,6 +398,7 @@ queue:
         * p,*,* -> n,*,*
         */
        old = xchg_tail(lock, tail);
+       next = NULL;
 
        /*
         * if there was a previous node; link it and wait until reaching the
@@ -391,8 +408,18 @@ queue:
                prev = decode_tail(old);
                WRITE_ONCE(prev->next, node);
 
-               pv_wait_node(node);
+               pv_wait_node(node, prev);
                arch_mcs_spin_lock_contended(&node->locked);
+
+               /*
+                * While waiting for the MCS lock, the next pointer may have
+                * been set by another lock waiter. We optimistically load
+                * the next pointer & prefetch the cacheline for writing
+                * to reduce latency in the upcoming MCS unlock operation.
+                */
+               next = READ_ONCE(node->next);
+               if (next)
+                       prefetchw(next);
        }
 
        /*
@@ -406,11 +433,22 @@ queue:
         * sequentiality; this is because the set_locked() function below
         * does not imply a full barrier.
         *
+        * The PV pv_wait_head_or_lock function, if active, will acquire
+        * the lock and return a non-zero value. So we have to skip the
+        * smp_load_acquire() call. As the next PV queue head hasn't been
+        * designated yet, there is no way for the locked value to become
+        * _Q_SLOW_VAL. So both the set_locked() and the
+        * atomic_cmpxchg_relaxed() calls will be safe.
+        *
+        * If PV isn't active, 0 will be returned instead.
+        *
         */
-       pv_wait_head(lock, node);
-       while ((val = smp_load_acquire(&lock->val.counter)) & _Q_LOCKED_PENDING_MASK)
-               cpu_relax();
+       if ((val = pv_wait_head_or_lock(lock, node)))
+               goto locked;
 
+       smp_cond_acquire(!((val = atomic_read(&lock->val)) & _Q_LOCKED_PENDING_MASK));
+
+locked:
        /*
         * claim the lock:
         *
@@ -422,11 +460,17 @@ queue:
         * to grab the lock.
         */
        for (;;) {
-               if (val != tail) {
+               /* In the PV case we might already have _Q_LOCKED_VAL set */
+               if ((val & _Q_TAIL_MASK) != tail) {
                        set_locked(lock);
                        break;
                }
-               old = atomic_cmpxchg(&lock->val, val, _Q_LOCKED_VAL);
+               /*
+                * The smp_load_acquire() call above has provided the necessary
+                * acquire semantics required for locking. At most two
+                * iterations of this loop may be ran.
+                */
+               old = atomic_cmpxchg_relaxed(&lock->val, val, _Q_LOCKED_VAL);
                if (old == val)
                        goto release;   /* No contention */
 
@@ -434,10 +478,12 @@ queue:
        }
 
        /*
-        * contended path; wait for next, release.
+        * contended path; wait for next if not observed yet, release.
         */
-       while (!(next = READ_ONCE(node->next)))
-               cpu_relax();
+       if (!next) {
+               while (!(next = READ_ONCE(node->next)))
+                       cpu_relax();
+       }
 
        arch_mcs_spin_unlock_contended(&next->locked);
        pv_kick_node(lock, next);
@@ -462,7 +508,7 @@ EXPORT_SYMBOL(queued_spin_lock_slowpath);
 #undef pv_init_node
 #undef pv_wait_node
 #undef pv_kick_node
-#undef pv_wait_head
+#undef pv_wait_head_or_lock
 
 #undef  queued_spin_lock_slowpath
 #define queued_spin_lock_slowpath      __pv_queued_spin_lock_slowpath
index f0450ff4829b6c1308d4768b2ae3a7c575b1cf51..87bb235c3448054d63923d0f9549cbc7718a49ca 100644 (file)
 
 #define _Q_SLOW_VAL    (3U << _Q_LOCKED_OFFSET)
 
+/*
+ * Queue Node Adaptive Spinning
+ *
+ * A queue node vCPU will stop spinning if the vCPU in the previous node is
+ * not running. The one lock stealing attempt allowed at slowpath entry
+ * mitigates the slight slowdown for non-overcommitted guest with this
+ * aggressive wait-early mechanism.
+ *
+ * The status of the previous node will be checked at fixed interval
+ * controlled by PV_PREV_CHECK_MASK. This is to ensure that we won't
+ * pound on the cacheline of the previous node too heavily.
+ */
+#define PV_PREV_CHECK_MASK     0xff
+
 /*
  * Queue node uses: vcpu_running & vcpu_halted.
  * Queue head uses: vcpu_running & vcpu_hashed.
@@ -40,6 +54,94 @@ struct pv_node {
        u8                      state;
 };
 
+/*
+ * By replacing the regular queued_spin_trylock() with the function below,
+ * it will be called once when a lock waiter enter the PV slowpath before
+ * being queued. By allowing one lock stealing attempt here when the pending
+ * bit is off, it helps to reduce the performance impact of lock waiter
+ * preemption without the drawback of lock starvation.
+ */
+#define queued_spin_trylock(l) pv_queued_spin_steal_lock(l)
+static inline bool pv_queued_spin_steal_lock(struct qspinlock *lock)
+{
+       struct __qspinlock *l = (void *)lock;
+
+       return !(atomic_read(&lock->val) & _Q_LOCKED_PENDING_MASK) &&
+               (cmpxchg(&l->locked, 0, _Q_LOCKED_VAL) == 0);
+}
+
+/*
+ * The pending bit is used by the queue head vCPU to indicate that it
+ * is actively spinning on the lock and no lock stealing is allowed.
+ */
+#if _Q_PENDING_BITS == 8
+static __always_inline void set_pending(struct qspinlock *lock)
+{
+       struct __qspinlock *l = (void *)lock;
+
+       WRITE_ONCE(l->pending, 1);
+}
+
+static __always_inline void clear_pending(struct qspinlock *lock)
+{
+       struct __qspinlock *l = (void *)lock;
+
+       WRITE_ONCE(l->pending, 0);
+}
+
+/*
+ * The pending bit check in pv_queued_spin_steal_lock() isn't a memory
+ * barrier. Therefore, an atomic cmpxchg() is used to acquire the lock
+ * just to be sure that it will get it.
+ */
+static __always_inline int trylock_clear_pending(struct qspinlock *lock)
+{
+       struct __qspinlock *l = (void *)lock;
+
+       return !READ_ONCE(l->locked) &&
+              (cmpxchg(&l->locked_pending, _Q_PENDING_VAL, _Q_LOCKED_VAL)
+                       == _Q_PENDING_VAL);
+}
+#else /* _Q_PENDING_BITS == 8 */
+static __always_inline void set_pending(struct qspinlock *lock)
+{
+       atomic_set_mask(_Q_PENDING_VAL, &lock->val);
+}
+
+static __always_inline void clear_pending(struct qspinlock *lock)
+{
+       atomic_clear_mask(_Q_PENDING_VAL, &lock->val);
+}
+
+static __always_inline int trylock_clear_pending(struct qspinlock *lock)
+{
+       int val = atomic_read(&lock->val);
+
+       for (;;) {
+               int old, new;
+
+               if (val  & _Q_LOCKED_MASK)
+                       break;
+
+               /*
+                * Try to clear pending bit & set locked bit
+                */
+               old = val;
+               new = (val & ~_Q_PENDING_MASK) | _Q_LOCKED_VAL;
+               val = atomic_cmpxchg(&lock->val, old, new);
+
+               if (val == old)
+                       return 1;
+       }
+       return 0;
+}
+#endif /* _Q_PENDING_BITS == 8 */
+
+/*
+ * Include queued spinlock statistics code
+ */
+#include "qspinlock_stat.h"
+
 /*
  * Lock and MCS node addresses hash table for fast lookup
  *
@@ -100,10 +202,13 @@ static struct qspinlock **pv_hash(struct qspinlock *lock, struct pv_node *node)
 {
        unsigned long offset, hash = hash_ptr(lock, pv_lock_hash_bits);
        struct pv_hash_entry *he;
+       int hopcnt = 0;
 
        for_each_hash_entry(he, offset, hash) {
+               hopcnt++;
                if (!cmpxchg(&he->lock, NULL, lock)) {
                        WRITE_ONCE(he->node, node);
+                       qstat_hop(hopcnt);
                        return &he->lock;
                }
        }
@@ -143,6 +248,20 @@ static struct pv_node *pv_unhash(struct qspinlock *lock)
        BUG();
 }
 
+/*
+ * Return true if when it is time to check the previous node which is not
+ * in a running state.
+ */
+static inline bool
+pv_wait_early(struct pv_node *prev, int loop)
+{
+
+       if ((loop & PV_PREV_CHECK_MASK) != 0)
+               return false;
+
+       return READ_ONCE(prev->state) != vcpu_running;
+}
+
 /*
  * Initialize the PV part of the mcs_spinlock node.
  */
@@ -161,15 +280,23 @@ static void pv_init_node(struct mcs_spinlock *node)
  * pv_kick_node() is used to set _Q_SLOW_VAL and fill in hash table on its
  * behalf.
  */
-static void pv_wait_node(struct mcs_spinlock *node)
+static void pv_wait_node(struct mcs_spinlock *node, struct mcs_spinlock *prev)
 {
        struct pv_node *pn = (struct pv_node *)node;
+       struct pv_node *pp = (struct pv_node *)prev;
+       int waitcnt = 0;
        int loop;
+       bool wait_early;
 
-       for (;;) {
-               for (loop = SPIN_THRESHOLD; loop; loop--) {
+       /* waitcnt processing will be compiled out if !QUEUED_LOCK_STAT */
+       for (;; waitcnt++) {
+               for (wait_early = false, loop = SPIN_THRESHOLD; loop; loop--) {
                        if (READ_ONCE(node->locked))
                                return;
+                       if (pv_wait_early(pp, loop)) {
+                               wait_early = true;
+                               break;
+                       }
                        cpu_relax();
                }
 
@@ -184,12 +311,17 @@ static void pv_wait_node(struct mcs_spinlock *node)
                 */
                smp_store_mb(pn->state, vcpu_halted);
 
-               if (!READ_ONCE(node->locked))
+               if (!READ_ONCE(node->locked)) {
+                       qstat_inc(qstat_pv_wait_node, true);
+                       qstat_inc(qstat_pv_wait_again, waitcnt);
+                       qstat_inc(qstat_pv_wait_early, wait_early);
                        pv_wait(&pn->state, vcpu_halted);
+               }
 
                /*
-                * If pv_kick_node() changed us to vcpu_hashed, retain that value
-                * so that pv_wait_head() knows to not also try to hash this lock.
+                * If pv_kick_node() changed us to vcpu_hashed, retain that
+                * value so that pv_wait_head_or_lock() knows to not also try
+                * to hash this lock.
                 */
                cmpxchg(&pn->state, vcpu_halted, vcpu_running);
 
@@ -200,6 +332,7 @@ static void pv_wait_node(struct mcs_spinlock *node)
                 * So it is better to spin for a while in the hope that the
                 * MCS lock will be released soon.
                 */
+               qstat_inc(qstat_pv_spurious_wakeup, !READ_ONCE(node->locked));
        }
 
        /*
@@ -212,8 +345,9 @@ static void pv_wait_node(struct mcs_spinlock *node)
 /*
  * Called after setting next->locked = 1 when we're the lock owner.
  *
- * Instead of waking the waiters stuck in pv_wait_node() advance their state such
- * that they're waiting in pv_wait_head(), this avoids a wake/sleep cycle.
+ * Instead of waking the waiters stuck in pv_wait_node() advance their state
+ * such that they're waiting in pv_wait_head_or_lock(), this avoids a
+ * wake/sleep cycle.
  */
 static void pv_kick_node(struct qspinlock *lock, struct mcs_spinlock *node)
 {
@@ -242,14 +376,19 @@ static void pv_kick_node(struct qspinlock *lock, struct mcs_spinlock *node)
 }
 
 /*
- * Wait for l->locked to become clear; halt the vcpu after a short spin.
+ * Wait for l->locked to become clear and acquire the lock;
+ * halt the vcpu after a short spin.
  * __pv_queued_spin_unlock() will wake us.
+ *
+ * The current value of the lock will be returned for additional processing.
  */
-static void pv_wait_head(struct qspinlock *lock, struct mcs_spinlock *node)
+static u32
+pv_wait_head_or_lock(struct qspinlock *lock, struct mcs_spinlock *node)
 {
        struct pv_node *pn = (struct pv_node *)node;
        struct __qspinlock *l = (void *)lock;
        struct qspinlock **lp = NULL;
+       int waitcnt = 0;
        int loop;
 
        /*
@@ -259,12 +398,25 @@ static void pv_wait_head(struct qspinlock *lock, struct mcs_spinlock *node)
        if (READ_ONCE(pn->state) == vcpu_hashed)
                lp = (struct qspinlock **)1;
 
-       for (;;) {
+       for (;; waitcnt++) {
+               /*
+                * Set correct vCPU state to be used by queue node wait-early
+                * mechanism.
+                */
+               WRITE_ONCE(pn->state, vcpu_running);
+
+               /*
+                * Set the pending bit in the active lock spinning loop to
+                * disable lock stealing before attempting to acquire the lock.
+                */
+               set_pending(lock);
                for (loop = SPIN_THRESHOLD; loop; loop--) {
-                       if (!READ_ONCE(l->locked))
-                               return;
+                       if (trylock_clear_pending(lock))
+                               goto gotlock;
                        cpu_relax();
                }
+               clear_pending(lock);
+
 
                if (!lp) { /* ONCE */
                        lp = pv_hash(lock, pn);
@@ -280,51 +432,50 @@ static void pv_wait_head(struct qspinlock *lock, struct mcs_spinlock *node)
                         *
                         * Matches the smp_rmb() in __pv_queued_spin_unlock().
                         */
-                       if (!cmpxchg(&l->locked, _Q_LOCKED_VAL, _Q_SLOW_VAL)) {
+                       if (xchg(&l->locked, _Q_SLOW_VAL) == 0) {
                                /*
-                                * The lock is free and _Q_SLOW_VAL has never
-                                * been set. Therefore we need to unhash before
-                                * getting the lock.
+                                * The lock was free and now we own the lock.
+                                * Change the lock value back to _Q_LOCKED_VAL
+                                * and unhash the table.
                                 */
+                               WRITE_ONCE(l->locked, _Q_LOCKED_VAL);
                                WRITE_ONCE(*lp, NULL);
-                               return;
+                               goto gotlock;
                        }
                }
+               WRITE_ONCE(pn->state, vcpu_halted);
+               qstat_inc(qstat_pv_wait_head, true);
+               qstat_inc(qstat_pv_wait_again, waitcnt);
                pv_wait(&l->locked, _Q_SLOW_VAL);
 
                /*
                 * The unlocker should have freed the lock before kicking the
                 * CPU. So if the lock is still not free, it is a spurious
-                * wakeup and so the vCPU should wait again after spinning for
-                * a while.
+                * wakeup or another vCPU has stolen the lock. The current
+                * vCPU should spin again.
                 */
+               qstat_inc(qstat_pv_spurious_wakeup, READ_ONCE(l->locked));
        }
 
        /*
-        * Lock is unlocked now; the caller will acquire it without waiting.
-        * As with pv_wait_node() we rely on the caller to do a load-acquire
-        * for us.
+        * The cmpxchg() or xchg() call before coming here provides the
+        * acquire semantics for locking. The dummy ORing of _Q_LOCKED_VAL
+        * here is to indicate to the compiler that the value will always
+        * be nozero to enable better code optimization.
         */
+gotlock:
+       return (u32)(atomic_read(&lock->val) | _Q_LOCKED_VAL);
 }
 
 /*
- * PV version of the unlock function to be used in stead of
- * queued_spin_unlock().
+ * PV versions of the unlock fastpath and slowpath functions to be used
+ * instead of queued_spin_unlock().
  */
-__visible void __pv_queued_spin_unlock(struct qspinlock *lock)
+__visible void
+__pv_queued_spin_unlock_slowpath(struct qspinlock *lock, u8 locked)
 {
        struct __qspinlock *l = (void *)lock;
        struct pv_node *node;
-       u8 locked;
-
-       /*
-        * We must not unlock if SLOW, because in that case we must first
-        * unhash. Otherwise it would be possible to have multiple @lock
-        * entries, which would be BAD.
-        */
-       locked = cmpxchg(&l->locked, _Q_LOCKED_VAL, 0);
-       if (likely(locked == _Q_LOCKED_VAL))
-               return;
 
        if (unlikely(locked != _Q_SLOW_VAL)) {
                WARN(!debug_locks_silent,
@@ -338,7 +489,7 @@ __visible void __pv_queued_spin_unlock(struct qspinlock *lock)
         * so we need a barrier to order the read of the node data in
         * pv_unhash *after* we've read the lock being _Q_SLOW_VAL.
         *
-        * Matches the cmpxchg() in pv_wait_head() setting _Q_SLOW_VAL.
+        * Matches the cmpxchg() in pv_wait_head_or_lock() setting _Q_SLOW_VAL.
         */
        smp_rmb();
 
@@ -361,14 +512,35 @@ __visible void __pv_queued_spin_unlock(struct qspinlock *lock)
         * vCPU is harmless other than the additional latency in completing
         * the unlock.
         */
+       qstat_inc(qstat_pv_kick_unlock, true);
        pv_kick(node->cpu);
 }
+
 /*
  * Include the architecture specific callee-save thunk of the
  * __pv_queued_spin_unlock(). This thunk is put together with
- * __pv_queued_spin_unlock() near the top of the file to make sure
- * that the callee-save thunk and the real unlock function are close
- * to each other sharing consecutive instruction cachelines.
+ * __pv_queued_spin_unlock() to make the callee-save thunk and the real unlock
+ * function close to each other sharing consecutive instruction cachelines.
+ * Alternatively, architecture specific version of __pv_queued_spin_unlock()
+ * can be defined.
  */
 #include <asm/qspinlock_paravirt.h>
 
+#ifndef __pv_queued_spin_unlock
+__visible void __pv_queued_spin_unlock(struct qspinlock *lock)
+{
+       struct __qspinlock *l = (void *)lock;
+       u8 locked;
+
+       /*
+        * We must not unlock if SLOW, because in that case we must first
+        * unhash. Otherwise it would be possible to have multiple @lock
+        * entries, which would be BAD.
+        */
+       locked = cmpxchg(&l->locked, _Q_LOCKED_VAL, 0);
+       if (likely(locked == _Q_LOCKED_VAL))
+               return;
+
+       __pv_queued_spin_unlock_slowpath(lock, locked);
+}
+#endif /* __pv_queued_spin_unlock */
diff --git a/kernel/locking/qspinlock_stat.h b/kernel/locking/qspinlock_stat.h
new file mode 100644 (file)
index 0000000..640dcec
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * This program is 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.
+ *
+ * Authors: Waiman Long <waiman.long@hpe.com>
+ */
+
+/*
+ * When queued spinlock statistical counters are enabled, the following
+ * debugfs files will be created for reporting the counter values:
+ *
+ * <debugfs>/qlockstat/
+ *   pv_hash_hops      - average # of hops per hashing operation
+ *   pv_kick_unlock    - # of vCPU kicks issued at unlock time
+ *   pv_kick_wake      - # of vCPU kicks used for computing pv_latency_wake
+ *   pv_latency_kick   - average latency (ns) of vCPU kick operation
+ *   pv_latency_wake   - average latency (ns) from vCPU kick to wakeup
+ *   pv_lock_stealing  - # of lock stealing operations
+ *   pv_spurious_wakeup        - # of spurious wakeups
+ *   pv_wait_again     - # of vCPU wait's that happened after a vCPU kick
+ *   pv_wait_early     - # of early vCPU wait's
+ *   pv_wait_head      - # of vCPU wait's at the queue head
+ *   pv_wait_node      - # of vCPU wait's at a non-head queue node
+ *
+ * Writing to the "reset_counters" file will reset all the above counter
+ * values.
+ *
+ * These statistical counters are implemented as per-cpu variables which are
+ * summed and computed whenever the corresponding debugfs files are read. This
+ * minimizes added overhead making the counters usable even in a production
+ * environment.
+ *
+ * There may be slight difference between pv_kick_wake and pv_kick_unlock.
+ */
+enum qlock_stats {
+       qstat_pv_hash_hops,
+       qstat_pv_kick_unlock,
+       qstat_pv_kick_wake,
+       qstat_pv_latency_kick,
+       qstat_pv_latency_wake,
+       qstat_pv_lock_stealing,
+       qstat_pv_spurious_wakeup,
+       qstat_pv_wait_again,
+       qstat_pv_wait_early,
+       qstat_pv_wait_head,
+       qstat_pv_wait_node,
+       qstat_num,      /* Total number of statistical counters */
+       qstat_reset_cnts = qstat_num,
+};
+
+#ifdef CONFIG_QUEUED_LOCK_STAT
+/*
+ * Collect pvqspinlock statistics
+ */
+#include <linux/debugfs.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+
+static const char * const qstat_names[qstat_num + 1] = {
+       [qstat_pv_hash_hops]       = "pv_hash_hops",
+       [qstat_pv_kick_unlock]     = "pv_kick_unlock",
+       [qstat_pv_kick_wake]       = "pv_kick_wake",
+       [qstat_pv_spurious_wakeup] = "pv_spurious_wakeup",
+       [qstat_pv_latency_kick]    = "pv_latency_kick",
+       [qstat_pv_latency_wake]    = "pv_latency_wake",
+       [qstat_pv_lock_stealing]   = "pv_lock_stealing",
+       [qstat_pv_wait_again]      = "pv_wait_again",
+       [qstat_pv_wait_early]      = "pv_wait_early",
+       [qstat_pv_wait_head]       = "pv_wait_head",
+       [qstat_pv_wait_node]       = "pv_wait_node",
+       [qstat_reset_cnts]         = "reset_counters",
+};
+
+/*
+ * Per-cpu counters
+ */
+static DEFINE_PER_CPU(unsigned long, qstats[qstat_num]);
+static DEFINE_PER_CPU(u64, pv_kick_time);
+
+/*
+ * Function to read and return the qlock statistical counter values
+ *
+ * The following counters are handled specially:
+ * 1. qstat_pv_latency_kick
+ *    Average kick latency (ns) = pv_latency_kick/pv_kick_unlock
+ * 2. qstat_pv_latency_wake
+ *    Average wake latency (ns) = pv_latency_wake/pv_kick_wake
+ * 3. qstat_pv_hash_hops
+ *    Average hops/hash = pv_hash_hops/pv_kick_unlock
+ */
+static ssize_t qstat_read(struct file *file, char __user *user_buf,
+                         size_t count, loff_t *ppos)
+{
+       char buf[64];
+       int cpu, counter, len;
+       u64 stat = 0, kicks = 0;
+
+       /*
+        * Get the counter ID stored in file->f_inode->i_private
+        */
+       if (!file->f_inode) {
+               WARN_ON_ONCE(1);
+               return -EBADF;
+       }
+       counter = (long)(file->f_inode->i_private);
+
+       if (counter >= qstat_num)
+               return -EBADF;
+
+       for_each_possible_cpu(cpu) {
+               stat += per_cpu(qstats[counter], cpu);
+               /*
+                * Need to sum additional counter for some of them
+                */
+               switch (counter) {
+
+               case qstat_pv_latency_kick:
+               case qstat_pv_hash_hops:
+                       kicks += per_cpu(qstats[qstat_pv_kick_unlock], cpu);
+                       break;
+
+               case qstat_pv_latency_wake:
+                       kicks += per_cpu(qstats[qstat_pv_kick_wake], cpu);
+                       break;
+               }
+       }
+
+       if (counter == qstat_pv_hash_hops) {
+               u64 frac;
+
+               frac = 100ULL * do_div(stat, kicks);
+               frac = DIV_ROUND_CLOSEST_ULL(frac, kicks);
+
+               /*
+                * Return a X.XX decimal number
+                */
+               len = snprintf(buf, sizeof(buf) - 1, "%llu.%02llu\n", stat, frac);
+       } else {
+               /*
+                * Round to the nearest ns
+                */
+               if ((counter == qstat_pv_latency_kick) ||
+                   (counter == qstat_pv_latency_wake)) {
+                       stat = 0;
+                       if (kicks)
+                               stat = DIV_ROUND_CLOSEST_ULL(stat, kicks);
+               }
+               len = snprintf(buf, sizeof(buf) - 1, "%llu\n", stat);
+       }
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+/*
+ * Function to handle write request
+ *
+ * When counter = reset_cnts, reset all the counter values.
+ * Since the counter updates aren't atomic, the resetting is done twice
+ * to make sure that the counters are very likely to be all cleared.
+ */
+static ssize_t qstat_write(struct file *file, const char __user *user_buf,
+                          size_t count, loff_t *ppos)
+{
+       int cpu;
+
+       /*
+        * Get the counter ID stored in file->f_inode->i_private
+        */
+       if (!file->f_inode) {
+               WARN_ON_ONCE(1);
+               return -EBADF;
+       }
+       if ((long)(file->f_inode->i_private) != qstat_reset_cnts)
+               return count;
+
+       for_each_possible_cpu(cpu) {
+               int i;
+               unsigned long *ptr = per_cpu_ptr(qstats, cpu);
+
+               for (i = 0 ; i < qstat_num; i++)
+                       WRITE_ONCE(ptr[i], 0);
+               for (i = 0 ; i < qstat_num; i++)
+                       WRITE_ONCE(ptr[i], 0);
+       }
+       return count;
+}
+
+/*
+ * Debugfs data structures
+ */
+static const struct file_operations fops_qstat = {
+       .read = qstat_read,
+       .write = qstat_write,
+       .llseek = default_llseek,
+};
+
+/*
+ * Initialize debugfs for the qspinlock statistical counters
+ */
+static int __init init_qspinlock_stat(void)
+{
+       struct dentry *d_qstat = debugfs_create_dir("qlockstat", NULL);
+       int i;
+
+       if (!d_qstat) {
+               pr_warn("Could not create 'qlockstat' debugfs directory\n");
+               return 0;
+       }
+
+       /*
+        * Create the debugfs files
+        *
+        * As reading from and writing to the stat files can be slow, only
+        * root is allowed to do the read/write to limit impact to system
+        * performance.
+        */
+       for (i = 0; i < qstat_num; i++)
+               debugfs_create_file(qstat_names[i], 0400, d_qstat,
+                                  (void *)(long)i, &fops_qstat);
+
+       debugfs_create_file(qstat_names[qstat_reset_cnts], 0200, d_qstat,
+                          (void *)(long)qstat_reset_cnts, &fops_qstat);
+       return 0;
+}
+fs_initcall(init_qspinlock_stat);
+
+/*
+ * Increment the PV qspinlock statistical counters
+ */
+static inline void qstat_inc(enum qlock_stats stat, bool cond)
+{
+       if (cond)
+               this_cpu_inc(qstats[stat]);
+}
+
+/*
+ * PV hash hop count
+ */
+static inline void qstat_hop(int hopcnt)
+{
+       this_cpu_add(qstats[qstat_pv_hash_hops], hopcnt);
+}
+
+/*
+ * Replacement function for pv_kick()
+ */
+static inline void __pv_kick(int cpu)
+{
+       u64 start = sched_clock();
+
+       per_cpu(pv_kick_time, cpu) = start;
+       pv_kick(cpu);
+       this_cpu_add(qstats[qstat_pv_latency_kick], sched_clock() - start);
+}
+
+/*
+ * Replacement function for pv_wait()
+ */
+static inline void __pv_wait(u8 *ptr, u8 val)
+{
+       u64 *pkick_time = this_cpu_ptr(&pv_kick_time);
+
+       *pkick_time = 0;
+       pv_wait(ptr, val);
+       if (*pkick_time) {
+               this_cpu_add(qstats[qstat_pv_latency_wake],
+                            sched_clock() - *pkick_time);
+               qstat_inc(qstat_pv_kick_wake, true);
+       }
+}
+
+#define pv_kick(c)     __pv_kick(c)
+#define pv_wait(p, v)  __pv_wait(p, v)
+
+/*
+ * PV unfair trylock count tracking function
+ */
+static inline int qstat_spin_steal_lock(struct qspinlock *lock)
+{
+       int ret = pv_queued_spin_steal_lock(lock);
+
+       qstat_inc(qstat_pv_lock_stealing, ret);
+       return ret;
+}
+#undef  queued_spin_trylock
+#define queued_spin_trylock(l) qstat_spin_steal_lock(l)
+
+#else /* CONFIG_QUEUED_LOCK_STAT */
+
+static inline void qstat_inc(enum qlock_stats stat, bool cond) { }
+static inline void qstat_hop(int hopcnt)                       { }
+
+#endif /* CONFIG_QUEUED_LOCK_STAT */
index 8f051a106676fb8f2d5457a9104340cce81ce37a..38c7bd5583fff036c0f993ac2c15077882d61501 100644 (file)
@@ -3571,6 +3571,12 @@ static int load_module(struct load_info *info, const char __user *uargs,
        synchronize_sched();
        mutex_unlock(&module_mutex);
  free_module:
+       /*
+        * Ftrace needs to clean up what it initialized.
+        * This does nothing if ftrace_module_init() wasn't called,
+        * but it must be called outside of module_mutex.
+        */
+       ftrace_release_mod(mod);
        /* Free lock-classes; relies on the preceding sync_rcu() */
        lockdep_free_key_range(mod->module_core, mod->core_size);
 
index 4b150bc0c6c111ee09f783eaa6aa101339f6ceec..b333380c6bb239f1ee870430774613aaab4dfb2d 100644 (file)
@@ -61,6 +61,17 @@ void __weak panic_smp_self_stop(void)
                cpu_relax();
 }
 
+/*
+ * Stop ourselves in NMI context if another CPU has already panicked. Arch code
+ * may override this to prepare for crash dumping, e.g. save regs info.
+ */
+void __weak nmi_panic_self_stop(struct pt_regs *regs)
+{
+       panic_smp_self_stop();
+}
+
+atomic_t panic_cpu = ATOMIC_INIT(PANIC_CPU_INVALID);
+
 /**
  *     panic - halt the system
  *     @fmt: The text string to print
@@ -71,17 +82,17 @@ void __weak panic_smp_self_stop(void)
  */
 void panic(const char *fmt, ...)
 {
-       static DEFINE_SPINLOCK(panic_lock);
        static char buf[1024];
        va_list args;
        long i, i_next = 0;
        int state = 0;
+       int old_cpu, this_cpu;
 
        /*
         * Disable local interrupts. This will prevent panic_smp_self_stop
         * from deadlocking the first cpu that invokes the panic, since
         * there is nothing to prevent an interrupt handler (that runs
-        * after the panic_lock is acquired) from invoking panic again.
+        * after setting panic_cpu) from invoking panic() again.
         */
        local_irq_disable();
 
@@ -94,8 +105,16 @@ void panic(const char *fmt, ...)
         * multiple parallel invocations of panic, all other CPUs either
         * stop themself or will wait until they are stopped by the 1st CPU
         * with smp_send_stop().
+        *
+        * `old_cpu == PANIC_CPU_INVALID' means this is the 1st CPU which
+        * comes here, so go ahead.
+        * `old_cpu == this_cpu' means we came from nmi_panic() which sets
+        * panic_cpu to this CPU.  In this case, this is also the 1st CPU.
         */
-       if (!spin_trylock(&panic_lock))
+       this_cpu = raw_smp_processor_id();
+       old_cpu  = atomic_cmpxchg(&panic_cpu, PANIC_CPU_INVALID, this_cpu);
+
+       if (old_cpu != PANIC_CPU_INVALID && old_cpu != this_cpu)
                panic_smp_self_stop();
 
        console_verbose();
@@ -117,9 +136,11 @@ void panic(const char *fmt, ...)
         * everything else.
         * If we want to run this after calling panic_notifiers, pass
         * the "crash_kexec_post_notifiers" option to the kernel.
+        *
+        * Bypass the panic_cpu check and call __crash_kexec directly.
         */
        if (!crash_kexec_post_notifiers)
-               crash_kexec(NULL);
+               __crash_kexec(NULL);
 
        /*
         * Note smp_send_stop is the usual smp shutdown function, which
@@ -142,9 +163,11 @@ void panic(const char *fmt, ...)
         * panic_notifiers and dumping kmsg before kdump.
         * Note: since some panic_notifiers can make crashed kernel
         * more unstable, it can increase risks of the kdump failure too.
+        *
+        * Bypass the panic_cpu check and call __crash_kexec directly.
         */
        if (crash_kexec_post_notifiers)
-               crash_kexec(NULL);
+               __crash_kexec(NULL);
 
        bust_spinlocks(0);
 
index d89328e260df6f4f953b649fea98587aacf12318..d2988d047d668d1d280c894beef56befdab65e65 100644 (file)
@@ -162,6 +162,27 @@ static int rcu_torture_writer_state;
 #define RTWS_SYNC              7
 #define RTWS_STUTTER           8
 #define RTWS_STOPPING          9
+static const char * const rcu_torture_writer_state_names[] = {
+       "RTWS_FIXED_DELAY",
+       "RTWS_DELAY",
+       "RTWS_REPLACE",
+       "RTWS_DEF_FREE",
+       "RTWS_EXP_SYNC",
+       "RTWS_COND_GET",
+       "RTWS_COND_SYNC",
+       "RTWS_SYNC",
+       "RTWS_STUTTER",
+       "RTWS_STOPPING",
+};
+
+static const char *rcu_torture_writer_state_getname(void)
+{
+       unsigned int i = READ_ONCE(rcu_torture_writer_state);
+
+       if (i >= ARRAY_SIZE(rcu_torture_writer_state_names))
+               return "???";
+       return rcu_torture_writer_state_names[i];
+}
 
 #if defined(MODULE) || defined(CONFIG_RCU_TORTURE_TEST_RUNNABLE)
 #define RCUTORTURE_RUNNABLE_INIT 1
@@ -1307,7 +1328,8 @@ rcu_torture_stats_print(void)
 
                rcutorture_get_gp_data(cur_ops->ttype,
                                       &flags, &gpnum, &completed);
-               pr_alert("??? Writer stall state %d g%lu c%lu f%#x\n",
+               pr_alert("??? Writer stall state %s(%d) g%lu c%lu f%#x\n",
+                        rcu_torture_writer_state_getname(),
                         rcu_torture_writer_state,
                         gpnum, completed, flags);
                show_rcu_gp_kthreads();
index a63a1ea5a41bf450f6b162674149a5928fca3530..9b9cdd549caa848111247b35b19109da7af9099d 100644 (file)
@@ -489,7 +489,7 @@ static void __synchronize_srcu(struct srcu_struct *sp, int trycount)
  */
 void synchronize_srcu(struct srcu_struct *sp)
 {
-       __synchronize_srcu(sp, rcu_gp_is_expedited()
+       __synchronize_srcu(sp, (rcu_gp_is_expedited() && !rcu_gp_is_normal())
                           ? SYNCHRONIZE_SRCU_EXP_TRYCOUNT
                           : SYNCHRONIZE_SRCU_TRYCOUNT);
 }
index f07343b54fe5a29d4fcabe7e78b9c3ea79029414..e41dd4131f7a141976e771653e3169f2955f6f33 100644 (file)
@@ -68,10 +68,6 @@ MODULE_ALIAS("rcutree");
 
 /* Data structures. */
 
-static struct lock_class_key rcu_node_class[RCU_NUM_LVLS];
-static struct lock_class_key rcu_fqs_class[RCU_NUM_LVLS];
-static struct lock_class_key rcu_exp_class[RCU_NUM_LVLS];
-
 /*
  * In order to export the rcu_state name to the tracing tools, it
  * needs to be added in the __tracepoint_string section.
@@ -246,24 +242,17 @@ static int rcu_gp_in_progress(struct rcu_state *rsp)
  */
 void rcu_sched_qs(void)
 {
-       unsigned long flags;
-
-       if (__this_cpu_read(rcu_sched_data.cpu_no_qs.s)) {
-               trace_rcu_grace_period(TPS("rcu_sched"),
-                                      __this_cpu_read(rcu_sched_data.gpnum),
-                                      TPS("cpuqs"));
-               __this_cpu_write(rcu_sched_data.cpu_no_qs.b.norm, false);
-               if (!__this_cpu_read(rcu_sched_data.cpu_no_qs.b.exp))
-                       return;
-               local_irq_save(flags);
-               if (__this_cpu_read(rcu_sched_data.cpu_no_qs.b.exp)) {
-                       __this_cpu_write(rcu_sched_data.cpu_no_qs.b.exp, false);
-                       rcu_report_exp_rdp(&rcu_sched_state,
-                                          this_cpu_ptr(&rcu_sched_data),
-                                          true);
-               }
-               local_irq_restore(flags);
-       }
+       if (!__this_cpu_read(rcu_sched_data.cpu_no_qs.s))
+               return;
+       trace_rcu_grace_period(TPS("rcu_sched"),
+                              __this_cpu_read(rcu_sched_data.gpnum),
+                              TPS("cpuqs"));
+       __this_cpu_write(rcu_sched_data.cpu_no_qs.b.norm, false);
+       if (!__this_cpu_read(rcu_sched_data.cpu_no_qs.b.exp))
+               return;
+       __this_cpu_write(rcu_sched_data.cpu_no_qs.b.exp, false);
+       rcu_report_exp_rdp(&rcu_sched_state,
+                          this_cpu_ptr(&rcu_sched_data), true);
 }
 
 void rcu_bh_qs(void)
@@ -300,17 +289,16 @@ EXPORT_PER_CPU_SYMBOL_GPL(rcu_qs_ctr);
  * We inform the RCU core by emulating a zero-duration dyntick-idle
  * period, which we in turn do by incrementing the ->dynticks counter
  * by two.
+ *
+ * The caller must have disabled interrupts.
  */
 static void rcu_momentary_dyntick_idle(void)
 {
-       unsigned long flags;
        struct rcu_data *rdp;
        struct rcu_dynticks *rdtp;
        int resched_mask;
        struct rcu_state *rsp;
 
-       local_irq_save(flags);
-
        /*
         * Yes, we can lose flag-setting operations.  This is OK, because
         * the flag will be set again after some delay.
@@ -340,13 +328,12 @@ static void rcu_momentary_dyntick_idle(void)
                smp_mb__after_atomic(); /* Later stuff after QS. */
                break;
        }
-       local_irq_restore(flags);
 }
 
 /*
  * Note a context switch.  This is a quiescent state for RCU-sched,
  * and requires special handling for preemptible RCU.
- * The caller must have disabled preemption.
+ * The caller must have disabled interrupts.
  */
 void rcu_note_context_switch(void)
 {
@@ -376,9 +363,14 @@ EXPORT_SYMBOL_GPL(rcu_note_context_switch);
  */
 void rcu_all_qs(void)
 {
+       unsigned long flags;
+
        barrier(); /* Avoid RCU read-side critical sections leaking down. */
-       if (unlikely(raw_cpu_read(rcu_sched_qs_mask)))
+       if (unlikely(raw_cpu_read(rcu_sched_qs_mask))) {
+               local_irq_save(flags);
                rcu_momentary_dyntick_idle();
+               local_irq_restore(flags);
+       }
        this_cpu_inc(rcu_qs_ctr);
        barrier(); /* Avoid RCU read-side critical sections leaking up. */
 }
@@ -605,25 +597,25 @@ static int rcu_future_needs_gp(struct rcu_state *rsp)
  * The caller must have disabled interrupts to prevent races with
  * normal callback registry.
  */
-static int
+static bool
 cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp)
 {
        int i;
 
        if (rcu_gp_in_progress(rsp))
-               return 0;  /* No, a grace period is already in progress. */
+               return false;  /* No, a grace period is already in progress. */
        if (rcu_future_needs_gp(rsp))
-               return 1;  /* Yes, a no-CBs CPU needs one. */
+               return true;  /* Yes, a no-CBs CPU needs one. */
        if (!rdp->nxttail[RCU_NEXT_TAIL])
-               return 0;  /* No, this is a no-CBs (or offline) CPU. */
+               return false;  /* No, this is a no-CBs (or offline) CPU. */
        if (*rdp->nxttail[RCU_NEXT_READY_TAIL])
-               return 1;  /* Yes, this CPU has newly registered callbacks. */
+               return true;  /* Yes, CPU has newly registered callbacks. */
        for (i = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++)
                if (rdp->nxttail[i - 1] != rdp->nxttail[i] &&
                    ULONG_CMP_LT(READ_ONCE(rsp->completed),
                                 rdp->nxtcompleted[i]))
-                       return 1;  /* Yes, CBs for future grace period. */
-       return 0; /* No grace period needed. */
+                       return true;  /* Yes, CBs for future grace period. */
+       return false; /* No grace period needed. */
 }
 
 /*
@@ -740,7 +732,7 @@ void rcu_user_enter(void)
  *
  * Exit from an interrupt handler, which might possibly result in entering
  * idle mode, in other words, leaving the mode in which read-side critical
- * sections can occur.
+ * sections can occur.  The caller must have disabled interrupts.
  *
  * This code assumes that the idle loop never does anything that might
  * result in unbalanced calls to irq_enter() and irq_exit().  If your
@@ -753,11 +745,10 @@ void rcu_user_enter(void)
  */
 void rcu_irq_exit(void)
 {
-       unsigned long flags;
        long long oldval;
        struct rcu_dynticks *rdtp;
 
-       local_irq_save(flags);
+       RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_irq_exit() invoked with irqs enabled!!!");
        rdtp = this_cpu_ptr(&rcu_dynticks);
        oldval = rdtp->dynticks_nesting;
        rdtp->dynticks_nesting--;
@@ -768,6 +759,17 @@ void rcu_irq_exit(void)
        else
                rcu_eqs_enter_common(oldval, true);
        rcu_sysidle_enter(1);
+}
+
+/*
+ * Wrapper for rcu_irq_exit() where interrupts are enabled.
+ */
+void rcu_irq_exit_irqson(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       rcu_irq_exit();
        local_irq_restore(flags);
 }
 
@@ -865,7 +867,7 @@ void rcu_user_exit(void)
  *
  * Enter an interrupt handler, which might possibly result in exiting
  * idle mode, in other words, entering the mode in which read-side critical
- * sections can occur.
+ * sections can occur.  The caller must have disabled interrupts.
  *
  * Note that the Linux kernel is fully capable of entering an interrupt
  * handler that it never exits, for example when doing upcalls to
@@ -881,11 +883,10 @@ void rcu_user_exit(void)
  */
 void rcu_irq_enter(void)
 {
-       unsigned long flags;
        struct rcu_dynticks *rdtp;
        long long oldval;
 
-       local_irq_save(flags);
+       RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_irq_enter() invoked with irqs enabled!!!");
        rdtp = this_cpu_ptr(&rcu_dynticks);
        oldval = rdtp->dynticks_nesting;
        rdtp->dynticks_nesting++;
@@ -896,6 +897,17 @@ void rcu_irq_enter(void)
        else
                rcu_eqs_exit_common(oldval, true);
        rcu_sysidle_exit(1);
+}
+
+/*
+ * Wrapper for rcu_irq_enter() where interrupts are enabled.
+ */
+void rcu_irq_enter_irqson(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       rcu_irq_enter();
        local_irq_restore(flags);
 }
 
@@ -1186,6 +1198,16 @@ static void record_gp_stall_check_time(struct rcu_state *rsp)
        rsp->n_force_qs_gpstart = READ_ONCE(rsp->n_force_qs);
 }
 
+/*
+ * Convert a ->gp_state value to a character string.
+ */
+static const char *gp_state_getname(short gs)
+{
+       if (gs < 0 || gs >= ARRAY_SIZE(gp_state_names))
+               return "???";
+       return gp_state_names[gs];
+}
+
 /*
  * Complain about starvation of grace-period kthread.
  */
@@ -1196,12 +1218,16 @@ static void rcu_check_gp_kthread_starvation(struct rcu_state *rsp)
 
        j = jiffies;
        gpa = READ_ONCE(rsp->gp_activity);
-       if (j - gpa > 2 * HZ)
-               pr_err("%s kthread starved for %ld jiffies! g%lu c%lu f%#x s%d ->state=%#lx\n",
+       if (j - gpa > 2 * HZ) {
+               pr_err("%s kthread starved for %ld jiffies! g%lu c%lu f%#x %s(%d) ->state=%#lx\n",
                       rsp->name, j - gpa,
                       rsp->gpnum, rsp->completed,
-                      rsp->gp_flags, rsp->gp_state,
-                      rsp->gp_kthread ? rsp->gp_kthread->state : 0);
+                      rsp->gp_flags,
+                      gp_state_getname(rsp->gp_state), rsp->gp_state,
+                      rsp->gp_kthread ? rsp->gp_kthread->state : ~0);
+               if (rsp->gp_kthread)
+                       sched_show_task(rsp->gp_kthread);
+       }
 }
 
 /*
@@ -1214,7 +1240,7 @@ static void rcu_dump_cpu_stacks(struct rcu_state *rsp)
        struct rcu_node *rnp;
 
        rcu_for_each_leaf_node(rsp, rnp) {
-               raw_spin_lock_irqsave(&rnp->lock, flags);
+               raw_spin_lock_irqsave_rcu_node(rnp, flags);
                if (rnp->qsmask != 0) {
                        for (cpu = 0; cpu <= rnp->grphi - rnp->grplo; cpu++)
                                if (rnp->qsmask & (1UL << cpu))
@@ -1237,7 +1263,7 @@ static void print_other_cpu_stall(struct rcu_state *rsp, unsigned long gpnum)
 
        /* Only let one CPU complain about others per time interval. */
 
-       raw_spin_lock_irqsave(&rnp->lock, flags);
+       raw_spin_lock_irqsave_rcu_node(rnp, flags);
        delta = jiffies - READ_ONCE(rsp->jiffies_stall);
        if (delta < RCU_STALL_RAT_DELAY || !rcu_gp_in_progress(rsp)) {
                raw_spin_unlock_irqrestore(&rnp->lock, flags);
@@ -1256,7 +1282,7 @@ static void print_other_cpu_stall(struct rcu_state *rsp, unsigned long gpnum)
               rsp->name);
        print_cpu_stall_info_begin();
        rcu_for_each_leaf_node(rsp, rnp) {
-               raw_spin_lock_irqsave(&rnp->lock, flags);
+               raw_spin_lock_irqsave_rcu_node(rnp, flags);
                ndetected += rcu_print_task_stall(rnp);
                if (rnp->qsmask != 0) {
                        for (cpu = 0; cpu <= rnp->grphi - rnp->grplo; cpu++)
@@ -1327,7 +1353,7 @@ static void print_cpu_stall(struct rcu_state *rsp)
 
        rcu_dump_cpu_stacks(rsp);
 
-       raw_spin_lock_irqsave(&rnp->lock, flags);
+       raw_spin_lock_irqsave_rcu_node(rnp, flags);
        if (ULONG_CMP_GE(jiffies, READ_ONCE(rsp->jiffies_stall)))
                WRITE_ONCE(rsp->jiffies_stall,
                           jiffies + 3 * rcu_jiffies_till_stall_check() + 3);
@@ -1534,10 +1560,8 @@ rcu_start_future_gp(struct rcu_node *rnp, struct rcu_data *rdp,
         * hold it, acquire the root rcu_node structure's lock in order to
         * start one (if needed).
         */
-       if (rnp != rnp_root) {
-               raw_spin_lock(&rnp_root->lock);
-               smp_mb__after_unlock_lock();
-       }
+       if (rnp != rnp_root)
+               raw_spin_lock_rcu_node(rnp_root);
 
        /*
         * Get a new grace-period number.  If there really is no grace
@@ -1786,11 +1810,10 @@ static void note_gp_changes(struct rcu_state *rsp, struct rcu_data *rdp)
        if ((rdp->gpnum == READ_ONCE(rnp->gpnum) &&
             rdp->completed == READ_ONCE(rnp->completed) &&
             !unlikely(READ_ONCE(rdp->gpwrap))) || /* w/out lock. */
-           !raw_spin_trylock(&rnp->lock)) { /* irqs already off, so later. */
+           !raw_spin_trylock_rcu_node(rnp)) { /* irqs already off, so later. */
                local_irq_restore(flags);
                return;
        }
-       smp_mb__after_unlock_lock();
        needwake = __note_gp_changes(rsp, rnp, rdp);
        raw_spin_unlock_irqrestore(&rnp->lock, flags);
        if (needwake)
@@ -1805,21 +1828,20 @@ static void rcu_gp_slow(struct rcu_state *rsp, int delay)
 }
 
 /*
- * Initialize a new grace period.  Return 0 if no grace period required.
+ * Initialize a new grace period.  Return false if no grace period required.
  */
-static int rcu_gp_init(struct rcu_state *rsp)
+static bool rcu_gp_init(struct rcu_state *rsp)
 {
        unsigned long oldmask;
        struct rcu_data *rdp;
        struct rcu_node *rnp = rcu_get_root(rsp);
 
        WRITE_ONCE(rsp->gp_activity, jiffies);
-       raw_spin_lock_irq(&rnp->lock);
-       smp_mb__after_unlock_lock();
+       raw_spin_lock_irq_rcu_node(rnp);
        if (!READ_ONCE(rsp->gp_flags)) {
                /* Spurious wakeup, tell caller to go back to sleep.  */
                raw_spin_unlock_irq(&rnp->lock);
-               return 0;
+               return false;
        }
        WRITE_ONCE(rsp->gp_flags, 0); /* Clear all flags: New grace period. */
 
@@ -1829,7 +1851,7 @@ static int rcu_gp_init(struct rcu_state *rsp)
                 * Not supposed to be able to happen.
                 */
                raw_spin_unlock_irq(&rnp->lock);
-               return 0;
+               return false;
        }
 
        /* Advance to a new grace period and initialize state. */
@@ -1847,8 +1869,7 @@ static int rcu_gp_init(struct rcu_state *rsp)
         */
        rcu_for_each_leaf_node(rsp, rnp) {
                rcu_gp_slow(rsp, gp_preinit_delay);
-               raw_spin_lock_irq(&rnp->lock);
-               smp_mb__after_unlock_lock();
+               raw_spin_lock_irq_rcu_node(rnp);
                if (rnp->qsmaskinit == rnp->qsmaskinitnext &&
                    !rnp->wait_blkd_tasks) {
                        /* Nothing to do on this leaf rcu_node structure. */
@@ -1904,8 +1925,7 @@ static int rcu_gp_init(struct rcu_state *rsp)
         */
        rcu_for_each_node_breadth_first(rsp, rnp) {
                rcu_gp_slow(rsp, gp_init_delay);
-               raw_spin_lock_irq(&rnp->lock);
-               smp_mb__after_unlock_lock();
+               raw_spin_lock_irq_rcu_node(rnp);
                rdp = this_cpu_ptr(rsp->rda);
                rcu_preempt_check_blocked_tasks(rnp);
                rnp->qsmask = rnp->qsmaskinit;
@@ -1923,7 +1943,7 @@ static int rcu_gp_init(struct rcu_state *rsp)
                WRITE_ONCE(rsp->gp_activity, jiffies);
        }
 
-       return 1;
+       return true;
 }
 
 /*
@@ -1973,8 +1993,7 @@ static void rcu_gp_fqs(struct rcu_state *rsp, bool first_time)
        }
        /* Clear flag to prevent immediate re-entry. */
        if (READ_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) {
-               raw_spin_lock_irq(&rnp->lock);
-               smp_mb__after_unlock_lock();
+               raw_spin_lock_irq_rcu_node(rnp);
                WRITE_ONCE(rsp->gp_flags,
                           READ_ONCE(rsp->gp_flags) & ~RCU_GP_FLAG_FQS);
                raw_spin_unlock_irq(&rnp->lock);
@@ -1993,8 +2012,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp)
        struct rcu_node *rnp = rcu_get_root(rsp);
 
        WRITE_ONCE(rsp->gp_activity, jiffies);
-       raw_spin_lock_irq(&rnp->lock);
-       smp_mb__after_unlock_lock();
+       raw_spin_lock_irq_rcu_node(rnp);
        gp_duration = jiffies - rsp->gp_start;
        if (gp_duration > rsp->gp_max)
                rsp->gp_max = gp_duration;
@@ -2019,8 +2037,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp)
         * grace period is recorded in any of the rcu_node structures.
         */
        rcu_for_each_node_breadth_first(rsp, rnp) {
-               raw_spin_lock_irq(&rnp->lock);
-               smp_mb__after_unlock_lock();
+               raw_spin_lock_irq_rcu_node(rnp);
                WARN_ON_ONCE(rcu_preempt_blocked_readers_cgp(rnp));
                WARN_ON_ONCE(rnp->qsmask);
                WRITE_ONCE(rnp->completed, rsp->gpnum);
@@ -2035,8 +2052,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp)
                rcu_gp_slow(rsp, gp_cleanup_delay);
        }
        rnp = rcu_get_root(rsp);
-       raw_spin_lock_irq(&rnp->lock);
-       smp_mb__after_unlock_lock(); /* Order GP before ->completed update. */
+       raw_spin_lock_irq_rcu_node(rnp); /* Order GP before ->completed update. */
        rcu_nocb_gp_set(rnp, nocb);
 
        /* Declare grace period done. */
@@ -2284,8 +2300,7 @@ rcu_report_qs_rnp(unsigned long mask, struct rcu_state *rsp,
                raw_spin_unlock_irqrestore(&rnp->lock, flags);
                rnp_c = rnp;
                rnp = rnp->parent;
-               raw_spin_lock_irqsave(&rnp->lock, flags);
-               smp_mb__after_unlock_lock();
+               raw_spin_lock_irqsave_rcu_node(rnp, flags);
                oldmask = rnp_c->qsmask;
        }
 
@@ -2332,8 +2347,7 @@ static void rcu_report_unblock_qs_rnp(struct rcu_state *rsp,
        gps = rnp->gpnum;
        mask = rnp->grpmask;
        raw_spin_unlock(&rnp->lock);    /* irqs remain disabled. */
-       raw_spin_lock(&rnp_p->lock);    /* irqs already disabled. */
-       smp_mb__after_unlock_lock();
+       raw_spin_lock_rcu_node(rnp_p);  /* irqs already disabled. */
        rcu_report_qs_rnp(mask, rsp, rnp_p, gps, flags);
 }
 
@@ -2355,8 +2369,7 @@ rcu_report_qs_rdp(int cpu, struct rcu_state *rsp, struct rcu_data *rdp)
        struct rcu_node *rnp;
 
        rnp = rdp->mynode;
-       raw_spin_lock_irqsave(&rnp->lock, flags);
-       smp_mb__after_unlock_lock();
+       raw_spin_lock_irqsave_rcu_node(rnp, flags);
        if ((rdp->cpu_no_qs.b.norm &&
             rdp->rcu_qs_ctr_snap == __this_cpu_read(rcu_qs_ctr)) ||
            rdp->gpnum != rnp->gpnum || rnp->completed == rnp->gpnum ||
@@ -2582,8 +2595,7 @@ static void rcu_cleanup_dead_rnp(struct rcu_node *rnp_leaf)
                rnp = rnp->parent;
                if (!rnp)
                        break;
-               raw_spin_lock(&rnp->lock); /* irqs already disabled. */
-               smp_mb__after_unlock_lock(); /* GP memory ordering. */
+               raw_spin_lock_rcu_node(rnp); /* irqs already disabled. */
                rnp->qsmaskinit &= ~mask;
                rnp->qsmask &= ~mask;
                if (rnp->qsmaskinit) {
@@ -2611,8 +2623,7 @@ static void rcu_cleanup_dying_idle_cpu(int cpu, struct rcu_state *rsp)
 
        /* Remove outgoing CPU from mask in the leaf rcu_node structure. */
        mask = rdp->grpmask;
-       raw_spin_lock_irqsave(&rnp->lock, flags);
-       smp_mb__after_unlock_lock();    /* Enforce GP memory-order guarantee. */
+       raw_spin_lock_irqsave_rcu_node(rnp, flags); /* Enforce GP memory-order guarantee. */
        rnp->qsmaskinitnext &= ~mask;
        raw_spin_unlock_irqrestore(&rnp->lock, flags);
 }
@@ -2809,8 +2820,7 @@ static void force_qs_rnp(struct rcu_state *rsp,
        rcu_for_each_leaf_node(rsp, rnp) {
                cond_resched_rcu_qs();
                mask = 0;
-               raw_spin_lock_irqsave(&rnp->lock, flags);
-               smp_mb__after_unlock_lock();
+               raw_spin_lock_irqsave_rcu_node(rnp, flags);
                if (rnp->qsmask == 0) {
                        if (rcu_state_p == &rcu_sched_state ||
                            rsp != rcu_state_p ||
@@ -2881,8 +2891,7 @@ static void force_quiescent_state(struct rcu_state *rsp)
        /* rnp_old == rcu_get_root(rsp), rnp == NULL. */
 
        /* Reached the root of the rcu_node tree, acquire lock. */
-       raw_spin_lock_irqsave(&rnp_old->lock, flags);
-       smp_mb__after_unlock_lock();
+       raw_spin_lock_irqsave_rcu_node(rnp_old, flags);
        raw_spin_unlock(&rnp_old->fqslock);
        if (READ_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) {
                rsp->n_force_qs_lh++;
@@ -2914,7 +2923,7 @@ __rcu_process_callbacks(struct rcu_state *rsp)
        /* Does this CPU require a not-yet-started grace period? */
        local_irq_save(flags);
        if (cpu_needs_another_gp(rsp, rdp)) {
-               raw_spin_lock(&rcu_get_root(rsp)->lock); /* irqs disabled. */
+               raw_spin_lock_rcu_node(rcu_get_root(rsp)); /* irqs disabled. */
                needwake = rcu_start_gp(rsp);
                raw_spin_unlock_irqrestore(&rcu_get_root(rsp)->lock, flags);
                if (needwake)
@@ -3005,8 +3014,7 @@ static void __call_rcu_core(struct rcu_state *rsp, struct rcu_data *rdp,
                if (!rcu_gp_in_progress(rsp)) {
                        struct rcu_node *rnp_root = rcu_get_root(rsp);
 
-                       raw_spin_lock(&rnp_root->lock);
-                       smp_mb__after_unlock_lock();
+                       raw_spin_lock_rcu_node(rnp_root);
                        needwake = rcu_start_gp(rsp);
                        raw_spin_unlock(&rnp_root->lock);
                        if (needwake)
@@ -3365,7 +3373,6 @@ static unsigned long rcu_seq_snap(unsigned long *sp)
 {
        unsigned long s;
 
-       smp_mb(); /* Caller's modifications seen first by other CPUs. */
        s = (READ_ONCE(*sp) + 3) & ~0x1;
        smp_mb(); /* Above access must not bleed into critical section. */
        return s;
@@ -3392,6 +3399,7 @@ static void rcu_exp_gp_seq_end(struct rcu_state *rsp)
 }
 static unsigned long rcu_exp_gp_seq_snap(struct rcu_state *rsp)
 {
+       smp_mb(); /* Caller's modifications seen first by other CPUs. */
        return rcu_seq_snap(&rsp->expedited_sequence);
 }
 static bool rcu_exp_gp_seq_done(struct rcu_state *rsp, unsigned long s)
@@ -3426,8 +3434,7 @@ static void sync_exp_reset_tree_hotplug(struct rcu_state *rsp)
         * CPUs for the current rcu_node structure up the rcu_node tree.
         */
        rcu_for_each_leaf_node(rsp, rnp) {
-               raw_spin_lock_irqsave(&rnp->lock, flags);
-               smp_mb__after_unlock_lock();
+               raw_spin_lock_irqsave_rcu_node(rnp, flags);
                if (rnp->expmaskinit == rnp->expmaskinitnext) {
                        raw_spin_unlock_irqrestore(&rnp->lock, flags);
                        continue;  /* No new CPUs, nothing to do. */
@@ -3447,8 +3454,7 @@ static void sync_exp_reset_tree_hotplug(struct rcu_state *rsp)
                rnp_up = rnp->parent;
                done = false;
                while (rnp_up) {
-                       raw_spin_lock_irqsave(&rnp_up->lock, flags);
-                       smp_mb__after_unlock_lock();
+                       raw_spin_lock_irqsave_rcu_node(rnp_up, flags);
                        if (rnp_up->expmaskinit)
                                done = true;
                        rnp_up->expmaskinit |= mask;
@@ -3472,8 +3478,7 @@ static void __maybe_unused sync_exp_reset_tree(struct rcu_state *rsp)
 
        sync_exp_reset_tree_hotplug(rsp);
        rcu_for_each_node_breadth_first(rsp, rnp) {
-               raw_spin_lock_irqsave(&rnp->lock, flags);
-               smp_mb__after_unlock_lock();
+               raw_spin_lock_irqsave_rcu_node(rnp, flags);
                WARN_ON_ONCE(rnp->expmask);
                rnp->expmask = rnp->expmaskinit;
                raw_spin_unlock_irqrestore(&rnp->lock, flags);
@@ -3531,8 +3536,7 @@ static void __rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp,
                mask = rnp->grpmask;
                raw_spin_unlock(&rnp->lock); /* irqs remain disabled */
                rnp = rnp->parent;
-               raw_spin_lock(&rnp->lock); /* irqs already disabled */
-               smp_mb__after_unlock_lock();
+               raw_spin_lock_rcu_node(rnp); /* irqs already disabled */
                WARN_ON_ONCE(!(rnp->expmask & mask));
                rnp->expmask &= ~mask;
        }
@@ -3549,8 +3553,7 @@ static void __maybe_unused rcu_report_exp_rnp(struct rcu_state *rsp,
 {
        unsigned long flags;
 
-       raw_spin_lock_irqsave(&rnp->lock, flags);
-       smp_mb__after_unlock_lock();
+       raw_spin_lock_irqsave_rcu_node(rnp, flags);
        __rcu_report_exp_rnp(rsp, rnp, wake, flags);
 }
 
@@ -3564,8 +3567,7 @@ static void rcu_report_exp_cpu_mult(struct rcu_state *rsp, struct rcu_node *rnp,
 {
        unsigned long flags;
 
-       raw_spin_lock_irqsave(&rnp->lock, flags);
-       smp_mb__after_unlock_lock();
+       raw_spin_lock_irqsave_rcu_node(rnp, flags);
        if (!(rnp->expmask & mask)) {
                raw_spin_unlock_irqrestore(&rnp->lock, flags);
                return;
@@ -3609,7 +3611,7 @@ static bool sync_exp_work_done(struct rcu_state *rsp, struct rcu_node *rnp,
  */
 static struct rcu_node *exp_funnel_lock(struct rcu_state *rsp, unsigned long s)
 {
-       struct rcu_data *rdp;
+       struct rcu_data *rdp = per_cpu_ptr(rsp->rda, raw_smp_processor_id());
        struct rcu_node *rnp0;
        struct rcu_node *rnp1 = NULL;
 
@@ -3623,7 +3625,7 @@ static struct rcu_node *exp_funnel_lock(struct rcu_state *rsp, unsigned long s)
        if (!mutex_is_locked(&rnp0->exp_funnel_mutex)) {
                if (mutex_trylock(&rnp0->exp_funnel_mutex)) {
                        if (sync_exp_work_done(rsp, rnp0, NULL,
-                                              &rsp->expedited_workdone0, s))
+                                              &rdp->expedited_workdone0, s))
                                return NULL;
                        return rnp0;
                }
@@ -3637,14 +3639,13 @@ static struct rcu_node *exp_funnel_lock(struct rcu_state *rsp, unsigned long s)
         * can be inexact, as it is just promoting locality and is not
         * strictly needed for correctness.
         */
-       rdp = per_cpu_ptr(rsp->rda, raw_smp_processor_id());
-       if (sync_exp_work_done(rsp, NULL, NULL, &rsp->expedited_workdone1, s))
+       if (sync_exp_work_done(rsp, NULL, NULL, &rdp->expedited_workdone1, s))
                return NULL;
        mutex_lock(&rdp->exp_funnel_mutex);
        rnp0 = rdp->mynode;
        for (; rnp0 != NULL; rnp0 = rnp0->parent) {
                if (sync_exp_work_done(rsp, rnp1, rdp,
-                                      &rsp->expedited_workdone2, s))
+                                      &rdp->expedited_workdone2, s))
                        return NULL;
                mutex_lock(&rnp0->exp_funnel_mutex);
                if (rnp1)
@@ -3654,7 +3655,7 @@ static struct rcu_node *exp_funnel_lock(struct rcu_state *rsp, unsigned long s)
                rnp1 = rnp0;
        }
        if (sync_exp_work_done(rsp, rnp1, rdp,
-                              &rsp->expedited_workdone3, s))
+                              &rdp->expedited_workdone3, s))
                return NULL;
        return rnp1;
 }
@@ -3708,8 +3709,7 @@ static void sync_rcu_exp_select_cpus(struct rcu_state *rsp,
 
        sync_exp_reset_tree(rsp);
        rcu_for_each_leaf_node(rsp, rnp) {
-               raw_spin_lock_irqsave(&rnp->lock, flags);
-               smp_mb__after_unlock_lock();
+               raw_spin_lock_irqsave_rcu_node(rnp, flags);
 
                /* Each pass checks a CPU for identity, offline, and idle. */
                mask_ofl_test = 0;
@@ -3741,24 +3741,22 @@ retry_ipi:
                        ret = smp_call_function_single(cpu, func, rsp, 0);
                        if (!ret) {
                                mask_ofl_ipi &= ~mask;
-                       } else {
-                               /* Failed, raced with offline. */
-                               raw_spin_lock_irqsave(&rnp->lock, flags);
-                               if (cpu_online(cpu) &&
-                                   (rnp->expmask & mask)) {
-                                       raw_spin_unlock_irqrestore(&rnp->lock,
-                                                                  flags);
-                                       schedule_timeout_uninterruptible(1);
-                                       if (cpu_online(cpu) &&
-                                           (rnp->expmask & mask))
-                                               goto retry_ipi;
-                                       raw_spin_lock_irqsave(&rnp->lock,
-                                                             flags);
-                               }
-                               if (!(rnp->expmask & mask))
-                                       mask_ofl_ipi &= ~mask;
+                               continue;
+                       }
+                       /* Failed, raced with offline. */
+                       raw_spin_lock_irqsave_rcu_node(rnp, flags);
+                       if (cpu_online(cpu) &&
+                           (rnp->expmask & mask)) {
                                raw_spin_unlock_irqrestore(&rnp->lock, flags);
+                               schedule_timeout_uninterruptible(1);
+                               if (cpu_online(cpu) &&
+                                   (rnp->expmask & mask))
+                                       goto retry_ipi;
+                               raw_spin_lock_irqsave_rcu_node(rnp, flags);
                        }
+                       if (!(rnp->expmask & mask))
+                               mask_ofl_ipi &= ~mask;
+                       raw_spin_unlock_irqrestore(&rnp->lock, flags);
                }
                /* Report quiescent states for those that went offline. */
                mask_ofl_test |= mask_ofl_ipi;
@@ -3773,6 +3771,7 @@ static void synchronize_sched_expedited_wait(struct rcu_state *rsp)
        unsigned long jiffies_stall;
        unsigned long jiffies_start;
        unsigned long mask;
+       int ndetected;
        struct rcu_node *rnp;
        struct rcu_node *rnp_root = rcu_get_root(rsp);
        int ret;
@@ -3785,7 +3784,7 @@ static void synchronize_sched_expedited_wait(struct rcu_state *rsp)
                                rsp->expedited_wq,
                                sync_rcu_preempt_exp_done(rnp_root),
                                jiffies_stall);
-               if (ret > 0)
+               if (ret > 0 || sync_rcu_preempt_exp_done(rnp_root))
                        return;
                if (ret < 0) {
                        /* Hit a signal, disable CPU stall warnings. */
@@ -3795,14 +3794,16 @@ static void synchronize_sched_expedited_wait(struct rcu_state *rsp)
                }
                pr_err("INFO: %s detected expedited stalls on CPUs/tasks: {",
                       rsp->name);
+               ndetected = 0;
                rcu_for_each_leaf_node(rsp, rnp) {
-                       (void)rcu_print_task_exp_stall(rnp);
+                       ndetected = rcu_print_task_exp_stall(rnp);
                        mask = 1;
                        for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask <<= 1) {
                                struct rcu_data *rdp;
 
                                if (!(rnp->expmask & mask))
                                        continue;
+                               ndetected++;
                                rdp = per_cpu_ptr(rsp->rda, cpu);
                                pr_cont(" %d-%c%c%c", cpu,
                                        "O."[cpu_online(cpu)],
@@ -3811,8 +3812,23 @@ static void synchronize_sched_expedited_wait(struct rcu_state *rsp)
                        }
                        mask <<= 1;
                }
-               pr_cont(" } %lu jiffies s: %lu\n",
-                       jiffies - jiffies_start, rsp->expedited_sequence);
+               pr_cont(" } %lu jiffies s: %lu root: %#lx/%c\n",
+                       jiffies - jiffies_start, rsp->expedited_sequence,
+                       rnp_root->expmask, ".T"[!!rnp_root->exp_tasks]);
+               if (!ndetected) {
+                       pr_err("blocking rcu_node structures:");
+                       rcu_for_each_node_breadth_first(rsp, rnp) {
+                               if (rnp == rnp_root)
+                                       continue; /* printed unconditionally */
+                               if (sync_rcu_preempt_exp_done(rnp))
+                                       continue;
+                               pr_cont(" l=%u:%d-%d:%#lx/%c",
+                                       rnp->level, rnp->grplo, rnp->grphi,
+                                       rnp->expmask,
+                                       ".T"[!!rnp->exp_tasks]);
+                       }
+                       pr_cont("\n");
+               }
                rcu_for_each_leaf_node(rsp, rnp) {
                        mask = 1;
                        for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask <<= 1) {
@@ -3847,6 +3863,16 @@ void synchronize_sched_expedited(void)
        struct rcu_node *rnp;
        struct rcu_state *rsp = &rcu_sched_state;
 
+       /* If only one CPU, this is automatically a grace period. */
+       if (rcu_blocking_is_gp())
+               return;
+
+       /* If expedited grace periods are prohibited, fall back to normal. */
+       if (rcu_gp_is_normal()) {
+               wait_rcu_gp(call_rcu_sched);
+               return;
+       }
+
        /* Take a snapshot of the sequence number.  */
        s = rcu_exp_gp_seq_snap(rsp);
 
@@ -4135,7 +4161,7 @@ static void rcu_init_new_rnp(struct rcu_node *rnp_leaf)
                rnp = rnp->parent;
                if (rnp == NULL)
                        return;
-               raw_spin_lock(&rnp->lock); /* Interrupts already disabled. */
+               raw_spin_lock_rcu_node(rnp); /* Interrupts already disabled. */
                rnp->qsmaskinit |= mask;
                raw_spin_unlock(&rnp->lock); /* Interrupts remain disabled. */
        }
@@ -4152,7 +4178,7 @@ rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp)
        struct rcu_node *rnp = rcu_get_root(rsp);
 
        /* Set up local state, ensuring consistent view of global state. */
-       raw_spin_lock_irqsave(&rnp->lock, flags);
+       raw_spin_lock_irqsave_rcu_node(rnp, flags);
        rdp->grpmask = 1UL << (cpu - rdp->mynode->grplo);
        rdp->dynticks = &per_cpu(rcu_dynticks, cpu);
        WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != DYNTICK_TASK_EXIT_IDLE);
@@ -4179,7 +4205,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp)
        struct rcu_node *rnp = rcu_get_root(rsp);
 
        /* Set up local state, ensuring consistent view of global state. */
-       raw_spin_lock_irqsave(&rnp->lock, flags);
+       raw_spin_lock_irqsave_rcu_node(rnp, flags);
        rdp->qlen_last_fqs_check = 0;
        rdp->n_force_qs_snap = rsp->n_force_qs;
        rdp->blimit = blimit;
@@ -4198,8 +4224,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp)
         */
        rnp = rdp->mynode;
        mask = rdp->grpmask;
-       raw_spin_lock(&rnp->lock);              /* irqs already disabled. */
-       smp_mb__after_unlock_lock();
+       raw_spin_lock_rcu_node(rnp);            /* irqs already disabled. */
        rnp->qsmaskinitnext |= mask;
        rnp->expmaskinitnext |= mask;
        if (!rdp->beenonline)
@@ -4327,14 +4352,14 @@ static int __init rcu_spawn_gp_kthread(void)
                t = kthread_create(rcu_gp_kthread, rsp, "%s", rsp->name);
                BUG_ON(IS_ERR(t));
                rnp = rcu_get_root(rsp);
-               raw_spin_lock_irqsave(&rnp->lock, flags);
+               raw_spin_lock_irqsave_rcu_node(rnp, flags);
                rsp->gp_kthread = t;
                if (kthread_prio) {
                        sp.sched_priority = kthread_prio;
                        sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
                }
-               wake_up_process(t);
                raw_spin_unlock_irqrestore(&rnp->lock, flags);
+               wake_up_process(t);
        }
        rcu_spawn_nocb_kthreads();
        rcu_spawn_boost_kthreads();
@@ -4385,12 +4410,14 @@ static void __init rcu_init_levelspread(int *levelspread, const int *levelcnt)
 /*
  * Helper function for rcu_init() that initializes one rcu_state structure.
  */
-static void __init rcu_init_one(struct rcu_state *rsp,
-               struct rcu_data __percpu *rda)
+static void __init rcu_init_one(struct rcu_state *rsp)
 {
        static const char * const buf[] = RCU_NODE_NAME_INIT;
        static const char * const fqs[] = RCU_FQS_NAME_INIT;
        static const char * const exp[] = RCU_EXP_NAME_INIT;
+       static struct lock_class_key rcu_node_class[RCU_NUM_LVLS];
+       static struct lock_class_key rcu_fqs_class[RCU_NUM_LVLS];
+       static struct lock_class_key rcu_exp_class[RCU_NUM_LVLS];
        static u8 fl_mask = 0x1;
 
        int levelcnt[RCU_NUM_LVLS];             /* # nodes in each level. */
@@ -4576,8 +4603,8 @@ void __init rcu_init(void)
 
        rcu_bootup_announce();
        rcu_init_geometry();
-       rcu_init_one(&rcu_bh_state, &rcu_bh_data);
-       rcu_init_one(&rcu_sched_state, &rcu_sched_data);
+       rcu_init_one(&rcu_bh_state);
+       rcu_init_one(&rcu_sched_state);
        if (dump_tree)
                rcu_dump_rcu_node_tree(&rcu_sched_state);
        __rcu_init_preempt();
index 9fb4e238d4dcaaed1565dd7bf08a3c71a7f518bf..83360b4f4352786b0129d5ac64046102d73933db 100644 (file)
@@ -178,6 +178,8 @@ struct rcu_node {
                                /*  beginning of each expedited GP. */
        unsigned long expmaskinitnext;
                                /* Online CPUs for next expedited GP. */
+                               /*  Any CPU that has ever been online will */
+                               /*  have its bit set. */
        unsigned long grpmask;  /* Mask to apply to parent qsmask. */
                                /*  Only one bit will be set in this mask. */
        int     grplo;          /* lowest-numbered CPU or group here. */
@@ -384,6 +386,10 @@ struct rcu_data {
        struct rcu_head oom_head;
 #endif /* #ifdef CONFIG_RCU_FAST_NO_HZ */
        struct mutex exp_funnel_mutex;
+       atomic_long_t expedited_workdone0;      /* # done by others #0. */
+       atomic_long_t expedited_workdone1;      /* # done by others #1. */
+       atomic_long_t expedited_workdone2;      /* # done by others #2. */
+       atomic_long_t expedited_workdone3;      /* # done by others #3. */
 
        /* 7) Callback offloading. */
 #ifdef CONFIG_RCU_NOCB_CPU
@@ -498,10 +504,6 @@ struct rcu_state {
        /* End of fields guarded by barrier_mutex. */
 
        unsigned long expedited_sequence;       /* Take a ticket. */
-       atomic_long_t expedited_workdone0;      /* # done by others #0. */
-       atomic_long_t expedited_workdone1;      /* # done by others #1. */
-       atomic_long_t expedited_workdone2;      /* # done by others #2. */
-       atomic_long_t expedited_workdone3;      /* # done by others #3. */
        atomic_long_t expedited_normal;         /* # fallbacks to normal. */
        atomic_t expedited_need_qs;             /* # CPUs left to check in. */
        wait_queue_head_t expedited_wq;         /* Wait for check-ins. */
@@ -545,6 +547,18 @@ struct rcu_state {
 #define RCU_GP_CLEANUP   5     /* Grace-period cleanup started. */
 #define RCU_GP_CLEANED   6     /* Grace-period cleanup complete. */
 
+#ifndef RCU_TREE_NONCORE
+static const char * const gp_state_names[] = {
+       "RCU_GP_IDLE",
+       "RCU_GP_WAIT_GPS",
+       "RCU_GP_DONE_GPS",
+       "RCU_GP_WAIT_FQS",
+       "RCU_GP_DOING_FQS",
+       "RCU_GP_CLEANUP",
+       "RCU_GP_CLEANED",
+};
+#endif /* #ifndef RCU_TREE_NONCORE */
+
 extern struct list_head rcu_struct_flavors;
 
 /* Sequence through rcu_state structures for each RCU flavor. */
@@ -664,3 +678,42 @@ static inline void rcu_nocb_q_lengths(struct rcu_data *rdp, long *ql, long *qll)
 #else /* #ifdef CONFIG_PPC */
 #define smp_mb__after_unlock_lock()    do { } while (0)
 #endif /* #else #ifdef CONFIG_PPC */
+
+/*
+ * Wrappers for the rcu_node::lock acquire.
+ *
+ * Because the rcu_nodes form a tree, the tree traversal locking will observe
+ * different lock values, this in turn means that an UNLOCK of one level
+ * followed by a LOCK of another level does not imply a full memory barrier;
+ * and most importantly transitivity is lost.
+ *
+ * In order to restore full ordering between tree levels, augment the regular
+ * lock acquire functions with smp_mb__after_unlock_lock().
+ */
+static inline void raw_spin_lock_rcu_node(struct rcu_node *rnp)
+{
+       raw_spin_lock(&rnp->lock);
+       smp_mb__after_unlock_lock();
+}
+
+static inline void raw_spin_lock_irq_rcu_node(struct rcu_node *rnp)
+{
+       raw_spin_lock_irq(&rnp->lock);
+       smp_mb__after_unlock_lock();
+}
+
+#define raw_spin_lock_irqsave_rcu_node(rnp, flags)     \
+do {                                                   \
+       typecheck(unsigned long, flags);                \
+       raw_spin_lock_irqsave(&(rnp)->lock, flags);     \
+       smp_mb__after_unlock_lock();                    \
+} while (0)
+
+static inline bool raw_spin_trylock_rcu_node(struct rcu_node *rnp)
+{
+       bool locked = raw_spin_trylock(&rnp->lock);
+
+       if (locked)
+               smp_mb__after_unlock_lock();
+       return locked;
+}
index 630c19772630cc0c2cac42e2cf751dec002e81e2..9467a8b7e756173bc9a94cc5b9828066a9f50e16 100644 (file)
@@ -63,8 +63,7 @@ static bool __read_mostly rcu_nocb_poll;    /* Offload kthread are to poll. */
 
 /*
  * Check the RCU kernel configuration parameters and print informative
- * messages about anything out of the ordinary.  If you like #ifdef, you
- * will love this function.
+ * messages about anything out of the ordinary.
  */
 static void __init rcu_bootup_announce_oddness(void)
 {
@@ -147,8 +146,8 @@ static void __init rcu_bootup_announce(void)
  * the corresponding expedited grace period will also be the end of the
  * normal grace period.
  */
-static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp,
-                                  unsigned long flags) __releases(rnp->lock)
+static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp)
+       __releases(rnp->lock) /* But leaves rrupts disabled. */
 {
        int blkd_state = (rnp->gp_tasks ? RCU_GP_TASKS : 0) +
                         (rnp->exp_tasks ? RCU_EXP_TASKS : 0) +
@@ -236,7 +235,7 @@ static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp,
                rnp->gp_tasks = &t->rcu_node_entry;
        if (!rnp->exp_tasks && (blkd_state & RCU_EXP_BLKD))
                rnp->exp_tasks = &t->rcu_node_entry;
-       raw_spin_unlock(&rnp->lock);
+       raw_spin_unlock(&rnp->lock); /* rrupts remain disabled. */
 
        /*
         * Report the quiescent state for the expedited GP.  This expedited
@@ -251,7 +250,6 @@ static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp,
        } else {
                WARN_ON_ONCE(t->rcu_read_unlock_special.b.exp_need_qs);
        }
-       local_irq_restore(flags);
 }
 
 /*
@@ -286,12 +284,11 @@ static void rcu_preempt_qs(void)
  * predating the current grace period drain, in other words, until
  * rnp->gp_tasks becomes NULL.
  *
- * Caller must disable preemption.
+ * Caller must disable interrupts.
  */
 static void rcu_preempt_note_context_switch(void)
 {
        struct task_struct *t = current;
-       unsigned long flags;
        struct rcu_data *rdp;
        struct rcu_node *rnp;
 
@@ -301,8 +298,7 @@ static void rcu_preempt_note_context_switch(void)
                /* Possibly blocking in an RCU read-side critical section. */
                rdp = this_cpu_ptr(rcu_state_p->rda);
                rnp = rdp->mynode;
-               raw_spin_lock_irqsave(&rnp->lock, flags);
-               smp_mb__after_unlock_lock();
+               raw_spin_lock_rcu_node(rnp);
                t->rcu_read_unlock_special.b.blocked = true;
                t->rcu_blocked_node = rnp;
 
@@ -318,7 +314,7 @@ static void rcu_preempt_note_context_switch(void)
                                       (rnp->qsmask & rdp->grpmask)
                                       ? rnp->gpnum
                                       : rnp->gpnum + 1);
-               rcu_preempt_ctxt_queue(rnp, rdp, flags);
+               rcu_preempt_ctxt_queue(rnp, rdp);
        } else if (t->rcu_read_lock_nesting < 0 &&
                   t->rcu_read_unlock_special.s) {
 
@@ -450,20 +446,13 @@ void rcu_read_unlock_special(struct task_struct *t)
 
                /*
                 * Remove this task from the list it blocked on.  The task
-                * now remains queued on the rcu_node corresponding to
-                * the CPU it first blocked on, so the first attempt to
-                * acquire the task's rcu_node's ->lock will succeed.
-                * Keep the loop and add a WARN_ON() out of sheer paranoia.
+                * now remains queued on the rcu_node corresponding to the
+                * CPU it first blocked on, so there is no longer any need
+                * to loop.  Retain a WARN_ON_ONCE() out of sheer paranoia.
                 */
-               for (;;) {
-                       rnp = t->rcu_blocked_node;
-                       raw_spin_lock(&rnp->lock);  /* irqs already disabled. */
-                       smp_mb__after_unlock_lock();
-                       if (rnp == t->rcu_blocked_node)
-                               break;
-                       WARN_ON_ONCE(1);
-                       raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
-               }
+               rnp = t->rcu_blocked_node;
+               raw_spin_lock_rcu_node(rnp); /* irqs already disabled. */
+               WARN_ON_ONCE(rnp != t->rcu_blocked_node);
                empty_norm = !rcu_preempt_blocked_readers_cgp(rnp);
                empty_exp = sync_rcu_preempt_exp_done(rnp);
                smp_mb(); /* ensure expedited fastpath sees end of RCU c-s. */
@@ -527,7 +516,7 @@ static void rcu_print_detail_task_stall_rnp(struct rcu_node *rnp)
        unsigned long flags;
        struct task_struct *t;
 
-       raw_spin_lock_irqsave(&rnp->lock, flags);
+       raw_spin_lock_irqsave_rcu_node(rnp, flags);
        if (!rcu_preempt_blocked_readers_cgp(rnp)) {
                raw_spin_unlock_irqrestore(&rnp->lock, flags);
                return;
@@ -748,6 +737,12 @@ void synchronize_rcu_expedited(void)
        struct rcu_state *rsp = rcu_state_p;
        unsigned long s;
 
+       /* If expedited grace periods are prohibited, fall back to normal. */
+       if (rcu_gp_is_normal()) {
+               wait_rcu_gp(call_rcu);
+               return;
+       }
+
        s = rcu_exp_gp_seq_snap(rsp);
 
        rnp_unlock = exp_funnel_lock(rsp, s);
@@ -788,7 +783,7 @@ EXPORT_SYMBOL_GPL(rcu_barrier);
  */
 static void __init __rcu_init_preempt(void)
 {
-       rcu_init_one(rcu_state_p, rcu_data_p);
+       rcu_init_one(rcu_state_p);
 }
 
 /*
@@ -989,8 +984,7 @@ static int rcu_boost(struct rcu_node *rnp)
            READ_ONCE(rnp->boost_tasks) == NULL)
                return 0;  /* Nothing left to boost. */
 
-       raw_spin_lock_irqsave(&rnp->lock, flags);
-       smp_mb__after_unlock_lock();
+       raw_spin_lock_irqsave_rcu_node(rnp, flags);
 
        /*
         * Recheck under the lock: all tasks in need of boosting
@@ -1176,8 +1170,7 @@ static int rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
                           "rcub/%d", rnp_index);
        if (IS_ERR(t))
                return PTR_ERR(t);
-       raw_spin_lock_irqsave(&rnp->lock, flags);
-       smp_mb__after_unlock_lock();
+       raw_spin_lock_irqsave_rcu_node(rnp, flags);
        rnp->boost_kthread_task = t;
        raw_spin_unlock_irqrestore(&rnp->lock, flags);
        sp.sched_priority = kthread_prio;
@@ -1524,7 +1517,8 @@ static void rcu_prepare_for_idle(void)
        struct rcu_state *rsp;
        int tne;
 
-       if (IS_ENABLED(CONFIG_RCU_NOCB_CPU_ALL))
+       if (IS_ENABLED(CONFIG_RCU_NOCB_CPU_ALL) ||
+           rcu_is_nocb_cpu(smp_processor_id()))
                return;
 
        /* Handle nohz enablement switches conservatively. */
@@ -1538,10 +1532,6 @@ static void rcu_prepare_for_idle(void)
        if (!tne)
                return;
 
-       /* If this is a no-CBs CPU, no callbacks, just return. */
-       if (rcu_is_nocb_cpu(smp_processor_id()))
-               return;
-
        /*
         * If a non-lazy callback arrived at a CPU having only lazy
         * callbacks, invoke RCU core for the side-effect of recalculating
@@ -1567,8 +1557,7 @@ static void rcu_prepare_for_idle(void)
                if (!*rdp->nxttail[RCU_DONE_TAIL])
                        continue;
                rnp = rdp->mynode;
-               raw_spin_lock(&rnp->lock); /* irqs already disabled. */
-               smp_mb__after_unlock_lock();
+               raw_spin_lock_rcu_node(rnp); /* irqs already disabled. */
                needwake = rcu_accelerate_cbs(rsp, rnp, rdp);
                raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
                if (needwake)
@@ -2068,8 +2057,7 @@ static void rcu_nocb_wait_gp(struct rcu_data *rdp)
        bool needwake;
        struct rcu_node *rnp = rdp->mynode;
 
-       raw_spin_lock_irqsave(&rnp->lock, flags);
-       smp_mb__after_unlock_lock();
+       raw_spin_lock_irqsave_rcu_node(rnp, flags);
        needwake = rcu_start_future_gp(rnp, rdp, &c);
        raw_spin_unlock_irqrestore(&rnp->lock, flags);
        if (needwake)
index ef7093cc9b5cd86c3f9f6c6cff6a33f4e0b62ea8..1088e64f01ad84f98143b95c549bf77ad9c655ab 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Read-Copy Update tracing for classic implementation
+ * Read-Copy Update tracing for hierarchical implementation.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,6 +16,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html.
  *
  * Copyright IBM Corporation, 2008
+ * Author: Paul E. McKenney
  *
  * Papers:  http://www.rdrop.com/users/paulmck/RCU
  *
@@ -33,9 +34,7 @@
 #include <linux/sched.h>
 #include <linux/atomic.h>
 #include <linux/bitops.h>
-#include <linux/module.h>
 #include <linux/completion.h>
-#include <linux/moduleparam.h>
 #include <linux/percpu.h>
 #include <linux/notifier.h>
 #include <linux/cpu.h>
@@ -183,14 +182,20 @@ static const struct file_operations rcudata_fops = {
 
 static int show_rcuexp(struct seq_file *m, void *v)
 {
+       int cpu;
        struct rcu_state *rsp = (struct rcu_state *)m->private;
-
+       struct rcu_data *rdp;
+       unsigned long s0 = 0, s1 = 0, s2 = 0, s3 = 0;
+
+       for_each_possible_cpu(cpu) {
+               rdp = per_cpu_ptr(rsp->rda, cpu);
+               s0 += atomic_long_read(&rdp->expedited_workdone0);
+               s1 += atomic_long_read(&rdp->expedited_workdone1);
+               s2 += atomic_long_read(&rdp->expedited_workdone2);
+               s3 += atomic_long_read(&rdp->expedited_workdone3);
+       }
        seq_printf(m, "s=%lu wd0=%lu wd1=%lu wd2=%lu wd3=%lu n=%lu enq=%d sc=%lu\n",
-                  rsp->expedited_sequence,
-                  atomic_long_read(&rsp->expedited_workdone0),
-                  atomic_long_read(&rsp->expedited_workdone1),
-                  atomic_long_read(&rsp->expedited_workdone2),
-                  atomic_long_read(&rsp->expedited_workdone3),
+                  rsp->expedited_sequence, s0, s1, s2, s3,
                   atomic_long_read(&rsp->expedited_normal),
                   atomic_read(&rsp->expedited_need_qs),
                   rsp->expedited_sequence / 2);
@@ -319,7 +324,7 @@ static void show_one_rcugp(struct seq_file *m, struct rcu_state *rsp)
        unsigned long gpmax;
        struct rcu_node *rnp = &rsp->node[0];
 
-       raw_spin_lock_irqsave(&rnp->lock, flags);
+       raw_spin_lock_irqsave_rcu_node(rnp, flags);
        completed = READ_ONCE(rsp->completed);
        gpnum = READ_ONCE(rsp->gpnum);
        if (completed == gpnum)
@@ -487,16 +492,4 @@ free_out:
        debugfs_remove_recursive(rcudir);
        return 1;
 }
-
-static void __exit rcutree_trace_cleanup(void)
-{
-       debugfs_remove_recursive(rcudir);
-}
-
-
-module_init(rcutree_trace_init);
-module_exit(rcutree_trace_cleanup);
-
-MODULE_AUTHOR("Paul E. McKenney");
-MODULE_DESCRIPTION("Read-Copy Update tracing for hierarchical implementation");
-MODULE_LICENSE("GPL");
+device_initcall(rcutree_trace_init);
index 5f748c5a40f0756b2d6c97fa615cde551649db4a..76b94e19430b21b8f4615b70dbb89282445ca149 100644 (file)
@@ -60,7 +60,12 @@ MODULE_ALIAS("rcupdate");
 #endif
 #define MODULE_PARAM_PREFIX "rcupdate."
 
+#ifndef CONFIG_TINY_RCU
 module_param(rcu_expedited, int, 0);
+module_param(rcu_normal, int, 0);
+static int rcu_normal_after_boot;
+module_param(rcu_normal_after_boot, int, 0);
+#endif /* #ifndef CONFIG_TINY_RCU */
 
 #if defined(CONFIG_DEBUG_LOCK_ALLOC) && defined(CONFIG_PREEMPT_COUNT)
 /**
@@ -113,6 +118,17 @@ EXPORT_SYMBOL(rcu_read_lock_sched_held);
 
 #ifndef CONFIG_TINY_RCU
 
+/*
+ * Should expedited grace-period primitives always fall back to their
+ * non-expedited counterparts?  Intended for use within RCU.  Note
+ * that if the user specifies both rcu_expedited and rcu_normal, then
+ * rcu_normal wins.
+ */
+bool rcu_gp_is_normal(void)
+{
+       return READ_ONCE(rcu_normal);
+}
+
 static atomic_t rcu_expedited_nesting =
        ATOMIC_INIT(IS_ENABLED(CONFIG_RCU_EXPEDITE_BOOT) ? 1 : 0);
 
@@ -157,8 +173,6 @@ void rcu_unexpedite_gp(void)
 }
 EXPORT_SYMBOL_GPL(rcu_unexpedite_gp);
 
-#endif /* #ifndef CONFIG_TINY_RCU */
-
 /*
  * Inform RCU of the end of the in-kernel boot sequence.
  */
@@ -166,8 +180,12 @@ void rcu_end_inkernel_boot(void)
 {
        if (IS_ENABLED(CONFIG_RCU_EXPEDITE_BOOT))
                rcu_unexpedite_gp();
+       if (rcu_normal_after_boot)
+               WRITE_ONCE(rcu_normal, 1);
 }
 
+#endif /* #ifndef CONFIG_TINY_RCU */
+
 #ifdef CONFIG_PREEMPT_RCU
 
 /*
index 750ed601ddf78e6dcdc5f10818c98b34b5feea3a..a5d966cb889175d5b196283341b1cead20f20603 100644 (file)
@@ -212,7 +212,7 @@ int proc_sched_autogroup_set_nice(struct task_struct *p, int nice)
        ag = autogroup_task_get(p);
 
        down_write(&ag->lock);
-       err = sched_group_set_shares(ag->tg, prio_to_weight[nice + 20]);
+       err = sched_group_set_shares(ag->tg, sched_prio_to_weight[nice + 20]);
        if (!err)
                ag->nice = nice;
        up_write(&ag->lock);
index caf4041f5b0ae6769bc562fccc189852eae77fcf..bc54e84675da0d50bd9a60a82f2da5df8590b080 100644 (file)
@@ -354,7 +354,7 @@ void sched_clock_idle_wakeup_event(u64 delta_ns)
                return;
 
        sched_clock_tick();
-       touch_softlockup_watchdog();
+       touch_softlockup_watchdog_sched();
 }
 EXPORT_SYMBOL_GPL(sched_clock_idle_wakeup_event);
 
index 732e993b564b8179e5723bb88839329eec6df8f5..77d97a6fc71515ce83f80e62edfdf726a09a8fc6 100644 (file)
@@ -731,7 +731,7 @@ bool sched_can_stop_tick(void)
        if (current->policy == SCHED_RR) {
                struct sched_rt_entity *rt_se = &current->rt;
 
-               return rt_se->run_list.prev == rt_se->run_list.next;
+               return list_is_singular(&rt_se->run_list);
        }
 
        /*
@@ -823,8 +823,8 @@ static void set_load_weight(struct task_struct *p)
                return;
        }
 
-       load->weight = scale_load(prio_to_weight[prio]);
-       load->inv_weight = prio_to_wmult[prio];
+       load->weight = scale_load(sched_prio_to_weight[prio]);
+       load->inv_weight = sched_prio_to_wmult[prio];
 }
 
 static inline void enqueue_task(struct rq *rq, struct task_struct *p, int flags)
@@ -1071,8 +1071,8 @@ static struct rq *move_queued_task(struct rq *rq, struct task_struct *p, int new
 {
        lockdep_assert_held(&rq->lock);
 
-       dequeue_task(rq, p, 0);
        p->on_rq = TASK_ON_RQ_MIGRATING;
+       dequeue_task(rq, p, 0);
        set_task_cpu(p, new_cpu);
        raw_spin_unlock(&rq->lock);
 
@@ -1080,8 +1080,8 @@ static struct rq *move_queued_task(struct rq *rq, struct task_struct *p, int new
 
        raw_spin_lock(&rq->lock);
        BUG_ON(task_cpu(p) != new_cpu);
-       p->on_rq = TASK_ON_RQ_QUEUED;
        enqueue_task(rq, p, 0);
+       p->on_rq = TASK_ON_RQ_QUEUED;
        check_preempt_curr(rq, p, 0);
 
        return rq;
@@ -1274,6 +1274,15 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
        WARN_ON_ONCE(p->state != TASK_RUNNING && p->state != TASK_WAKING &&
                        !p->on_rq);
 
+       /*
+        * Migrating fair class task must have p->on_rq = TASK_ON_RQ_MIGRATING,
+        * because schedstat_wait_{start,end} rebase migrating task's wait_start
+        * time relying on p->on_rq.
+        */
+       WARN_ON_ONCE(p->state == TASK_RUNNING &&
+                    p->sched_class == &fair_sched_class &&
+                    (p->on_rq && !task_on_rq_migrating(p)));
+
 #ifdef CONFIG_LOCKDEP
        /*
         * The caller should hold either p->pi_lock or rq->lock, when changing
@@ -1310,9 +1319,11 @@ static void __migrate_swap_task(struct task_struct *p, int cpu)
                src_rq = task_rq(p);
                dst_rq = cpu_rq(cpu);
 
+               p->on_rq = TASK_ON_RQ_MIGRATING;
                deactivate_task(src_rq, p, 0);
                set_task_cpu(p, cpu);
                activate_task(dst_rq, p, 0);
+               p->on_rq = TASK_ON_RQ_QUEUED;
                check_preempt_curr(dst_rq, p, 0);
        } else {
                /*
@@ -1905,6 +1916,97 @@ static void ttwu_queue(struct task_struct *p, int cpu)
        raw_spin_unlock(&rq->lock);
 }
 
+/*
+ * Notes on Program-Order guarantees on SMP systems.
+ *
+ *  MIGRATION
+ *
+ * The basic program-order guarantee on SMP systems is that when a task [t]
+ * migrates, all its activity on its old cpu [c0] happens-before any subsequent
+ * execution on its new cpu [c1].
+ *
+ * For migration (of runnable tasks) this is provided by the following means:
+ *
+ *  A) UNLOCK of the rq(c0)->lock scheduling out task t
+ *  B) migration for t is required to synchronize *both* rq(c0)->lock and
+ *     rq(c1)->lock (if not at the same time, then in that order).
+ *  C) LOCK of the rq(c1)->lock scheduling in task
+ *
+ * Transitivity guarantees that B happens after A and C after B.
+ * Note: we only require RCpc transitivity.
+ * Note: the cpu doing B need not be c0 or c1
+ *
+ * Example:
+ *
+ *   CPU0            CPU1            CPU2
+ *
+ *   LOCK rq(0)->lock
+ *   sched-out X
+ *   sched-in Y
+ *   UNLOCK rq(0)->lock
+ *
+ *                                   LOCK rq(0)->lock // orders against CPU0
+ *                                   dequeue X
+ *                                   UNLOCK rq(0)->lock
+ *
+ *                                   LOCK rq(1)->lock
+ *                                   enqueue X
+ *                                   UNLOCK rq(1)->lock
+ *
+ *                   LOCK rq(1)->lock // orders against CPU2
+ *                   sched-out Z
+ *                   sched-in X
+ *                   UNLOCK rq(1)->lock
+ *
+ *
+ *  BLOCKING -- aka. SLEEP + WAKEUP
+ *
+ * For blocking we (obviously) need to provide the same guarantee as for
+ * migration. However the means are completely different as there is no lock
+ * chain to provide order. Instead we do:
+ *
+ *   1) smp_store_release(X->on_cpu, 0)
+ *   2) smp_cond_acquire(!X->on_cpu)
+ *
+ * Example:
+ *
+ *   CPU0 (schedule)  CPU1 (try_to_wake_up) CPU2 (schedule)
+ *
+ *   LOCK rq(0)->lock LOCK X->pi_lock
+ *   dequeue X
+ *   sched-out X
+ *   smp_store_release(X->on_cpu, 0);
+ *
+ *                    smp_cond_acquire(!X->on_cpu);
+ *                    X->state = WAKING
+ *                    set_task_cpu(X,2)
+ *
+ *                    LOCK rq(2)->lock
+ *                    enqueue X
+ *                    X->state = RUNNING
+ *                    UNLOCK rq(2)->lock
+ *
+ *                                          LOCK rq(2)->lock // orders against CPU1
+ *                                          sched-out Z
+ *                                          sched-in X
+ *                                          UNLOCK rq(2)->lock
+ *
+ *                    UNLOCK X->pi_lock
+ *   UNLOCK rq(0)->lock
+ *
+ *
+ * However; for wakeups there is a second guarantee we must provide, namely we
+ * must observe the state that lead to our wakeup. That is, not only must our
+ * task observe its own prior state, it must also observe the stores prior to
+ * its wakeup.
+ *
+ * This means that any means of doing remote wakeups must order the CPU doing
+ * the wakeup against the CPU the task is going to end up running on. This,
+ * however, is already required for the regular Program-Order guarantee above,
+ * since the waking CPU is the one issueing the ACQUIRE (smp_cond_acquire).
+ *
+ */
+
 /**
  * try_to_wake_up - wake up a thread
  * @p: the thread to be awakened
@@ -1968,19 +2070,13 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
        /*
         * If the owning (remote) cpu is still in the middle of schedule() with
         * this task as prev, wait until its done referencing the task.
-        */
-       while (p->on_cpu)
-               cpu_relax();
-       /*
-        * Combined with the control dependency above, we have an effective
-        * smp_load_acquire() without the need for full barriers.
         *
         * Pairs with the smp_store_release() in finish_lock_switch().
         *
         * This ensures that tasks getting woken will be fully ordered against
         * their previous state and preserve Program Order.
         */
-       smp_rmb();
+       smp_cond_acquire(!p->on_cpu);
 
        p->sched_contributes_to_load = !!task_contributes_to_load(p);
        p->state = TASK_WAKING;
@@ -2109,6 +2205,10 @@ static void __sched_fork(unsigned long clone_flags, struct task_struct *p)
        p->se.vruntime                  = 0;
        INIT_LIST_HEAD(&p->se.group_node);
 
+#ifdef CONFIG_FAIR_GROUP_SCHED
+       p->se.cfs_rq                    = NULL;
+#endif
+
 #ifdef CONFIG_SCHEDSTATS
        memset(&p->se.statistics, 0, sizeof(p->se.statistics));
 #endif
@@ -3109,7 +3209,6 @@ static void __sched notrace __schedule(bool preempt)
 
        cpu = smp_processor_id();
        rq = cpu_rq(cpu);
-       rcu_note_context_switch();
        prev = rq->curr;
 
        /*
@@ -3128,13 +3227,16 @@ static void __sched notrace __schedule(bool preempt)
        if (sched_feat(HRTICK))
                hrtick_clear(rq);
 
+       local_irq_disable();
+       rcu_note_context_switch();
+
        /*
         * Make sure that signal_pending_state()->signal_pending() below
         * can't be reordered with __set_current_state(TASK_INTERRUPTIBLE)
         * done by the caller to avoid the race with signal_wake_up().
         */
        smp_mb__before_spinlock();
-       raw_spin_lock_irq(&rq->lock);
+       raw_spin_lock(&rq->lock);
        lockdep_pin_lock(&rq->lock);
 
        rq->clock_skip_update <<= 1; /* promote REQ to ACT */
@@ -7355,6 +7457,9 @@ int in_sched_functions(unsigned long addr)
  */
 struct task_group root_task_group;
 LIST_HEAD(task_groups);
+
+/* Cacheline aligned slab cache for task_group */
+static struct kmem_cache *task_group_cache __read_mostly;
 #endif
 
 DECLARE_PER_CPU(cpumask_var_t, load_balance_mask);
@@ -7412,11 +7517,12 @@ void __init sched_init(void)
 #endif /* CONFIG_RT_GROUP_SCHED */
 
 #ifdef CONFIG_CGROUP_SCHED
+       task_group_cache = KMEM_CACHE(task_group, 0);
+
        list_add(&root_task_group.list, &task_groups);
        INIT_LIST_HEAD(&root_task_group.children);
        INIT_LIST_HEAD(&root_task_group.siblings);
        autogroup_init(&init_task);
-
 #endif /* CONFIG_CGROUP_SCHED */
 
        for_each_possible_cpu(i) {
@@ -7697,7 +7803,7 @@ static void free_sched_group(struct task_group *tg)
        free_fair_sched_group(tg);
        free_rt_sched_group(tg);
        autogroup_free(tg);
-       kfree(tg);
+       kmem_cache_free(task_group_cache, tg);
 }
 
 /* allocate runqueue etc for a new task group */
@@ -7705,7 +7811,7 @@ struct task_group *sched_create_group(struct task_group *parent)
 {
        struct task_group *tg;
 
-       tg = kzalloc(sizeof(*tg), GFP_KERNEL);
+       tg = kmem_cache_alloc(task_group_cache, GFP_KERNEL | __GFP_ZERO);
        if (!tg)
                return ERR_PTR(-ENOMEM);
 
@@ -8610,3 +8716,44 @@ void dump_cpu_task(int cpu)
        pr_info("Task dump for CPU %d:\n", cpu);
        sched_show_task(cpu_curr(cpu));
 }
+
+/*
+ * Nice levels are multiplicative, with a gentle 10% change for every
+ * nice level changed. I.e. when a CPU-bound task goes from nice 0 to
+ * nice 1, it will get ~10% less CPU time than another CPU-bound task
+ * that remained on nice 0.
+ *
+ * The "10% effect" is relative and cumulative: from _any_ nice level,
+ * if you go up 1 level, it's -10% CPU usage, if you go down 1 level
+ * it's +10% CPU usage. (to achieve that we use a multiplier of 1.25.
+ * If a task goes up by ~10% and another task goes down by ~10% then
+ * the relative distance between them is ~25%.)
+ */
+const int sched_prio_to_weight[40] = {
+ /* -20 */     88761,     71755,     56483,     46273,     36291,
+ /* -15 */     29154,     23254,     18705,     14949,     11916,
+ /* -10 */      9548,      7620,      6100,      4904,      3906,
+ /*  -5 */      3121,      2501,      1991,      1586,      1277,
+ /*   0 */      1024,       820,       655,       526,       423,
+ /*   5 */       335,       272,       215,       172,       137,
+ /*  10 */       110,        87,        70,        56,        45,
+ /*  15 */        36,        29,        23,        18,        15,
+};
+
+/*
+ * Inverse (2^32/x) values of the sched_prio_to_weight[] array, precalculated.
+ *
+ * In cases where the weight does not change often, we can use the
+ * precalculated inverse to speed up arithmetics by turning divisions
+ * into multiplications:
+ */
+const u32 sched_prio_to_wmult[40] = {
+ /* -20 */     48388,     59856,     76040,     92818,    118348,
+ /* -15 */    147320,    184698,    229616,    287308,    360437,
+ /* -10 */    449829,    563644,    704093,    875809,   1099582,
+ /*  -5 */   1376151,   1717300,   2157191,   2708050,   3363326,
+ /*   0 */   4194304,   5237765,   6557202,   8165337,  10153587,
+ /*   5 */  12820798,  15790321,  19976592,  24970740,  31350126,
+ /*  10 */  39045157,  49367440,  61356676,  76695844,  95443717,
+ /*  15 */ 119304647, 148102320, 186737708, 238609294, 286331153,
+};
index 05de80b48586e9fa3241c708c7e6fd7c9b6fb24a..b2ab2ffb1adc021de289d3e3c857de60ad2428b6 100644 (file)
@@ -5,6 +5,9 @@
 #include <linux/static_key.h>
 #include <linux/context_tracking.h>
 #include "sched.h"
+#ifdef CONFIG_PARAVIRT
+#include <asm/paravirt.h>
+#endif
 
 
 #ifdef CONFIG_IRQ_TIME_ACCOUNTING
@@ -466,7 +469,7 @@ void account_process_tick(struct task_struct *p, int user_tick)
        cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy);
        struct rq *rq = this_rq();
 
-       if (vtime_accounting_enabled())
+       if (vtime_accounting_cpu_enabled())
                return;
 
        if (sched_clock_irqtime) {
@@ -680,7 +683,7 @@ static cputime_t get_vtime_delta(struct task_struct *tsk)
 {
        unsigned long long delta = vtime_delta(tsk);
 
-       WARN_ON_ONCE(tsk->vtime_snap_whence == VTIME_SLEEPING);
+       WARN_ON_ONCE(tsk->vtime_snap_whence == VTIME_INACTIVE);
        tsk->vtime_snap += delta;
 
        /* CHECKME: always safe to convert nsecs to cputime? */
@@ -696,37 +699,37 @@ static void __vtime_account_system(struct task_struct *tsk)
 
 void vtime_account_system(struct task_struct *tsk)
 {
-       write_seqlock(&tsk->vtime_seqlock);
+       write_seqcount_begin(&tsk->vtime_seqcount);
        __vtime_account_system(tsk);
-       write_sequnlock(&tsk->vtime_seqlock);
+       write_seqcount_end(&tsk->vtime_seqcount);
 }
 
 void vtime_gen_account_irq_exit(struct task_struct *tsk)
 {
-       write_seqlock(&tsk->vtime_seqlock);
+       write_seqcount_begin(&tsk->vtime_seqcount);
        __vtime_account_system(tsk);
        if (context_tracking_in_user())
                tsk->vtime_snap_whence = VTIME_USER;
-       write_sequnlock(&tsk->vtime_seqlock);
+       write_seqcount_end(&tsk->vtime_seqcount);
 }
 
 void vtime_account_user(struct task_struct *tsk)
 {
        cputime_t delta_cpu;
 
-       write_seqlock(&tsk->vtime_seqlock);
+       write_seqcount_begin(&tsk->vtime_seqcount);
        delta_cpu = get_vtime_delta(tsk);
        tsk->vtime_snap_whence = VTIME_SYS;
        account_user_time(tsk, delta_cpu, cputime_to_scaled(delta_cpu));
-       write_sequnlock(&tsk->vtime_seqlock);
+       write_seqcount_end(&tsk->vtime_seqcount);
 }
 
 void vtime_user_enter(struct task_struct *tsk)
 {
-       write_seqlock(&tsk->vtime_seqlock);
+       write_seqcount_begin(&tsk->vtime_seqcount);
        __vtime_account_system(tsk);
        tsk->vtime_snap_whence = VTIME_USER;
-       write_sequnlock(&tsk->vtime_seqlock);
+       write_seqcount_end(&tsk->vtime_seqcount);
 }
 
 void vtime_guest_enter(struct task_struct *tsk)
@@ -738,19 +741,19 @@ void vtime_guest_enter(struct task_struct *tsk)
         * synchronization against the reader (task_gtime())
         * that can thus safely catch up with a tickless delta.
         */
-       write_seqlock(&tsk->vtime_seqlock);
+       write_seqcount_begin(&tsk->vtime_seqcount);
        __vtime_account_system(tsk);
        current->flags |= PF_VCPU;
-       write_sequnlock(&tsk->vtime_seqlock);
+       write_seqcount_end(&tsk->vtime_seqcount);
 }
 EXPORT_SYMBOL_GPL(vtime_guest_enter);
 
 void vtime_guest_exit(struct task_struct *tsk)
 {
-       write_seqlock(&tsk->vtime_seqlock);
+       write_seqcount_begin(&tsk->vtime_seqcount);
        __vtime_account_system(tsk);
        current->flags &= ~PF_VCPU;
-       write_sequnlock(&tsk->vtime_seqlock);
+       write_seqcount_end(&tsk->vtime_seqcount);
 }
 EXPORT_SYMBOL_GPL(vtime_guest_exit);
 
@@ -763,24 +766,26 @@ void vtime_account_idle(struct task_struct *tsk)
 
 void arch_vtime_task_switch(struct task_struct *prev)
 {
-       write_seqlock(&prev->vtime_seqlock);
-       prev->vtime_snap_whence = VTIME_SLEEPING;
-       write_sequnlock(&prev->vtime_seqlock);
+       write_seqcount_begin(&prev->vtime_seqcount);
+       prev->vtime_snap_whence = VTIME_INACTIVE;
+       write_seqcount_end(&prev->vtime_seqcount);
 
-       write_seqlock(&current->vtime_seqlock);
+       write_seqcount_begin(&current->vtime_seqcount);
        current->vtime_snap_whence = VTIME_SYS;
        current->vtime_snap = sched_clock_cpu(smp_processor_id());
-       write_sequnlock(&current->vtime_seqlock);
+       write_seqcount_end(&current->vtime_seqcount);
 }
 
 void vtime_init_idle(struct task_struct *t, int cpu)
 {
        unsigned long flags;
 
-       write_seqlock_irqsave(&t->vtime_seqlock, flags);
+       local_irq_save(flags);
+       write_seqcount_begin(&t->vtime_seqcount);
        t->vtime_snap_whence = VTIME_SYS;
        t->vtime_snap = sched_clock_cpu(cpu);
-       write_sequnlock_irqrestore(&t->vtime_seqlock, flags);
+       write_seqcount_end(&t->vtime_seqcount);
+       local_irq_restore(flags);
 }
 
 cputime_t task_gtime(struct task_struct *t)
@@ -788,17 +793,17 @@ cputime_t task_gtime(struct task_struct *t)
        unsigned int seq;
        cputime_t gtime;
 
-       if (!context_tracking_is_enabled())
+       if (!vtime_accounting_enabled())
                return t->gtime;
 
        do {
-               seq = read_seqbegin(&t->vtime_seqlock);
+               seq = read_seqcount_begin(&t->vtime_seqcount);
 
                gtime = t->gtime;
-               if (t->flags & PF_VCPU)
+               if (t->vtime_snap_whence == VTIME_SYS && t->flags & PF_VCPU)
                        gtime += vtime_delta(t);
 
-       } while (read_seqretry(&t->vtime_seqlock, seq));
+       } while (read_seqcount_retry(&t->vtime_seqcount, seq));
 
        return gtime;
 }
@@ -821,7 +826,7 @@ fetch_task_cputime(struct task_struct *t,
                *udelta = 0;
                *sdelta = 0;
 
-               seq = read_seqbegin(&t->vtime_seqlock);
+               seq = read_seqcount_begin(&t->vtime_seqcount);
 
                if (u_dst)
                        *u_dst = *u_src;
@@ -829,7 +834,7 @@ fetch_task_cputime(struct task_struct *t,
                        *s_dst = *s_src;
 
                /* Task is sleeping, nothing to add */
-               if (t->vtime_snap_whence == VTIME_SLEEPING ||
+               if (t->vtime_snap_whence == VTIME_INACTIVE ||
                    is_idle_task(t))
                        continue;
 
@@ -845,7 +850,7 @@ fetch_task_cputime(struct task_struct *t,
                        if (t->vtime_snap_whence == VTIME_SYS)
                                *sdelta = delta;
                }
-       } while (read_seqretry(&t->vtime_seqlock, seq));
+       } while (read_seqcount_retry(&t->vtime_seqcount, seq));
 }
 
 
@@ -853,6 +858,14 @@ void task_cputime(struct task_struct *t, cputime_t *utime, cputime_t *stime)
 {
        cputime_t udelta, sdelta;
 
+       if (!vtime_accounting_enabled()) {
+               if (utime)
+                       *utime = t->utime;
+               if (stime)
+                       *stime = t->stime;
+               return;
+       }
+
        fetch_task_cputime(t, utime, stime, &t->utime,
                           &t->stime, &udelta, &sdelta);
        if (utime)
@@ -866,6 +879,14 @@ void task_cputime_scaled(struct task_struct *t,
 {
        cputime_t udelta, sdelta;
 
+       if (!vtime_accounting_enabled()) {
+               if (utimescaled)
+                       *utimescaled = t->utimescaled;
+               if (stimescaled)
+                       *stimescaled = t->stimescaled;
+               return;
+       }
+
        fetch_task_cputime(t, utimescaled, stimescaled,
                           &t->utimescaled, &t->stimescaled, &udelta, &sdelta);
        if (utimescaled)
index 8b0a15e285f9121ccd5540fa11eef49c94f017c1..cd64c979d0e1857aceb8f9f4383c507ad5fa6809 100644 (file)
@@ -176,8 +176,10 @@ static void enqueue_pushable_dl_task(struct rq *rq, struct task_struct *p)
                }
        }
 
-       if (leftmost)
+       if (leftmost) {
                dl_rq->pushable_dl_tasks_leftmost = &p->pushable_dl_tasks;
+               dl_rq->earliest_dl.next = p->dl.deadline;
+       }
 
        rb_link_node(&p->pushable_dl_tasks, parent, link);
        rb_insert_color(&p->pushable_dl_tasks, &dl_rq->pushable_dl_tasks_root);
@@ -195,6 +197,10 @@ static void dequeue_pushable_dl_task(struct rq *rq, struct task_struct *p)
 
                next_node = rb_next(&p->pushable_dl_tasks);
                dl_rq->pushable_dl_tasks_leftmost = next_node;
+               if (next_node) {
+                       dl_rq->earliest_dl.next = rb_entry(next_node,
+                               struct task_struct, pushable_dl_tasks)->dl.deadline;
+               }
        }
 
        rb_erase(&p->pushable_dl_tasks, &dl_rq->pushable_dl_tasks_root);
@@ -782,42 +788,14 @@ static void update_curr_dl(struct rq *rq)
 
 #ifdef CONFIG_SMP
 
-static struct task_struct *pick_next_earliest_dl_task(struct rq *rq, int cpu);
-
-static inline u64 next_deadline(struct rq *rq)
-{
-       struct task_struct *next = pick_next_earliest_dl_task(rq, rq->cpu);
-
-       if (next && dl_prio(next->prio))
-               return next->dl.deadline;
-       else
-               return 0;
-}
-
 static void inc_dl_deadline(struct dl_rq *dl_rq, u64 deadline)
 {
        struct rq *rq = rq_of_dl_rq(dl_rq);
 
        if (dl_rq->earliest_dl.curr == 0 ||
            dl_time_before(deadline, dl_rq->earliest_dl.curr)) {
-               /*
-                * If the dl_rq had no -deadline tasks, or if the new task
-                * has shorter deadline than the current one on dl_rq, we
-                * know that the previous earliest becomes our next earliest,
-                * as the new task becomes the earliest itself.
-                */
-               dl_rq->earliest_dl.next = dl_rq->earliest_dl.curr;
                dl_rq->earliest_dl.curr = deadline;
                cpudl_set(&rq->rd->cpudl, rq->cpu, deadline, 1);
-       } else if (dl_rq->earliest_dl.next == 0 ||
-                  dl_time_before(deadline, dl_rq->earliest_dl.next)) {
-               /*
-                * On the other hand, if the new -deadline task has a
-                * a later deadline than the earliest one on dl_rq, but
-                * it is earlier than the next (if any), we must
-                * recompute the next-earliest.
-                */
-               dl_rq->earliest_dl.next = next_deadline(rq);
        }
 }
 
@@ -839,7 +817,6 @@ static void dec_dl_deadline(struct dl_rq *dl_rq, u64 deadline)
 
                entry = rb_entry(leftmost, struct sched_dl_entity, rb_node);
                dl_rq->earliest_dl.curr = entry->deadline;
-               dl_rq->earliest_dl.next = next_deadline(rq);
                cpudl_set(&rq->rd->cpudl, rq->cpu, entry->deadline, 1);
        }
 }
@@ -1274,28 +1251,6 @@ static int pick_dl_task(struct rq *rq, struct task_struct *p, int cpu)
        return 0;
 }
 
-/* Returns the second earliest -deadline task, NULL otherwise */
-static struct task_struct *pick_next_earliest_dl_task(struct rq *rq, int cpu)
-{
-       struct rb_node *next_node = rq->dl.rb_leftmost;
-       struct sched_dl_entity *dl_se;
-       struct task_struct *p = NULL;
-
-next_node:
-       next_node = rb_next(next_node);
-       if (next_node) {
-               dl_se = rb_entry(next_node, struct sched_dl_entity, rb_node);
-               p = dl_task_of(dl_se);
-
-               if (pick_dl_task(rq, p, cpu))
-                       return p;
-
-               goto next_node;
-       }
-
-       return NULL;
-}
-
 /*
  * Return the earliest pushable rq's task, which is suitable to be executed
  * on the CPU, NULL otherwise:
index 90e26b11deaa1ab4b78302605850523a7852720b..1926606ece807361ab02ef51f4864543640e8d8d 100644 (file)
@@ -738,12 +738,56 @@ static void update_curr_fair(struct rq *rq)
        update_curr(cfs_rq_of(&rq->curr->se));
 }
 
+#ifdef CONFIG_SCHEDSTATS
+static inline void
+update_stats_wait_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+       u64 wait_start = rq_clock(rq_of(cfs_rq));
+
+       if (entity_is_task(se) && task_on_rq_migrating(task_of(se)) &&
+           likely(wait_start > se->statistics.wait_start))
+               wait_start -= se->statistics.wait_start;
+
+       se->statistics.wait_start = wait_start;
+}
+
+static void
+update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+       struct task_struct *p;
+       u64 delta = rq_clock(rq_of(cfs_rq)) - se->statistics.wait_start;
+
+       if (entity_is_task(se)) {
+               p = task_of(se);
+               if (task_on_rq_migrating(p)) {
+                       /*
+                        * Preserve migrating task's wait time so wait_start
+                        * time stamp can be adjusted to accumulate wait time
+                        * prior to migration.
+                        */
+                       se->statistics.wait_start = delta;
+                       return;
+               }
+               trace_sched_stat_wait(p, delta);
+       }
+
+       se->statistics.wait_max = max(se->statistics.wait_max, delta);
+       se->statistics.wait_count++;
+       se->statistics.wait_sum += delta;
+       se->statistics.wait_start = 0;
+}
+#else
 static inline void
 update_stats_wait_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-       schedstat_set(se->statistics.wait_start, rq_clock(rq_of(cfs_rq)));
 }
 
+static inline void
+update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+}
+#endif
+
 /*
  * Task is being enqueued - update stats:
  */
@@ -757,23 +801,6 @@ static void update_stats_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se)
                update_stats_wait_start(cfs_rq, se);
 }
 
-static void
-update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-       schedstat_set(se->statistics.wait_max, max(se->statistics.wait_max,
-                       rq_clock(rq_of(cfs_rq)) - se->statistics.wait_start));
-       schedstat_set(se->statistics.wait_count, se->statistics.wait_count + 1);
-       schedstat_set(se->statistics.wait_sum, se->statistics.wait_sum +
-                       rq_clock(rq_of(cfs_rq)) - se->statistics.wait_start);
-#ifdef CONFIG_SCHEDSTATS
-       if (entity_is_task(se)) {
-               trace_sched_stat_wait(task_of(se),
-                       rq_clock(rq_of(cfs_rq)) - se->statistics.wait_start);
-       }
-#endif
-       schedstat_set(se->statistics.wait_start, 0);
-}
-
 static inline void
 update_stats_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
@@ -2155,6 +2182,7 @@ void task_numa_work(struct callback_head *work)
        unsigned long migrate, next_scan, now = jiffies;
        struct task_struct *p = current;
        struct mm_struct *mm = p->mm;
+       u64 runtime = p->se.sum_exec_runtime;
        struct vm_area_struct *vma;
        unsigned long start, end;
        unsigned long nr_pte_updates = 0;
@@ -2277,6 +2305,17 @@ out:
        else
                reset_ptenuma_scan(p);
        up_read(&mm->mmap_sem);
+
+       /*
+        * Make sure tasks use at least 32x as much time to run other code
+        * than they used here, to limit NUMA PTE scanning overhead to 3% max.
+        * Usually update_task_scan_period slows down scanning enough; on an
+        * overloaded system we need to limit overhead on a per task basis.
+        */
+       if (unlikely(p->se.sum_exec_runtime != runtime)) {
+               u64 diff = p->se.sum_exec_runtime - runtime;
+               p->node_stamp += 32 * diff;
+       }
 }
 
 /*
@@ -2670,12 +2709,64 @@ static inline void update_tg_load_avg(struct cfs_rq *cfs_rq, int force)
 {
        long delta = cfs_rq->avg.load_avg - cfs_rq->tg_load_avg_contrib;
 
+       /*
+        * No need to update load_avg for root_task_group as it is not used.
+        */
+       if (cfs_rq->tg == &root_task_group)
+               return;
+
        if (force || abs(delta) > cfs_rq->tg_load_avg_contrib / 64) {
                atomic_long_add(delta, &cfs_rq->tg->load_avg);
                cfs_rq->tg_load_avg_contrib = cfs_rq->avg.load_avg;
        }
 }
 
+/*
+ * Called within set_task_rq() right before setting a task's cpu. The
+ * caller only guarantees p->pi_lock is held; no other assumptions,
+ * including the state of rq->lock, should be made.
+ */
+void set_task_rq_fair(struct sched_entity *se,
+                     struct cfs_rq *prev, struct cfs_rq *next)
+{
+       if (!sched_feat(ATTACH_AGE_LOAD))
+               return;
+
+       /*
+        * We are supposed to update the task to "current" time, then its up to
+        * date and ready to go to new CPU/cfs_rq. But we have difficulty in
+        * getting what current time is, so simply throw away the out-of-date
+        * time. This will result in the wakee task is less decayed, but giving
+        * the wakee more load sounds not bad.
+        */
+       if (se->avg.last_update_time && prev) {
+               u64 p_last_update_time;
+               u64 n_last_update_time;
+
+#ifndef CONFIG_64BIT
+               u64 p_last_update_time_copy;
+               u64 n_last_update_time_copy;
+
+               do {
+                       p_last_update_time_copy = prev->load_last_update_time_copy;
+                       n_last_update_time_copy = next->load_last_update_time_copy;
+
+                       smp_rmb();
+
+                       p_last_update_time = prev->avg.last_update_time;
+                       n_last_update_time = next->avg.last_update_time;
+
+               } while (p_last_update_time != p_last_update_time_copy ||
+                        n_last_update_time != n_last_update_time_copy);
+#else
+               p_last_update_time = prev->avg.last_update_time;
+               n_last_update_time = next->avg.last_update_time;
+#endif
+               __update_load_avg(p_last_update_time, cpu_of(rq_of(prev)),
+                                 &se->avg, 0, 0, NULL);
+               se->avg.last_update_time = n_last_update_time;
+       }
+}
 #else /* CONFIG_FAIR_GROUP_SCHED */
 static inline void update_tg_load_avg(struct cfs_rq *cfs_rq, int force) {}
 #endif /* CONFIG_FAIR_GROUP_SCHED */
@@ -2689,7 +2780,7 @@ static inline int update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq)
        int decayed, removed = 0;
 
        if (atomic_long_read(&cfs_rq->removed_load_avg)) {
-               long r = atomic_long_xchg(&cfs_rq->removed_load_avg, 0);
+               s64 r = atomic_long_xchg(&cfs_rq->removed_load_avg, 0);
                sa->load_avg = max_t(long, sa->load_avg - r, 0);
                sa->load_sum = max_t(s64, sa->load_sum - r * LOAD_AVG_MAX, 0);
                removed = 1;
@@ -2809,48 +2900,48 @@ dequeue_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
                max_t(s64,  cfs_rq->runnable_load_sum - se->avg.load_sum, 0);
 }
 
-/*
- * Task first catches up with cfs_rq, and then subtract
- * itself from the cfs_rq (task must be off the queue now).
- */
-void remove_entity_load_avg(struct sched_entity *se)
-{
-       struct cfs_rq *cfs_rq = cfs_rq_of(se);
-       u64 last_update_time;
-
 #ifndef CONFIG_64BIT
+static inline u64 cfs_rq_last_update_time(struct cfs_rq *cfs_rq)
+{
        u64 last_update_time_copy;
+       u64 last_update_time;
 
        do {
                last_update_time_copy = cfs_rq->load_last_update_time_copy;
                smp_rmb();
                last_update_time = cfs_rq->avg.last_update_time;
        } while (last_update_time != last_update_time_copy);
-#else
-       last_update_time = cfs_rq->avg.last_update_time;
-#endif
 
-       __update_load_avg(last_update_time, cpu_of(rq_of(cfs_rq)), &se->avg, 0, 0, NULL);
-       atomic_long_add(se->avg.load_avg, &cfs_rq->removed_load_avg);
-       atomic_long_add(se->avg.util_avg, &cfs_rq->removed_util_avg);
+       return last_update_time;
 }
-
-/*
- * Update the rq's load with the elapsed running time before entering
- * idle. if the last scheduled task is not a CFS task, idle_enter will
- * be the only way to update the runnable statistic.
- */
-void idle_enter_fair(struct rq *this_rq)
+#else
+static inline u64 cfs_rq_last_update_time(struct cfs_rq *cfs_rq)
 {
+       return cfs_rq->avg.last_update_time;
 }
+#endif
 
 /*
- * Update the rq's load with the elapsed idle time before a task is
- * scheduled. if the newly scheduled task is not a CFS task, idle_exit will
- * be the only way to update the runnable statistic.
+ * Task first catches up with cfs_rq, and then subtract
+ * itself from the cfs_rq (task must be off the queue now).
  */
-void idle_exit_fair(struct rq *this_rq)
+void remove_entity_load_avg(struct sched_entity *se)
 {
+       struct cfs_rq *cfs_rq = cfs_rq_of(se);
+       u64 last_update_time;
+
+       /*
+        * Newly created task or never used group entity should not be removed
+        * from its (source) cfs_rq
+        */
+       if (se->avg.last_update_time == 0)
+               return;
+
+       last_update_time = cfs_rq_last_update_time(cfs_rq);
+
+       __update_load_avg(last_update_time, cpu_of(rq_of(cfs_rq)), &se->avg, 0, 0, NULL);
+       atomic_long_add(se->avg.load_avg, &cfs_rq->removed_load_avg);
+       atomic_long_add(se->avg.util_avg, &cfs_rq->removed_util_avg);
 }
 
 static inline unsigned long cfs_rq_runnable_load_avg(struct cfs_rq *cfs_rq)
@@ -4240,42 +4331,37 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
  */
 
 /*
- * The exact cpuload at various idx values, calculated at every tick would be
- * load = (2^idx - 1) / 2^idx * load + 1 / 2^idx * cur_load
+ * The exact cpuload calculated at every tick would be:
+ *
+ *   load' = (1 - 1/2^i) * load + (1/2^i) * cur_load
  *
- * If a cpu misses updates for n-1 ticks (as it was idle) and update gets called
- * on nth tick when cpu may be busy, then we have:
- * load = ((2^idx - 1) / 2^idx)^(n-1) * load
- * load = (2^idx - 1) / 2^idx) * load + 1 / 2^idx * cur_load
+ * If a cpu misses updates for n ticks (as it was idle) and update gets
+ * called on the n+1-th tick when cpu may be busy, then we have:
+ *
+ *   load_n   = (1 - 1/2^i)^n * load_0
+ *   load_n+1 = (1 - 1/2^i)   * load_n + (1/2^i) * cur_load
  *
  * decay_load_missed() below does efficient calculation of
- * load = ((2^idx - 1) / 2^idx)^(n-1) * load
- * avoiding 0..n-1 loop doing load = ((2^idx - 1) / 2^idx) * load
+ *
+ *   load' = (1 - 1/2^i)^n * load
+ *
+ * Because x^(n+m) := x^n * x^m we can decompose any x^n in power-of-2 factors.
+ * This allows us to precompute the above in said factors, thereby allowing the
+ * reduction of an arbitrary n in O(log_2 n) steps. (See also
+ * fixed_power_int())
  *
  * The calculation is approximated on a 128 point scale.
- * degrade_zero_ticks is the number of ticks after which load at any
- * particular idx is approximated to be zero.
- * degrade_factor is a precomputed table, a row for each load idx.
- * Each column corresponds to degradation factor for a power of two ticks,
- * based on 128 point scale.
- * Example:
- * row 2, col 3 (=12) says that the degradation at load idx 2 after
- * 8 ticks is 12/128 (which is an approximation of exact factor 3^8/4^8).
- *
- * With this power of 2 load factors, we can degrade the load n times
- * by looking at 1 bits in n and doing as many mult/shift instead of
- * n mult/shifts needed by the exact degradation.
  */
 #define DEGRADE_SHIFT          7
-static const unsigned char
-               degrade_zero_ticks[CPU_LOAD_IDX_MAX] = {0, 8, 32, 64, 128};
-static const unsigned char
-               degrade_factor[CPU_LOAD_IDX_MAX][DEGRADE_SHIFT + 1] = {
-                                       {0, 0, 0, 0, 0, 0, 0, 0},
-                                       {64, 32, 8, 0, 0, 0, 0, 0},
-                                       {96, 72, 40, 12, 1, 0, 0},
-                                       {112, 98, 75, 43, 15, 1, 0},
-                                       {120, 112, 98, 76, 45, 16, 2} };
+
+static const u8 degrade_zero_ticks[CPU_LOAD_IDX_MAX] = {0, 8, 32, 64, 128};
+static const u8 degrade_factor[CPU_LOAD_IDX_MAX][DEGRADE_SHIFT + 1] = {
+       {   0,   0,  0,  0,  0,  0, 0, 0 },
+       {  64,  32,  8,  0,  0,  0, 0, 0 },
+       {  96,  72, 40, 12,  1,  0, 0, 0 },
+       { 112,  98, 75, 43, 15,  1, 0, 0 },
+       { 120, 112, 98, 76, 45, 16, 2, 0 }
+};
 
 /*
  * Update cpu_load for any missed ticks, due to tickless idle. The backlog
@@ -4306,14 +4392,46 @@ decay_load_missed(unsigned long load, unsigned long missed_updates, int idx)
        return load;
 }
 
-/*
+/**
+ * __update_cpu_load - update the rq->cpu_load[] statistics
+ * @this_rq: The rq to update statistics for
+ * @this_load: The current load
+ * @pending_updates: The number of missed updates
+ * @active: !0 for NOHZ_FULL
+ *
  * Update rq->cpu_load[] statistics. This function is usually called every
- * scheduler tick (TICK_NSEC). With tickless idle this will not be called
- * every tick. We fix it up based on jiffies.
+ * scheduler tick (TICK_NSEC).
+ *
+ * This function computes a decaying average:
+ *
+ *   load[i]' = (1 - 1/2^i) * load[i] + (1/2^i) * load
+ *
+ * Because of NOHZ it might not get called on every tick which gives need for
+ * the @pending_updates argument.
+ *
+ *   load[i]_n = (1 - 1/2^i) * load[i]_n-1 + (1/2^i) * load_n-1
+ *             = A * load[i]_n-1 + B ; A := (1 - 1/2^i), B := (1/2^i) * load
+ *             = A * (A * load[i]_n-2 + B) + B
+ *             = A * (A * (A * load[i]_n-3 + B) + B) + B
+ *             = A^3 * load[i]_n-3 + (A^2 + A + 1) * B
+ *             = A^n * load[i]_0 + (A^(n-1) + A^(n-2) + ... + 1) * B
+ *             = A^n * load[i]_0 + ((1 - A^n) / (1 - A)) * B
+ *             = (1 - 1/2^i)^n * (load[i]_0 - load) + load
+ *
+ * In the above we've assumed load_n := load, which is true for NOHZ_FULL as
+ * any change in load would have resulted in the tick being turned back on.
+ *
+ * For regular NOHZ, this reduces to:
+ *
+ *   load[i]_n = (1 - 1/2^i)^n * load[i]_0
+ *
+ * see decay_load_misses(). For NOHZ_FULL we get to subtract and add the extra
+ * term. See the @active paramter.
  */
 static void __update_cpu_load(struct rq *this_rq, unsigned long this_load,
-                             unsigned long pending_updates)
+                             unsigned long pending_updates, int active)
 {
+       unsigned long tickless_load = active ? this_rq->cpu_load[0] : 0;
        int i, scale;
 
        this_rq->nr_load_updates++;
@@ -4325,8 +4443,9 @@ static void __update_cpu_load(struct rq *this_rq, unsigned long this_load,
 
                /* scale is effectively 1 << i now, and >> i divides by scale */
 
-               old_load = this_rq->cpu_load[i];
+               old_load = this_rq->cpu_load[i] - tickless_load;
                old_load = decay_load_missed(old_load, pending_updates - 1, i);
+               old_load += tickless_load;
                new_load = this_load;
                /*
                 * Round up the averaging division if load is increasing. This
@@ -4381,16 +4500,17 @@ static void update_idle_cpu_load(struct rq *this_rq)
        pending_updates = curr_jiffies - this_rq->last_load_update_tick;
        this_rq->last_load_update_tick = curr_jiffies;
 
-       __update_cpu_load(this_rq, load, pending_updates);
+       __update_cpu_load(this_rq, load, pending_updates, 0);
 }
 
 /*
  * Called from tick_nohz_idle_exit() -- try and fix up the ticks we missed.
  */
-void update_cpu_load_nohz(void)
+void update_cpu_load_nohz(int active)
 {
        struct rq *this_rq = this_rq();
        unsigned long curr_jiffies = READ_ONCE(jiffies);
+       unsigned long load = active ? weighted_cpuload(cpu_of(this_rq)) : 0;
        unsigned long pending_updates;
 
        if (curr_jiffies == this_rq->last_load_update_tick)
@@ -4401,10 +4521,11 @@ void update_cpu_load_nohz(void)
        if (pending_updates) {
                this_rq->last_load_update_tick = curr_jiffies;
                /*
-                * We were idle, this means load 0, the current load might be
-                * !0 due to remote wakeups and the sort.
+                * In the regular NOHZ case, we were idle, this means load 0.
+                * In the NOHZ_FULL case, we were non-idle, we should consider
+                * its weighted load.
                 */
-               __update_cpu_load(this_rq, 0, pending_updates);
+               __update_cpu_load(this_rq, load, pending_updates, active);
        }
        raw_spin_unlock(&this_rq->lock);
 }
@@ -4420,7 +4541,7 @@ void update_cpu_load_active(struct rq *this_rq)
         * See the mess around update_idle_cpu_load() / update_cpu_load_nohz().
         */
        this_rq->last_load_update_tick = jiffies;
-       __update_cpu_load(this_rq, load, 1);
+       __update_cpu_load(this_rq, load, 1, 1);
 }
 
 /*
@@ -5007,8 +5128,7 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_f
 /*
  * Called immediately before a task is migrated to a new cpu; task_cpu(p) and
  * cfs_rq_of(p) references at time of call are still valid and identify the
- * previous cpu.  However, the caller only guarantees p->pi_lock is held; no
- * other assumptions, including the state of rq->lock, should be made.
+ * previous cpu. The caller guarantees p->pi_lock or task_rq(p)->lock is held.
  */
 static void migrate_task_rq_fair(struct task_struct *p)
 {
@@ -5721,8 +5841,8 @@ static void detach_task(struct task_struct *p, struct lb_env *env)
 {
        lockdep_assert_held(&env->src_rq->lock);
 
-       deactivate_task(env->src_rq, p, 0);
        p->on_rq = TASK_ON_RQ_MIGRATING;
+       deactivate_task(env->src_rq, p, 0);
        set_task_cpu(p, env->dst_cpu);
 }
 
@@ -5855,8 +5975,8 @@ static void attach_task(struct rq *rq, struct task_struct *p)
        lockdep_assert_held(&rq->lock);
 
        BUG_ON(task_rq(p) != rq);
-       p->on_rq = TASK_ON_RQ_QUEUED;
        activate_task(rq, p, 0);
+       p->on_rq = TASK_ON_RQ_QUEUED;
        check_preempt_curr(rq, p, 0);
 }
 
@@ -6302,7 +6422,7 @@ static inline void update_sg_lb_stats(struct lb_env *env,
                        bool *overload)
 {
        unsigned long load;
-       int i;
+       int i, nr_running;
 
        memset(sgs, 0, sizeof(*sgs));
 
@@ -6319,7 +6439,8 @@ static inline void update_sg_lb_stats(struct lb_env *env,
                sgs->group_util += cpu_util(i);
                sgs->sum_nr_running += rq->cfs.h_nr_running;
 
-               if (rq->nr_running > 1)
+               nr_running = rq->nr_running;
+               if (nr_running > 1)
                        *overload = true;
 
 #ifdef CONFIG_NUMA_BALANCING
@@ -6327,7 +6448,10 @@ static inline void update_sg_lb_stats(struct lb_env *env,
                sgs->nr_preferred_running += rq->nr_preferred_running;
 #endif
                sgs->sum_weighted_load += weighted_cpuload(i);
-               if (idle_cpu(i))
+               /*
+                * No need to call idle_cpu() if nr_running is not 0
+                */
+               if (!nr_running && idle_cpu(i))
                        sgs->idle_cpus++;
        }
 
@@ -7248,8 +7372,6 @@ static int idle_balance(struct rq *this_rq)
        int pulled_task = 0;
        u64 curr_cost = 0;
 
-       idle_enter_fair(this_rq);
-
        /*
         * We must set idle_stamp _before_ calling idle_balance(), such that we
         * measure the duration of idle_balance() as idle time.
@@ -7330,10 +7452,8 @@ out:
        if (this_rq->nr_running != this_rq->cfs.h_nr_running)
                pulled_task = -1;
 
-       if (pulled_task) {
-               idle_exit_fair(this_rq);
+       if (pulled_task)
                this_rq->idle_stamp = 0;
-       }
 
        return pulled_task;
 }
index c4ae0f1fdf9bfc13eae3f85afdeeb8c8d60f1079..47ce94931f1b612a589151e3e64210450a006174 100644 (file)
@@ -47,7 +47,6 @@ dequeue_task_idle(struct rq *rq, struct task_struct *p, int flags)
 
 static void put_prev_task_idle(struct rq *rq, struct task_struct *prev)
 {
-       idle_exit_fair(rq);
        rq_last_tick_reset(rq);
 }
 
index b242775bf670e116233862c590915e06132485ca..10f16374df7f3a3f0f3dc0eb281559cacd223311 100644 (file)
@@ -248,7 +248,12 @@ struct task_group {
        unsigned long shares;
 
 #ifdef CONFIG_SMP
-       atomic_long_t load_avg;
+       /*
+        * load_avg can be heavily contended at clock tick time, so put
+        * it in its own cacheline separated from the fields above which
+        * will also be accessed at each tick.
+        */
+       atomic_long_t load_avg ____cacheline_aligned;
 #endif
 #endif
 
@@ -335,7 +340,15 @@ extern void sched_move_task(struct task_struct *tsk);
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
 extern int sched_group_set_shares(struct task_group *tg, unsigned long shares);
-#endif
+
+#ifdef CONFIG_SMP
+extern void set_task_rq_fair(struct sched_entity *se,
+                            struct cfs_rq *prev, struct cfs_rq *next);
+#else /* !CONFIG_SMP */
+static inline void set_task_rq_fair(struct sched_entity *se,
+                            struct cfs_rq *prev, struct cfs_rq *next) { }
+#endif /* CONFIG_SMP */
+#endif /* CONFIG_FAIR_GROUP_SCHED */
 
 #else /* CONFIG_CGROUP_SCHED */
 
@@ -933,6 +946,7 @@ static inline void set_task_rq(struct task_struct *p, unsigned int cpu)
 #endif
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
+       set_task_rq_fair(&p->se, p->se.cfs_rq, tg->cfs_rq[cpu]);
        p->se.cfs_rq = tg->cfs_rq[cpu];
        p->se.parent = tg->se[cpu];
 #endif
@@ -1076,7 +1090,7 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev)
         * In particular, the load of prev->state in finish_task_switch() must
         * happen before this.
         *
-        * Pairs with the control dependency and rmb in try_to_wake_up().
+        * Pairs with the smp_cond_acquire() in try_to_wake_up().
         */
        smp_store_release(&prev->on_cpu, 0);
 #endif
@@ -1113,46 +1127,8 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev)
 #define WEIGHT_IDLEPRIO                3
 #define WMULT_IDLEPRIO         1431655765
 
-/*
- * Nice levels are multiplicative, with a gentle 10% change for every
- * nice level changed. I.e. when a CPU-bound task goes from nice 0 to
- * nice 1, it will get ~10% less CPU time than another CPU-bound task
- * that remained on nice 0.
- *
- * The "10% effect" is relative and cumulative: from _any_ nice level,
- * if you go up 1 level, it's -10% CPU usage, if you go down 1 level
- * it's +10% CPU usage. (to achieve that we use a multiplier of 1.25.
- * If a task goes up by ~10% and another task goes down by ~10% then
- * the relative distance between them is ~25%.)
- */
-static const int prio_to_weight[40] = {
- /* -20 */     88761,     71755,     56483,     46273,     36291,
- /* -15 */     29154,     23254,     18705,     14949,     11916,
- /* -10 */      9548,      7620,      6100,      4904,      3906,
- /*  -5 */      3121,      2501,      1991,      1586,      1277,
- /*   0 */      1024,       820,       655,       526,       423,
- /*   5 */       335,       272,       215,       172,       137,
- /*  10 */       110,        87,        70,        56,        45,
- /*  15 */        36,        29,        23,        18,        15,
-};
-
-/*
- * Inverse (2^32/x) values of the prio_to_weight[] array, precalculated.
- *
- * In cases where the weight does not change often, we can use the
- * precalculated inverse to speed up arithmetics by turning divisions
- * into multiplications:
- */
-static const u32 prio_to_wmult[40] = {
- /* -20 */     48388,     59856,     76040,     92818,    118348,
- /* -15 */    147320,    184698,    229616,    287308,    360437,
- /* -10 */    449829,    563644,    704093,    875809,   1099582,
- /*  -5 */   1376151,   1717300,   2157191,   2708050,   3363326,
- /*   0 */   4194304,   5237765,   6557202,   8165337,  10153587,
- /*   5 */  12820798,  15790321,  19976592,  24970740,  31350126,
- /*  10 */  39045157,  49367440,  61356676,  76695844,  95443717,
- /*  15 */ 119304647, 148102320, 186737708, 238609294, 286331153,
-};
+extern const int sched_prio_to_weight[40];
+extern const u32 sched_prio_to_wmult[40];
 
 #define ENQUEUE_WAKEUP         0x01
 #define ENQUEUE_HEAD           0x02
@@ -1252,16 +1228,8 @@ extern void update_group_capacity(struct sched_domain *sd, int cpu);
 
 extern void trigger_load_balance(struct rq *rq);
 
-extern void idle_enter_fair(struct rq *this_rq);
-extern void idle_exit_fair(struct rq *this_rq);
-
 extern void set_cpus_allowed_common(struct task_struct *p, const struct cpumask *new_mask);
 
-#else
-
-static inline void idle_enter_fair(struct rq *rq) { }
-static inline void idle_exit_fair(struct rq *rq) { }
-
 #endif
 
 #ifdef CONFIG_CPU_IDLE
index a3bbaee77c586e9836567f900012aa5231e94dbd..edb6de4f5908cefc7e9a792adfea5998c4ae9a87 100644 (file)
@@ -28,7 +28,6 @@
  */
 struct cpu_stop_done {
        atomic_t                nr_todo;        /* nr left to execute */
-       bool                    executed;       /* actually executed? */
        int                     ret;            /* collected return value */
        struct completion       completion;     /* fired if nr_todo reaches 0 */
 };
@@ -63,14 +62,10 @@ static void cpu_stop_init_done(struct cpu_stop_done *done, unsigned int nr_todo)
 }
 
 /* signal completion unless @done is NULL */
-static void cpu_stop_signal_done(struct cpu_stop_done *done, bool executed)
+static void cpu_stop_signal_done(struct cpu_stop_done *done)
 {
-       if (done) {
-               if (executed)
-                       done->executed = true;
-               if (atomic_dec_and_test(&done->nr_todo))
-                       complete(&done->completion);
-       }
+       if (atomic_dec_and_test(&done->nr_todo))
+               complete(&done->completion);
 }
 
 static void __cpu_stop_queue_work(struct cpu_stopper *stopper,
@@ -81,17 +76,21 @@ static void __cpu_stop_queue_work(struct cpu_stopper *stopper,
 }
 
 /* queue @work to @stopper.  if offline, @work is completed immediately */
-static void cpu_stop_queue_work(unsigned int cpu, struct cpu_stop_work *work)
+static bool cpu_stop_queue_work(unsigned int cpu, struct cpu_stop_work *work)
 {
        struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu);
        unsigned long flags;
+       bool enabled;
 
        spin_lock_irqsave(&stopper->lock, flags);
-       if (stopper->enabled)
+       enabled = stopper->enabled;
+       if (enabled)
                __cpu_stop_queue_work(stopper, work);
-       else
-               cpu_stop_signal_done(work->done, false);
+       else if (work->done)
+               cpu_stop_signal_done(work->done);
        spin_unlock_irqrestore(&stopper->lock, flags);
+
+       return enabled;
 }
 
 /**
@@ -124,9 +123,10 @@ int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg)
        struct cpu_stop_work work = { .fn = fn, .arg = arg, .done = &done };
 
        cpu_stop_init_done(&done, 1);
-       cpu_stop_queue_work(cpu, &work);
+       if (!cpu_stop_queue_work(cpu, &work))
+               return -ENOENT;
        wait_for_completion(&done.completion);
-       return done.executed ? done.ret : -ENOENT;
+       return done.ret;
 }
 
 /* This controls the threads on each CPU. */
@@ -258,7 +258,6 @@ int stop_two_cpus(unsigned int cpu1, unsigned int cpu2, cpu_stop_fn_t fn, void *
        struct cpu_stop_work work1, work2;
        struct multi_stop_data msdata;
 
-       preempt_disable();
        msdata = (struct multi_stop_data){
                .fn = fn,
                .data = arg,
@@ -277,16 +276,11 @@ int stop_two_cpus(unsigned int cpu1, unsigned int cpu2, cpu_stop_fn_t fn, void *
 
        if (cpu1 > cpu2)
                swap(cpu1, cpu2);
-       if (cpu_stop_queue_two_works(cpu1, &work1, cpu2, &work2)) {
-               preempt_enable();
+       if (cpu_stop_queue_two_works(cpu1, &work1, cpu2, &work2))
                return -ENOENT;
-       }
-
-       preempt_enable();
 
        wait_for_completion(&done.completion);
-
-       return done.executed ? done.ret : -ENOENT;
+       return done.ret;
 }
 
 /**
@@ -302,23 +296,28 @@ int stop_two_cpus(unsigned int cpu1, unsigned int cpu2, cpu_stop_fn_t fn, void *
  *
  * CONTEXT:
  * Don't care.
+ *
+ * RETURNS:
+ * true if cpu_stop_work was queued successfully and @fn will be called,
+ * false otherwise.
  */
-void stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
+bool stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
                        struct cpu_stop_work *work_buf)
 {
        *work_buf = (struct cpu_stop_work){ .fn = fn, .arg = arg, };
-       cpu_stop_queue_work(cpu, work_buf);
+       return cpu_stop_queue_work(cpu, work_buf);
 }
 
 /* static data for stop_cpus */
 static DEFINE_MUTEX(stop_cpus_mutex);
 
-static void queue_stop_cpus_work(const struct cpumask *cpumask,
+static bool queue_stop_cpus_work(const struct cpumask *cpumask,
                                 cpu_stop_fn_t fn, void *arg,
                                 struct cpu_stop_done *done)
 {
        struct cpu_stop_work *work;
        unsigned int cpu;
+       bool queued = false;
 
        /*
         * Disable preemption while queueing to avoid getting
@@ -331,9 +330,12 @@ static void queue_stop_cpus_work(const struct cpumask *cpumask,
                work->fn = fn;
                work->arg = arg;
                work->done = done;
-               cpu_stop_queue_work(cpu, work);
+               if (cpu_stop_queue_work(cpu, work))
+                       queued = true;
        }
        lg_global_unlock(&stop_cpus_lock);
+
+       return queued;
 }
 
 static int __stop_cpus(const struct cpumask *cpumask,
@@ -342,9 +344,10 @@ static int __stop_cpus(const struct cpumask *cpumask,
        struct cpu_stop_done done;
 
        cpu_stop_init_done(&done, cpumask_weight(cpumask));
-       queue_stop_cpus_work(cpumask, fn, arg, &done);
+       if (!queue_stop_cpus_work(cpumask, fn, arg, &done))
+               return -ENOENT;
        wait_for_completion(&done.completion);
-       return done.executed ? done.ret : -ENOENT;
+       return done.ret;
 }
 
 /**
@@ -432,7 +435,6 @@ static void cpu_stopper_thread(unsigned int cpu)
 {
        struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu);
        struct cpu_stop_work *work;
-       int ret;
 
 repeat:
        work = NULL;
@@ -448,23 +450,19 @@ repeat:
                cpu_stop_fn_t fn = work->fn;
                void *arg = work->arg;
                struct cpu_stop_done *done = work->done;
-               char ksym_buf[KSYM_NAME_LEN] __maybe_unused;
-
-               /* cpu stop callbacks are not allowed to sleep */
-               preempt_disable();
+               int ret;
 
+               /* cpu stop callbacks must not sleep, make in_atomic() == T */
+               preempt_count_inc();
                ret = fn(arg);
-               if (ret)
-                       done->ret = ret;
-
-               /* restore preemption and check it's still balanced */
-               preempt_enable();
+               if (done) {
+                       if (ret)
+                               done->ret = ret;
+                       cpu_stop_signal_done(done);
+               }
+               preempt_count_dec();
                WARN_ONCE(preempt_count(),
-                         "cpu_stop: %s(%p) leaked preempt count\n",
-                         kallsyms_lookup((unsigned long)fn, NULL, NULL, NULL,
-                                         ksym_buf), arg);
-
-               cpu_stop_signal_done(done, true);
+                         "cpu_stop: %pf(%p) leaked preempt count\n", fn, arg);
                goto repeat;
        }
 }
index 7fbba635a5499805c316c36e99910f1d96eb6fb6..e840ed867a5d9406e26a8bc13f3e635b0d66cbdd 100644 (file)
@@ -271,11 +271,27 @@ static int alarmtimer_suspend(struct device *dev)
                __pm_wakeup_event(ws, MSEC_PER_SEC);
        return ret;
 }
+
+static int alarmtimer_resume(struct device *dev)
+{
+       struct rtc_device *rtc;
+
+       rtc = alarmtimer_get_rtcdev();
+       if (rtc)
+               rtc_timer_cancel(rtc, &rtctimer);
+       return 0;
+}
+
 #else
 static int alarmtimer_suspend(struct device *dev)
 {
        return 0;
 }
+
+static int alarmtimer_resume(struct device *dev)
+{
+       return 0;
+}
 #endif
 
 static void alarmtimer_freezerset(ktime_t absexp, enum alarmtimer_type type)
@@ -800,6 +816,7 @@ out:
 /* Suspend hook structures */
 static const struct dev_pm_ops alarmtimer_pm_ops = {
        .suspend = alarmtimer_suspend,
+       .resume = alarmtimer_resume,
 };
 
 static struct platform_driver alarmtimer_driver = {
index 1347882d131e11a404b029d83edfb281483b9c9c..664de539299b6ec3c8eb9a1565f02c14ae839379 100644 (file)
@@ -218,8 +218,8 @@ static void clocksource_watchdog(unsigned long data)
 
                /* Check the deviation from the watchdog clocksource. */
                if (abs(cs_nsec - wd_nsec) > WATCHDOG_THRESHOLD) {
-                       pr_warn("timekeeping watchdog: Marking clocksource '%s' as unstable because the skew is too large:\n",
-                               cs->name);
+                       pr_warn("timekeeping watchdog on CPU%d: Marking clocksource '%s' as unstable because the skew is too large:\n",
+                               smp_processor_id(), cs->name);
                        pr_warn("                      '%s' wd_now: %llx wd_last: %llx mask: %llx\n",
                                watchdog->name, wdnow, wdlast, watchdog->mask);
                        pr_warn("                      '%s' cs_now: %llx cs_last: %llx mask: %llx\n",
index 149cc8086aea16bbd811d3af37e187fd08bb366f..36f2ca09aa5e458bf1f31e3ec018e180dcc5b345 100644 (file)
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/rtc.h>
+#include <linux/math64.h>
 
 #include "ntp_internal.h"
+#include "timekeeping_internal.h"
+
 
 /*
  * NTP timekeeping variables:
@@ -70,7 +73,7 @@ static long                   time_esterror = NTP_PHASE_LIMIT;
 static s64                     time_freq;
 
 /* time at last adjustment (secs):                                     */
-static long                    time_reftime;
+static time64_t                time_reftime;
 
 static long                    time_adjust;
 
@@ -297,25 +300,27 @@ static void ntp_update_offset(long offset)
        if (!(time_status & STA_PLL))
                return;
 
-       if (!(time_status & STA_NANO))
+       if (!(time_status & STA_NANO)) {
+               /* Make sure the multiplication below won't overflow */
+               offset = clamp(offset, -USEC_PER_SEC, USEC_PER_SEC);
                offset *= NSEC_PER_USEC;
+       }
 
        /*
         * Scale the phase adjustment and
         * clamp to the operating range.
         */
-       offset = min(offset, MAXPHASE);
-       offset = max(offset, -MAXPHASE);
+       offset = clamp(offset, -MAXPHASE, MAXPHASE);
 
        /*
         * Select how the frequency is to be controlled
         * and in which mode (PLL or FLL).
         */
-       secs = get_seconds() - time_reftime;
+       secs = (long)(__ktime_get_real_seconds() - time_reftime);
        if (unlikely(time_status & STA_FREQHOLD))
                secs = 0;
 
-       time_reftime = get_seconds();
+       time_reftime = __ktime_get_real_seconds();
 
        offset64    = offset;
        freq_adj    = ntp_update_offset_fll(offset64, secs);
@@ -390,10 +395,11 @@ ktime_t ntp_get_next_leap(void)
  *
  * Also handles leap second processing, and returns leap offset
  */
-int second_overflow(unsigned long secs)
+int second_overflow(time64_t secs)
 {
        s64 delta;
        int leap = 0;
+       s32 rem;
 
        /*
         * Leap second processing. If in leap-insert state at the end of the
@@ -404,19 +410,19 @@ int second_overflow(unsigned long secs)
        case TIME_OK:
                if (time_status & STA_INS) {
                        time_state = TIME_INS;
-                       ntp_next_leap_sec = secs + SECS_PER_DAY -
-                                               (secs % SECS_PER_DAY);
+                       div_s64_rem(secs, SECS_PER_DAY, &rem);
+                       ntp_next_leap_sec = secs + SECS_PER_DAY - rem;
                } else if (time_status & STA_DEL) {
                        time_state = TIME_DEL;
-                       ntp_next_leap_sec = secs + SECS_PER_DAY -
-                                                ((secs+1) % SECS_PER_DAY);
+                       div_s64_rem(secs + 1, SECS_PER_DAY, &rem);
+                       ntp_next_leap_sec = secs + SECS_PER_DAY - rem;
                }
                break;
        case TIME_INS:
                if (!(time_status & STA_INS)) {
                        ntp_next_leap_sec = TIME64_MAX;
                        time_state = TIME_OK;
-               } else if (secs % SECS_PER_DAY == 0) {
+               } else if (secs == ntp_next_leap_sec) {
                        leap = -1;
                        time_state = TIME_OOP;
                        printk(KERN_NOTICE
@@ -427,7 +433,7 @@ int second_overflow(unsigned long secs)
                if (!(time_status & STA_DEL)) {
                        ntp_next_leap_sec = TIME64_MAX;
                        time_state = TIME_OK;
-               } else if ((secs + 1) % SECS_PER_DAY == 0) {
+               } else if (secs == ntp_next_leap_sec) {
                        leap = 1;
                        ntp_next_leap_sec = TIME64_MAX;
                        time_state = TIME_WAIT;
@@ -590,7 +596,7 @@ static inline void process_adj_status(struct timex *txc, struct timespec64 *ts)
         * reference time to current time.
         */
        if (!(time_status & STA_PLL) && (txc->status & STA_PLL))
-               time_reftime = get_seconds();
+               time_reftime = __ktime_get_real_seconds();
 
        /* only set allowed bits */
        time_status &= STA_RONLY;
@@ -674,8 +680,14 @@ int ntp_validate_timex(struct timex *txc)
                        return -EINVAL;
        }
 
-       if ((txc->modes & ADJ_SETOFFSET) && (!capable(CAP_SYS_TIME)))
-               return -EPERM;
+       if (txc->modes & ADJ_SETOFFSET) {
+               /* In order to inject time, you gotta be super-user! */
+               if (!capable(CAP_SYS_TIME))
+                       return -EPERM;
+
+               if (!timeval_inject_offset_valid(&txc->time))
+                       return -EINVAL;
+       }
 
        /*
         * Check for potential multiplication overflows that can
index af924470eac04c046e3481750a32833cef9acc13..d8a7c11fa71a51e09063cf807d6f59959a6119ab 100644 (file)
@@ -6,7 +6,7 @@ extern void ntp_clear(void);
 /* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */
 extern u64 ntp_tick_length(void);
 extern ktime_t ntp_get_next_leap(void);
-extern int second_overflow(unsigned long secs);
+extern int second_overflow(time64_t secs);
 extern int ntp_validate_timex(struct timex *);
 extern int __do_adjtimex(struct timex *, struct timespec64 *, s32 *);
 extern void __hardpps(const struct timespec64 *, const struct timespec64 *);
index ce033c7aa2e8f8a179ae4a031c176e1a358a100d..9cff0ab82b635d33d2936697d909724d07767e69 100644 (file)
@@ -69,10 +69,10 @@ static ssize_t posix_clock_read(struct file *fp, char __user *buf,
 static unsigned int posix_clock_poll(struct file *fp, poll_table *wait)
 {
        struct posix_clock *clk = get_posix_clock(fp);
-       int result = 0;
+       unsigned int result = 0;
 
        if (!clk)
-               return -ENODEV;
+               return POLLERR;
 
        if (clk->ops.poll)
                result = clk->ops.poll(clk, fp, wait);
index 7c7ec45159834a1b25576fbed037c9951f3c076f..9cc20af58c76300111f23a007b9fd5ad0c8bd60b 100644 (file)
@@ -143,7 +143,7 @@ static void tick_sched_handle(struct tick_sched *ts, struct pt_regs *regs)
         * when we go busy again does not account too much ticks.
         */
        if (ts->tick_stopped) {
-               touch_softlockup_watchdog();
+               touch_softlockup_watchdog_sched();
                if (is_idle_task(current))
                        ts->idle_jiffies++;
        }
@@ -430,7 +430,7 @@ static void tick_nohz_update_jiffies(ktime_t now)
        tick_do_update_jiffies64(now);
        local_irq_restore(flags);
 
-       touch_softlockup_watchdog();
+       touch_softlockup_watchdog_sched();
 }
 
 /*
@@ -603,15 +603,31 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
 
        /*
         * If the tick is due in the next period, keep it ticking or
-        * restart it proper.
+        * force prod the timer.
         */
        delta = next_tick - basemono;
        if (delta <= (u64)TICK_NSEC) {
                tick.tv64 = 0;
+               /*
+                * We've not stopped the tick yet, and there's a timer in the
+                * next period, so no point in stopping it either, bail.
+                */
                if (!ts->tick_stopped)
                        goto out;
+
+               /*
+                * If, OTOH, we did stop it, but there's a pending (expired)
+                * timer reprogram the timer hardware to fire now.
+                *
+                * We will not restart the tick proper, just prod the timer
+                * hardware into firing an interrupt to process the pending
+                * timers. Just like tick_irq_exit() will not restart the tick
+                * for 'normal' interrupts.
+                *
+                * Only once we exit the idle loop will we re-enable the tick,
+                * see tick_nohz_idle_exit().
+                */
                if (delta == 0) {
-                       /* Tick is stopped, but required now. Enforce it */
                        tick_nohz_restart(ts, now);
                        goto out;
                }
@@ -694,14 +710,14 @@ out:
        return tick;
 }
 
-static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now)
+static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now, int active)
 {
        /* Update jiffies first */
        tick_do_update_jiffies64(now);
-       update_cpu_load_nohz();
+       update_cpu_load_nohz(active);
 
        calc_load_exit_idle();
-       touch_softlockup_watchdog();
+       touch_softlockup_watchdog_sched();
        /*
         * Cancel the scheduled timer and restore the tick
         */
@@ -725,7 +741,7 @@ static void tick_nohz_full_update_tick(struct tick_sched *ts)
        if (can_stop_full_tick())
                tick_nohz_stop_sched_tick(ts, ktime_get(), cpu);
        else if (ts->tick_stopped)
-               tick_nohz_restart_sched_tick(ts, ktime_get());
+               tick_nohz_restart_sched_tick(ts, ktime_get(), 1);
 #endif
 }
 
@@ -875,7 +891,7 @@ static void tick_nohz_account_idle_ticks(struct tick_sched *ts)
 #ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
        unsigned long ticks;
 
-       if (vtime_accounting_enabled())
+       if (vtime_accounting_cpu_enabled())
                return;
        /*
         * We stopped the tick in idle. Update process times would miss the
@@ -916,7 +932,7 @@ void tick_nohz_idle_exit(void)
                tick_nohz_stop_idle(ts, now);
 
        if (ts->tick_stopped) {
-               tick_nohz_restart_sched_tick(ts, now);
+               tick_nohz_restart_sched_tick(ts, now, 0);
                tick_nohz_account_idle_ticks(ts);
        }
 
index d563c19603029bc6c57ac55154f71ed027320276..34b4cedfa80da0de969c12d1551620513f93d02c 100644 (file)
@@ -305,8 +305,7 @@ static inline s64 timekeeping_get_ns(struct tk_read_base *tkr)
 
        delta = timekeeping_get_delta(tkr);
 
-       nsec = delta * tkr->mult + tkr->xtime_nsec;
-       nsec >>= tkr->shift;
+       nsec = (delta * tkr->mult + tkr->xtime_nsec) >> tkr->shift;
 
        /* If arch requires, add in get_arch_timeoffset() */
        return nsec + arch_gettimeoffset();
@@ -846,6 +845,19 @@ time64_t ktime_get_real_seconds(void)
 }
 EXPORT_SYMBOL_GPL(ktime_get_real_seconds);
 
+/**
+ * __ktime_get_real_seconds - The same as ktime_get_real_seconds
+ * but without the sequence counter protect. This internal function
+ * is called just when timekeeping lock is already held.
+ */
+time64_t __ktime_get_real_seconds(void)
+{
+       struct timekeeper *tk = &tk_core.timekeeper;
+
+       return tk->xtime_sec;
+}
+
+
 #ifdef CONFIG_NTP_PPS
 
 /**
@@ -959,7 +971,7 @@ int timekeeping_inject_offset(struct timespec *ts)
        struct timespec64 ts64, tmp;
        int ret = 0;
 
-       if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC)
+       if (!timespec_inject_offset_valid(ts))
                return -EINVAL;
 
        ts64 = timespec_to_timespec64(*ts);
@@ -1592,9 +1604,12 @@ static __always_inline void timekeeping_freqadjust(struct timekeeper *tk,
 {
        s64 interval = tk->cycle_interval;
        s64 xinterval = tk->xtime_interval;
+       u32 base = tk->tkr_mono.clock->mult;
+       u32 max = tk->tkr_mono.clock->maxadj;
+       u32 cur_adj = tk->tkr_mono.mult;
        s64 tick_error;
        bool negative;
-       u32 adj;
+       u32 adj_scale;
 
        /* Remove any current error adj from freq calculation */
        if (tk->ntp_err_mult)
@@ -1613,13 +1628,33 @@ static __always_inline void timekeeping_freqadjust(struct timekeeper *tk,
        /* preserve the direction of correction */
        negative = (tick_error < 0);
 
-       /* Sort out the magnitude of the correction */
+       /* If any adjustment would pass the max, just return */
+       if (negative && (cur_adj - 1) <= (base - max))
+               return;
+       if (!negative && (cur_adj + 1) >= (base + max))
+               return;
+       /*
+        * Sort out the magnitude of the correction, but
+        * avoid making so large a correction that we go
+        * over the max adjustment.
+        */
+       adj_scale = 0;
        tick_error = abs(tick_error);
-       for (adj = 0; tick_error > interval; adj++)
+       while (tick_error > interval) {
+               u32 adj = 1 << (adj_scale + 1);
+
+               /* Check if adjustment gets us within 1 unit from the max */
+               if (negative && (cur_adj - adj) <= (base - max))
+                       break;
+               if (!negative && (cur_adj + adj) >= (base + max))
+                       break;
+
+               adj_scale++;
                tick_error >>= 1;
+       }
 
        /* scale the corrections */
-       timekeeping_apply_adjustment(tk, offset, negative, adj);
+       timekeeping_apply_adjustment(tk, offset, negative, adj_scale);
 }
 
 /*
index 4ea005a7f9dab06f30eacc93b2ef18604a321746..5be76270ec4a8f155574aabe2812f9edefb80aec 100644 (file)
@@ -17,7 +17,11 @@ static inline cycle_t clocksource_delta(cycle_t now, cycle_t last, cycle_t mask)
 {
        cycle_t ret = (now - last) & mask;
 
-       return (s64) ret > 0 ? ret : 0;
+       /*
+        * Prevent time going backwards by checking the MSB of mask in
+        * the result. If set, return 0.
+        */
+       return ret & ~(mask >> 1) ? 0 : ret;
 }
 #else
 static inline cycle_t clocksource_delta(cycle_t now, cycle_t last, cycle_t mask)
@@ -26,4 +30,6 @@ static inline cycle_t clocksource_delta(cycle_t now, cycle_t last, cycle_t mask)
 }
 #endif
 
+extern time64_t __ktime_get_real_seconds(void);
+
 #endif /* _TIMEKEEPING_INTERNAL_H */
index 1c2b28536feb8113a408b2335c38fb0a0c4272e1..060df67dbdd1d038dba8ec35909890f3e892b6d7 100644 (file)
@@ -273,6 +273,7 @@ static const char **find_next(void *v, loff_t *pos)
        if (*pos < last_index + start_index)
                return __start___tracepoint_str + (*pos - last_index);
 
+       start_index += last_index;
        return find_next_mod_format(start_index, v, fmt, pos);
 }
 
index 18f34cf75f741e2a63db6dc6c522dfa2e03d1a54..b3ace6ebbba3934ca52b6e5a6e420183da233fdc 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/smpboot.h>
 #include <linux/sched/rt.h>
 #include <linux/tick.h>
+#include <linux/workqueue.h>
 
 #include <asm/irq_regs.h>
 #include <linux/kvm_para.h>
@@ -225,7 +226,15 @@ static void __touch_watchdog(void)
        __this_cpu_write(watchdog_touch_ts, get_timestamp());
 }
 
-void touch_softlockup_watchdog(void)
+/**
+ * touch_softlockup_watchdog_sched - touch watchdog on scheduler stalls
+ *
+ * Call when the scheduler may have stalled for legitimate reasons
+ * preventing the watchdog task from executing - e.g. the scheduler
+ * entering idle state.  This should only be used for scheduler events.
+ * Use touch_softlockup_watchdog() for everything else.
+ */
+void touch_softlockup_watchdog_sched(void)
 {
        /*
         * Preemption can be enabled.  It doesn't matter which CPU's timestamp
@@ -233,6 +242,12 @@ void touch_softlockup_watchdog(void)
         */
        raw_cpu_write(watchdog_touch_ts, 0);
 }
+
+void touch_softlockup_watchdog(void)
+{
+       touch_softlockup_watchdog_sched();
+       wq_watchdog_touch(raw_smp_processor_id());
+}
 EXPORT_SYMBOL(touch_softlockup_watchdog);
 
 void touch_all_softlockup_watchdogs(void)
@@ -246,6 +261,7 @@ void touch_all_softlockup_watchdogs(void)
         */
        for_each_watchdog_cpu(cpu)
                per_cpu(watchdog_touch_ts, cpu) = 0;
+       wq_watchdog_touch(-1);
 }
 
 #ifdef CONFIG_HARDLOCKUP_DETECTOR
@@ -351,7 +367,7 @@ static void watchdog_overflow_callback(struct perf_event *event,
                        trigger_allbutself_cpu_backtrace();
 
                if (hardlockup_panic)
-                       panic("Hard LOCKUP");
+                       nmi_panic(regs, "Hard LOCKUP");
 
                __this_cpu_write(hard_watchdog_warn, true);
                return;
index c579dbab2e36ab20dd94a5f753a480df17ae28ff..61a0264e28f9b5917c0e8a60bb9668b21e59c4b2 100644 (file)
@@ -148,6 +148,8 @@ struct worker_pool {
        int                     id;             /* I: pool ID */
        unsigned int            flags;          /* X: flags */
 
+       unsigned long           watchdog_ts;    /* L: watchdog timestamp */
+
        struct list_head        worklist;       /* L: list of pending works */
        int                     nr_workers;     /* L: total number of workers */
 
@@ -1083,6 +1085,8 @@ static void pwq_activate_delayed_work(struct work_struct *work)
        struct pool_workqueue *pwq = get_work_pwq(work);
 
        trace_workqueue_activate_work(work);
+       if (list_empty(&pwq->pool->worklist))
+               pwq->pool->watchdog_ts = jiffies;
        move_linked_works(work, &pwq->pool->worklist, NULL);
        __clear_bit(WORK_STRUCT_DELAYED_BIT, work_data_bits(work));
        pwq->nr_active++;
@@ -1385,6 +1389,8 @@ retry:
                trace_workqueue_activate_work(work);
                pwq->nr_active++;
                worklist = &pwq->pool->worklist;
+               if (list_empty(worklist))
+                       pwq->pool->watchdog_ts = jiffies;
        } else {
                work_flags |= WORK_STRUCT_DELAYED;
                worklist = &pwq->delayed_works;
@@ -2157,6 +2163,8 @@ recheck:
                        list_first_entry(&pool->worklist,
                                         struct work_struct, entry);
 
+               pool->watchdog_ts = jiffies;
+
                if (likely(!(*work_data_bits(work) & WORK_STRUCT_LINKED))) {
                        /* optimization path, not strictly necessary */
                        process_one_work(worker, work);
@@ -2240,6 +2248,7 @@ repeat:
                                        struct pool_workqueue, mayday_node);
                struct worker_pool *pool = pwq->pool;
                struct work_struct *work, *n;
+               bool first = true;
 
                __set_current_state(TASK_RUNNING);
                list_del_init(&pwq->mayday_node);
@@ -2256,9 +2265,14 @@ repeat:
                 * process'em.
                 */
                WARN_ON_ONCE(!list_empty(scheduled));
-               list_for_each_entry_safe(work, n, &pool->worklist, entry)
-                       if (get_work_pwq(work) == pwq)
+               list_for_each_entry_safe(work, n, &pool->worklist, entry) {
+                       if (get_work_pwq(work) == pwq) {
+                               if (first)
+                                       pool->watchdog_ts = jiffies;
                                move_linked_works(work, scheduled, &n);
+                       }
+                       first = false;
+               }
 
                if (!list_empty(scheduled)) {
                        process_scheduled_works(rescuer);
@@ -2316,6 +2330,37 @@ repeat:
        goto repeat;
 }
 
+/**
+ * check_flush_dependency - check for flush dependency sanity
+ * @target_wq: workqueue being flushed
+ * @target_work: work item being flushed (NULL for workqueue flushes)
+ *
+ * %current is trying to flush the whole @target_wq or @target_work on it.
+ * If @target_wq doesn't have %WQ_MEM_RECLAIM, verify that %current is not
+ * reclaiming memory or running on a workqueue which doesn't have
+ * %WQ_MEM_RECLAIM as that can break forward-progress guarantee leading to
+ * a deadlock.
+ */
+static void check_flush_dependency(struct workqueue_struct *target_wq,
+                                  struct work_struct *target_work)
+{
+       work_func_t target_func = target_work ? target_work->func : NULL;
+       struct worker *worker;
+
+       if (target_wq->flags & WQ_MEM_RECLAIM)
+               return;
+
+       worker = current_wq_worker();
+
+       WARN_ONCE(current->flags & PF_MEMALLOC,
+                 "workqueue: PF_MEMALLOC task %d(%s) is flushing !WQ_MEM_RECLAIM %s:%pf",
+                 current->pid, current->comm, target_wq->name, target_func);
+       WARN_ONCE(worker && (worker->current_pwq->wq->flags & WQ_MEM_RECLAIM),
+                 "workqueue: WQ_MEM_RECLAIM %s:%pf is flushing !WQ_MEM_RECLAIM %s:%pf",
+                 worker->current_pwq->wq->name, worker->current_func,
+                 target_wq->name, target_func);
+}
+
 struct wq_barrier {
        struct work_struct      work;
        struct completion       done;
@@ -2525,6 +2570,8 @@ void flush_workqueue(struct workqueue_struct *wq)
                list_add_tail(&this_flusher.list, &wq->flusher_overflow);
        }
 
+       check_flush_dependency(wq, NULL);
+
        mutex_unlock(&wq->mutex);
 
        wait_for_completion(&this_flusher.done);
@@ -2697,6 +2744,8 @@ static bool start_flush_work(struct work_struct *work, struct wq_barrier *barr)
                pwq = worker->current_pwq;
        }
 
+       check_flush_dependency(pwq->wq, work);
+
        insert_wq_barrier(pwq, barr, work, worker);
        spin_unlock_irq(&pool->lock);
 
@@ -3069,6 +3118,7 @@ static int init_worker_pool(struct worker_pool *pool)
        pool->cpu = -1;
        pool->node = NUMA_NO_NODE;
        pool->flags |= POOL_DISASSOCIATED;
+       pool->watchdog_ts = jiffies;
        INIT_LIST_HEAD(&pool->worklist);
        INIT_LIST_HEAD(&pool->idle_list);
        hash_init(pool->busy_hash);
@@ -3601,7 +3651,6 @@ static int apply_workqueue_attrs_locked(struct workqueue_struct *wq,
                                        const struct workqueue_attrs *attrs)
 {
        struct apply_wqattrs_ctx *ctx;
-       int ret = -ENOMEM;
 
        /* only unbound workqueues can change attributes */
        if (WARN_ON(!(wq->flags & WQ_UNBOUND)))
@@ -3612,16 +3661,14 @@ static int apply_workqueue_attrs_locked(struct workqueue_struct *wq,
                return -EINVAL;
 
        ctx = apply_wqattrs_prepare(wq, attrs);
+       if (!ctx)
+               return -ENOMEM;
 
        /* the ctx has been prepared successfully, let's commit it */
-       if (ctx) {
-               apply_wqattrs_commit(ctx);
-               ret = 0;
-       }
-
+       apply_wqattrs_commit(ctx);
        apply_wqattrs_cleanup(ctx);
 
-       return ret;
+       return 0;
 }
 
 /**
@@ -4308,7 +4355,9 @@ void show_workqueue_state(void)
 
                pr_info("pool %d:", pool->id);
                pr_cont_pool_info(pool);
-               pr_cont(" workers=%d", pool->nr_workers);
+               pr_cont(" hung=%us workers=%d",
+                       jiffies_to_msecs(jiffies - pool->watchdog_ts) / 1000,
+                       pool->nr_workers);
                if (pool->manager)
                        pr_cont(" manager: %d",
                                task_pid_nr(pool->manager->task));
@@ -5167,6 +5216,154 @@ static void workqueue_sysfs_unregister(struct workqueue_struct *wq)
 static void workqueue_sysfs_unregister(struct workqueue_struct *wq)    { }
 #endif /* CONFIG_SYSFS */
 
+/*
+ * Workqueue watchdog.
+ *
+ * Stall may be caused by various bugs - missing WQ_MEM_RECLAIM, illegal
+ * flush dependency, a concurrency managed work item which stays RUNNING
+ * indefinitely.  Workqueue stalls can be very difficult to debug as the
+ * usual warning mechanisms don't trigger and internal workqueue state is
+ * largely opaque.
+ *
+ * Workqueue watchdog monitors all worker pools periodically and dumps
+ * state if some pools failed to make forward progress for a while where
+ * forward progress is defined as the first item on ->worklist changing.
+ *
+ * This mechanism is controlled through the kernel parameter
+ * "workqueue.watchdog_thresh" which can be updated at runtime through the
+ * corresponding sysfs parameter file.
+ */
+#ifdef CONFIG_WQ_WATCHDOG
+
+static void wq_watchdog_timer_fn(unsigned long data);
+
+static unsigned long wq_watchdog_thresh = 30;
+static struct timer_list wq_watchdog_timer =
+       TIMER_DEFERRED_INITIALIZER(wq_watchdog_timer_fn, 0, 0);
+
+static unsigned long wq_watchdog_touched = INITIAL_JIFFIES;
+static DEFINE_PER_CPU(unsigned long, wq_watchdog_touched_cpu) = INITIAL_JIFFIES;
+
+static void wq_watchdog_reset_touched(void)
+{
+       int cpu;
+
+       wq_watchdog_touched = jiffies;
+       for_each_possible_cpu(cpu)
+               per_cpu(wq_watchdog_touched_cpu, cpu) = jiffies;
+}
+
+static void wq_watchdog_timer_fn(unsigned long data)
+{
+       unsigned long thresh = READ_ONCE(wq_watchdog_thresh) * HZ;
+       bool lockup_detected = false;
+       struct worker_pool *pool;
+       int pi;
+
+       if (!thresh)
+               return;
+
+       rcu_read_lock();
+
+       for_each_pool(pool, pi) {
+               unsigned long pool_ts, touched, ts;
+
+               if (list_empty(&pool->worklist))
+                       continue;
+
+               /* get the latest of pool and touched timestamps */
+               pool_ts = READ_ONCE(pool->watchdog_ts);
+               touched = READ_ONCE(wq_watchdog_touched);
+
+               if (time_after(pool_ts, touched))
+                       ts = pool_ts;
+               else
+                       ts = touched;
+
+               if (pool->cpu >= 0) {
+                       unsigned long cpu_touched =
+                               READ_ONCE(per_cpu(wq_watchdog_touched_cpu,
+                                                 pool->cpu));
+                       if (time_after(cpu_touched, ts))
+                               ts = cpu_touched;
+               }
+
+               /* did we stall? */
+               if (time_after(jiffies, ts + thresh)) {
+                       lockup_detected = true;
+                       pr_emerg("BUG: workqueue lockup - pool");
+                       pr_cont_pool_info(pool);
+                       pr_cont(" stuck for %us!\n",
+                               jiffies_to_msecs(jiffies - pool_ts) / 1000);
+               }
+       }
+
+       rcu_read_unlock();
+
+       if (lockup_detected)
+               show_workqueue_state();
+
+       wq_watchdog_reset_touched();
+       mod_timer(&wq_watchdog_timer, jiffies + thresh);
+}
+
+void wq_watchdog_touch(int cpu)
+{
+       if (cpu >= 0)
+               per_cpu(wq_watchdog_touched_cpu, cpu) = jiffies;
+       else
+               wq_watchdog_touched = jiffies;
+}
+
+static void wq_watchdog_set_thresh(unsigned long thresh)
+{
+       wq_watchdog_thresh = 0;
+       del_timer_sync(&wq_watchdog_timer);
+
+       if (thresh) {
+               wq_watchdog_thresh = thresh;
+               wq_watchdog_reset_touched();
+               mod_timer(&wq_watchdog_timer, jiffies + thresh * HZ);
+       }
+}
+
+static int wq_watchdog_param_set_thresh(const char *val,
+                                       const struct kernel_param *kp)
+{
+       unsigned long thresh;
+       int ret;
+
+       ret = kstrtoul(val, 0, &thresh);
+       if (ret)
+               return ret;
+
+       if (system_wq)
+               wq_watchdog_set_thresh(thresh);
+       else
+               wq_watchdog_thresh = thresh;
+
+       return 0;
+}
+
+static const struct kernel_param_ops wq_watchdog_thresh_ops = {
+       .set    = wq_watchdog_param_set_thresh,
+       .get    = param_get_ulong,
+};
+
+module_param_cb(watchdog_thresh, &wq_watchdog_thresh_ops, &wq_watchdog_thresh,
+               0644);
+
+static void wq_watchdog_init(void)
+{
+       wq_watchdog_set_thresh(wq_watchdog_thresh);
+}
+
+#else  /* CONFIG_WQ_WATCHDOG */
+
+static inline void wq_watchdog_init(void) { }
+
+#endif /* CONFIG_WQ_WATCHDOG */
+
 static void __init wq_numa_init(void)
 {
        cpumask_var_t *tbl;
@@ -5290,6 +5487,9 @@ static int __init init_workqueues(void)
               !system_unbound_wq || !system_freezable_wq ||
               !system_power_efficient_wq ||
               !system_freezable_power_efficient_wq);
+
+       wq_watchdog_init();
+
        return 0;
 }
 early_initcall(init_workqueues);
index 8c15b29d5adc64214880cf7c066fb83349f612aa..c98e93c0a084cb9d78146f14902080da953ac076 100644 (file)
@@ -812,6 +812,17 @@ config BOOTPARAM_HUNG_TASK_PANIC_VALUE
        default 0 if !BOOTPARAM_HUNG_TASK_PANIC
        default 1 if BOOTPARAM_HUNG_TASK_PANIC
 
+config WQ_WATCHDOG
+       bool "Detect Workqueue Stalls"
+       depends on DEBUG_KERNEL
+       help
+         Say Y here to enable stall detection on workqueues.  If a
+         worker pool doesn't make forward progress on a pending work
+         item for over a given amount of time, 30s by default, a
+         warning message is printed along with dump of workqueue
+         state.  This can be configured through kernel parameter
+         "workqueue.watchdog_thresh" and its sysfs counterpart.
+
 endmenu # "Debug lockups and hangs"
 
 config PANIC_ON_OOPS
@@ -1523,8 +1534,7 @@ config FAIL_IO_TIMEOUT
 
 config FAIL_MMC_REQUEST
        bool "Fault-injection capability for MMC IO"
-       select DEBUG_FS
-       depends on FAULT_INJECTION && MMC
+       depends on FAULT_INJECTION_DEBUG_FS && MMC
        help
          Provide fault-injection capability for MMC IO.
          This will make the mmc core return data errors. This is
index 83c33a5bcffb1a33b44bb5872f94f44fe4d05352..d62de8bf022d2534182fa2bcbdf31b4eb142a8a3 100644 (file)
 #include <linux/kernel.h>
 #include <linux/atomic.h>
 
+#ifdef CONFIG_X86
+#include <asm/processor.h>     /* for boot_cpu_has below */
+#endif
+
 #define TEST(bit, op, c_op, val)                               \
 do {                                                           \
        atomic##bit##_set(&v, v0);                              \
@@ -27,6 +31,65 @@ do {                                                         \
                (unsigned long long)r);                         \
 } while (0)
 
+/*
+ * Test for a atomic operation family,
+ * @test should be a macro accepting parameters (bit, op, ...)
+ */
+
+#define FAMILY_TEST(test, bit, op, args...)    \
+do {                                           \
+       test(bit, op, ##args);          \
+       test(bit, op##_acquire, ##args);        \
+       test(bit, op##_release, ##args);        \
+       test(bit, op##_relaxed, ##args);        \
+} while (0)
+
+#define TEST_RETURN(bit, op, c_op, val)                                \
+do {                                                           \
+       atomic##bit##_set(&v, v0);                              \
+       r = v0;                                                 \
+       r c_op val;                                             \
+       BUG_ON(atomic##bit##_##op(val, &v) != r);               \
+       BUG_ON(atomic##bit##_read(&v) != r);                    \
+} while (0)
+
+#define RETURN_FAMILY_TEST(bit, op, c_op, val)                 \
+do {                                                           \
+       FAMILY_TEST(TEST_RETURN, bit, op, c_op, val);           \
+} while (0)
+
+#define TEST_ARGS(bit, op, init, ret, expect, args...)         \
+do {                                                           \
+       atomic##bit##_set(&v, init);                            \
+       BUG_ON(atomic##bit##_##op(&v, ##args) != ret);          \
+       BUG_ON(atomic##bit##_read(&v) != expect);               \
+} while (0)
+
+#define XCHG_FAMILY_TEST(bit, init, new)                               \
+do {                                                                   \
+       FAMILY_TEST(TEST_ARGS, bit, xchg, init, init, new, new);        \
+} while (0)
+
+#define CMPXCHG_FAMILY_TEST(bit, init, new, wrong)                     \
+do {                                                                   \
+       FAMILY_TEST(TEST_ARGS, bit, cmpxchg,                            \
+                       init, init, new, init, new);                    \
+       FAMILY_TEST(TEST_ARGS, bit, cmpxchg,                            \
+                       init, init, init, wrong, new);                  \
+} while (0)
+
+#define INC_RETURN_FAMILY_TEST(bit, i)                 \
+do {                                                   \
+       FAMILY_TEST(TEST_ARGS, bit, inc_return,         \
+                       i, (i) + one, (i) + one);       \
+} while (0)
+
+#define DEC_RETURN_FAMILY_TEST(bit, i)                 \
+do {                                                   \
+       FAMILY_TEST(TEST_ARGS, bit, dec_return,         \
+                       i, (i) - one, (i) - one);       \
+} while (0)
+
 static __init void test_atomic(void)
 {
        int v0 = 0xaaa31337;
@@ -45,6 +108,18 @@ static __init void test_atomic(void)
        TEST(, and, &=, v1);
        TEST(, xor, ^=, v1);
        TEST(, andnot, &= ~, v1);
+
+       RETURN_FAMILY_TEST(, add_return, +=, onestwos);
+       RETURN_FAMILY_TEST(, add_return, +=, -one);
+       RETURN_FAMILY_TEST(, sub_return, -=, onestwos);
+       RETURN_FAMILY_TEST(, sub_return, -=, -one);
+
+       INC_RETURN_FAMILY_TEST(, v0);
+       DEC_RETURN_FAMILY_TEST(, v0);
+
+       XCHG_FAMILY_TEST(, v0, v1);
+       CMPXCHG_FAMILY_TEST(, v0, v1, onestwos);
+
 }
 
 #define INIT(c) do { atomic64_set(&v, c); r = c; } while (0)
@@ -74,59 +149,26 @@ static __init void test_atomic64(void)
        TEST(64, xor, ^=, v1);
        TEST(64, andnot, &= ~, v1);
 
-       INIT(v0);
-       r += onestwos;
-       BUG_ON(atomic64_add_return(onestwos, &v) != r);
-       BUG_ON(v.counter != r);
-
-       INIT(v0);
-       r += -one;
-       BUG_ON(atomic64_add_return(-one, &v) != r);
-       BUG_ON(v.counter != r);
-
-       INIT(v0);
-       r -= onestwos;
-       BUG_ON(atomic64_sub_return(onestwos, &v) != r);
-       BUG_ON(v.counter != r);
-
-       INIT(v0);
-       r -= -one;
-       BUG_ON(atomic64_sub_return(-one, &v) != r);
-       BUG_ON(v.counter != r);
+       RETURN_FAMILY_TEST(64, add_return, +=, onestwos);
+       RETURN_FAMILY_TEST(64, add_return, +=, -one);
+       RETURN_FAMILY_TEST(64, sub_return, -=, onestwos);
+       RETURN_FAMILY_TEST(64, sub_return, -=, -one);
 
        INIT(v0);
        atomic64_inc(&v);
        r += one;
        BUG_ON(v.counter != r);
 
-       INIT(v0);
-       r += one;
-       BUG_ON(atomic64_inc_return(&v) != r);
-       BUG_ON(v.counter != r);
-
        INIT(v0);
        atomic64_dec(&v);
        r -= one;
        BUG_ON(v.counter != r);
 
-       INIT(v0);
-       r -= one;
-       BUG_ON(atomic64_dec_return(&v) != r);
-       BUG_ON(v.counter != r);
+       INC_RETURN_FAMILY_TEST(64, v0);
+       DEC_RETURN_FAMILY_TEST(64, v0);
 
-       INIT(v0);
-       BUG_ON(atomic64_xchg(&v, v1) != v0);
-       r = v1;
-       BUG_ON(v.counter != r);
-
-       INIT(v0);
-       BUG_ON(atomic64_cmpxchg(&v, v0, v1) != v0);
-       r = v1;
-       BUG_ON(v.counter != r);
-
-       INIT(v0);
-       BUG_ON(atomic64_cmpxchg(&v, v2, v1) != v0);
-       BUG_ON(v.counter != r);
+       XCHG_FAMILY_TEST(64, v0, v1);
+       CMPXCHG_FAMILY_TEST(64, v0, v1, v2);
 
        INIT(v0);
        BUG_ON(atomic64_add_unless(&v, one, v0));
index c24c2f7e296fa15e5431ef7dc4a31f8551e37c15..3859bf63561c63936947b007fe3ee20e822509a1 100644 (file)
@@ -37,7 +37,7 @@ void __list_add(struct list_head *new,
        next->prev = new;
        new->next = next;
        new->prev = prev;
-       prev->next = new;
+       WRITE_ONCE(prev->next, new);
 }
 EXPORT_SYMBOL(__list_add);
 
index eb9240c458fad6a0c4a55b5e211ada4e6aace6b0..51282f5797606545330a29e93b3728d843616ea9 100644 (file)
@@ -519,7 +519,8 @@ int rhashtable_walk_init(struct rhashtable *ht, struct rhashtable_iter *iter)
                return -ENOMEM;
 
        spin_lock(&ht->lock);
-       iter->walker->tbl = rht_dereference(ht->tbl, ht);
+       iter->walker->tbl =
+               rcu_dereference_protected(ht->tbl, lockdep_is_held(&ht->lock));
        list_add(&iter->walker->list, &iter->walker->tbl->walkers);
        spin_unlock(&ht->lock);
 
index 3b6380784c285938b369e0a058793011a83242b5..91e32bc8517ffe458f667a19a346ebd16ff2d0aa 100644 (file)
@@ -33,6 +33,7 @@ EXPORT_SYMBOL(contig_page_data);
 unsigned long max_low_pfn;
 unsigned long min_low_pfn;
 unsigned long max_pfn;
+unsigned long long max_possible_pfn;
 
 bootmem_data_t bootmem_node_data[MAX_NUMNODES] __initdata;
 
index d300f1329814ba538b271fafabb0351d3182d639..07ff069fef256055f776803c708754db310d74f2 100644 (file)
@@ -822,6 +822,17 @@ int __init_memblock memblock_mark_mirror(phys_addr_t base, phys_addr_t size)
        return memblock_setclr_flag(base, size, 1, MEMBLOCK_MIRROR);
 }
 
+/**
+ * memblock_mark_nomap - Mark a memory region with flag MEMBLOCK_NOMAP.
+ * @base: the base phys addr of the region
+ * @size: the size of the region
+ *
+ * Return 0 on success, -errno on failure.
+ */
+int __init_memblock memblock_mark_nomap(phys_addr_t base, phys_addr_t size)
+{
+       return memblock_setclr_flag(base, size, 1, MEMBLOCK_NOMAP);
+}
 
 /**
  * __next_reserved_mem_region - next function for for_each_reserved_region()
@@ -913,6 +924,10 @@ void __init_memblock __next_mem_range(u64 *idx, int nid, ulong flags,
                if ((flags & MEMBLOCK_MIRROR) && !memblock_is_mirror(m))
                        continue;
 
+               /* skip nomap memory unless we were asked for it explicitly */
+               if (!(flags & MEMBLOCK_NOMAP) && memblock_is_nomap(m))
+                       continue;
+
                if (!type_b) {
                        if (out_start)
                                *out_start = m_start;
@@ -1022,6 +1037,10 @@ void __init_memblock __next_mem_range_rev(u64 *idx, int nid, ulong flags,
                if ((flags & MEMBLOCK_MIRROR) && !memblock_is_mirror(m))
                        continue;
 
+               /* skip nomap memory unless we were asked for it explicitly */
+               if (!(flags & MEMBLOCK_NOMAP) && memblock_is_nomap(m))
+                       continue;
+
                if (!type_b) {
                        if (out_start)
                                *out_start = m_start;
@@ -1519,6 +1538,15 @@ int __init_memblock memblock_is_memory(phys_addr_t addr)
        return memblock_search(&memblock.memory, addr) != -1;
 }
 
+int __init_memblock memblock_is_map_memory(phys_addr_t addr)
+{
+       int i = memblock_search(&memblock.memory, addr);
+
+       if (i == -1)
+               return false;
+       return !memblock_is_nomap(&memblock.memory.regions[i]);
+}
+
 #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
 int __init_memblock memblock_search_pfn_nid(unsigned long pfn,
                         unsigned long *start_pfn, unsigned long *end_pfn)
index e234c21a5e6cb3d02104da2422548692fda1e881..fc10620967c79d7b8fbbcc0f82fd9804b1562f13 100644 (file)
@@ -903,14 +903,20 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
                if (prev && reclaim->generation != iter->generation)
                        goto out_unlock;
 
-               do {
+               while (1) {
                        pos = READ_ONCE(iter->position);
+                       if (!pos || css_tryget(&pos->css))
+                               break;
                        /*
-                        * A racing update may change the position and
-                        * put the last reference, hence css_tryget(),
-                        * or retry to see the updated position.
+                        * css reference reached zero, so iter->position will
+                        * be cleared by ->css_released. However, we should not
+                        * rely on this happening soon, because ->css_released
+                        * is called from a work queue, and by busy-waiting we
+                        * might block it. So we clear iter->position right
+                        * away.
                         */
-               } while (pos && !css_tryget(&pos->css));
+                       (void)cmpxchg(&iter->position, pos, NULL);
+               }
        }
 
        if (pos)
@@ -956,17 +962,13 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
        }
 
        if (reclaim) {
-               if (cmpxchg(&iter->position, pos, memcg) == pos) {
-                       if (memcg)
-                               css_get(&memcg->css);
-                       if (pos)
-                               css_put(&pos->css);
-               }
-
                /*
-                * pairs with css_tryget when dereferencing iter->position
-                * above.
+                * The position could have already been updated by a competing
+                * thread, so check that the value hasn't changed since we read
+                * it to avoid reclaiming from the same cgroup twice.
                 */
+               (void)cmpxchg(&iter->position, pos, memcg);
+
                if (pos)
                        css_put(&pos->css);
 
@@ -999,6 +1001,28 @@ void mem_cgroup_iter_break(struct mem_cgroup *root,
                css_put(&prev->css);
 }
 
+static void invalidate_reclaim_iterators(struct mem_cgroup *dead_memcg)
+{
+       struct mem_cgroup *memcg = dead_memcg;
+       struct mem_cgroup_reclaim_iter *iter;
+       struct mem_cgroup_per_zone *mz;
+       int nid, zid;
+       int i;
+
+       while ((memcg = parent_mem_cgroup(memcg))) {
+               for_each_node(nid) {
+                       for (zid = 0; zid < MAX_NR_ZONES; zid++) {
+                               mz = &memcg->nodeinfo[nid]->zoneinfo[zid];
+                               for (i = 0; i <= DEF_PRIORITY; i++) {
+                                       iter = &mz->iter[i];
+                                       cmpxchg(&iter->position,
+                                               dead_memcg, NULL);
+                               }
+                       }
+               }
+       }
+}
+
 /*
  * Iteration constructs for visiting all cgroups (under a tree).  If
  * loops are exited prematurely (break), mem_cgroup_iter_break() must
@@ -4324,6 +4348,13 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
        wb_memcg_offline(memcg);
 }
 
+static void mem_cgroup_css_released(struct cgroup_subsys_state *css)
+{
+       struct mem_cgroup *memcg = mem_cgroup_from_css(css);
+
+       invalidate_reclaim_iterators(memcg);
+}
+
 static void mem_cgroup_css_free(struct cgroup_subsys_state *css)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_css(css);
@@ -5185,6 +5216,7 @@ struct cgroup_subsys memory_cgrp_subsys = {
        .css_alloc = mem_cgroup_css_alloc,
        .css_online = mem_cgroup_css_online,
        .css_offline = mem_cgroup_css_offline,
+       .css_released = mem_cgroup_css_released,
        .css_free = mem_cgroup_css_free,
        .css_reset = mem_cgroup_css_reset,
        .can_attach = mem_cgroup_can_attach,
index 67d488ab495e57b9018484932e135078c787903c..a042a9d537bb31984d6b2a8d3cc8ae1e54361e4f 100644 (file)
@@ -1375,23 +1375,30 @@ int is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages)
  */
 int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn)
 {
-       unsigned long pfn;
+       unsigned long pfn, sec_end_pfn;
        struct zone *zone = NULL;
        struct page *page;
        int i;
-       for (pfn = start_pfn;
+       for (pfn = start_pfn, sec_end_pfn = SECTION_ALIGN_UP(start_pfn);
             pfn < end_pfn;
-            pfn += MAX_ORDER_NR_PAGES) {
-               i = 0;
-               /* This is just a CONFIG_HOLES_IN_ZONE check.*/
-               while ((i < MAX_ORDER_NR_PAGES) && !pfn_valid_within(pfn + i))
-                       i++;
-               if (i == MAX_ORDER_NR_PAGES)
+            pfn = sec_end_pfn + 1, sec_end_pfn += PAGES_PER_SECTION) {
+               /* Make sure the memory section is present first */
+               if (!present_section_nr(pfn_to_section_nr(pfn)))
                        continue;
-               page = pfn_to_page(pfn + i);
-               if (zone && page_zone(page) != zone)
-                       return 0;
-               zone = page_zone(page);
+               for (; pfn < sec_end_pfn && pfn < end_pfn;
+                    pfn += MAX_ORDER_NR_PAGES) {
+                       i = 0;
+                       /* This is just a CONFIG_HOLES_IN_ZONE check.*/
+                       while ((i < MAX_ORDER_NR_PAGES) &&
+                               !pfn_valid_within(pfn + i))
+                               i++;
+                       if (i == MAX_ORDER_NR_PAGES)
+                               continue;
+                       page = pfn_to_page(pfn + i);
+                       if (zone && page_zone(page) != zone)
+                               return 0;
+                       zone = page_zone(page);
+               }
        }
        return 1;
 }
index c25bc6268e46506dba0320d15bb5c2e7d3e079f3..de824e72c3e89a915c429455501c644d1ae22d6e 100644 (file)
@@ -319,6 +319,10 @@ static unsigned long move_vma(struct vm_area_struct *vma,
        hiwater_vm = mm->hiwater_vm;
        vm_stat_account(mm, vma->vm_flags, vma->vm_file, new_len>>PAGE_SHIFT);
 
+       /* Tell pfnmap has moved from this vma */
+       if (unlikely(vma->vm_flags & VM_PFNMAP))
+               untrack_pfn_moved(vma);
+
        if (do_munmap(mm, old_addr, old_len) < 0) {
                /* OOM: unable to split vma, just get accounts right */
                vm_unacct_memory(excess >> PAGE_SHIFT);
index e57cf24babd671c0757eaf320673777774a0658c..99feb2b07fc541a9e79ea92018f7aeadf14d68a9 100644 (file)
@@ -31,6 +31,7 @@ EXPORT_SYMBOL(contig_page_data);
 unsigned long max_low_pfn;
 unsigned long min_low_pfn;
 unsigned long max_pfn;
+unsigned long long max_possible_pfn;
 
 static void * __init __alloc_memory_core_early(int nid, u64 size, u64 align,
                                        u64 goal, u64 limit)
index 2afcdbbdb68506096d5c6fad584a8425709d10aa..5813b7fa85b64667c7ea7f9c73da84e073b6d325 100644 (file)
@@ -2438,7 +2438,6 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
        int len;
        struct inode *inode;
        struct page *page;
-       char *kaddr;
        struct shmem_inode_info *info;
 
        len = strlen(symname) + 1;
@@ -2477,9 +2476,8 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
                }
                inode->i_mapping->a_ops = &shmem_aops;
                inode->i_op = &shmem_symlink_inode_operations;
-               kaddr = kmap_atomic(page);
-               memcpy(kaddr, symname, len);
-               kunmap_atomic(kaddr);
+               inode_nohighmem(inode);
+               memcpy(page_address(page), symname, len);
                SetPageUptodate(page);
                set_page_dirty(page);
                unlock_page(page);
@@ -2492,23 +2490,34 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
        return 0;
 }
 
-static const char *shmem_follow_link(struct dentry *dentry, void **cookie)
+static void shmem_put_link(void *arg)
 {
-       struct page *page = NULL;
-       int error = shmem_getpage(d_inode(dentry), 0, &page, SGP_READ, NULL);
-       if (error)
-               return ERR_PTR(error);
-       unlock_page(page);
-       *cookie = page;
-       return kmap(page);
+       mark_page_accessed(arg);
+       put_page(arg);
 }
 
-static void shmem_put_link(struct inode *unused, void *cookie)
+static const char *shmem_get_link(struct dentry *dentry,
+                                 struct inode *inode,
+                                 struct delayed_call *done)
 {
-       struct page *page = cookie;
-       kunmap(page);
-       mark_page_accessed(page);
-       page_cache_release(page);
+       struct page *page = NULL;
+       int error;
+       if (!dentry) {
+               page = find_get_page(inode->i_mapping, 0);
+               if (!page)
+                       return ERR_PTR(-ECHILD);
+               if (!PageUptodate(page)) {
+                       put_page(page);
+                       return ERR_PTR(-ECHILD);
+               }
+       } else {
+               error = shmem_getpage(inode, 0, &page, SGP_READ, NULL);
+               if (error)
+                       return ERR_PTR(error);
+               unlock_page(page);
+       }
+       set_delayed_call(done, shmem_put_link, page);
+       return page_address(page);
 }
 
 #ifdef CONFIG_TMPFS_XATTR
@@ -2555,122 +2564,74 @@ static int shmem_initxattrs(struct inode *inode,
        return 0;
 }
 
-static const struct xattr_handler *shmem_xattr_handlers[] = {
-#ifdef CONFIG_TMPFS_POSIX_ACL
-       &posix_acl_access_xattr_handler,
-       &posix_acl_default_xattr_handler,
-#endif
-       NULL
-};
-
-static int shmem_xattr_validate(const char *name)
-{
-       struct { const char *prefix; size_t len; } arr[] = {
-               { XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN },
-               { XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN }
-       };
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(arr); i++) {
-               size_t preflen = arr[i].len;
-               if (strncmp(name, arr[i].prefix, preflen) == 0) {
-                       if (!name[preflen])
-                               return -EINVAL;
-                       return 0;
-               }
-       }
-       return -EOPNOTSUPP;
-}
-
-static ssize_t shmem_getxattr(struct dentry *dentry, const char *name,
-                             void *buffer, size_t size)
+static int shmem_xattr_handler_get(const struct xattr_handler *handler,
+                                  struct dentry *dentry, const char *name,
+                                  void *buffer, size_t size)
 {
        struct shmem_inode_info *info = SHMEM_I(d_inode(dentry));
-       int err;
-
-       /*
-        * If this is a request for a synthetic attribute in the system.*
-        * namespace use the generic infrastructure to resolve a handler
-        * for it via sb->s_xattr.
-        */
-       if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
-               return generic_getxattr(dentry, name, buffer, size);
-
-       err = shmem_xattr_validate(name);
-       if (err)
-               return err;
 
+       name = xattr_full_name(handler, name);
        return simple_xattr_get(&info->xattrs, name, buffer, size);
 }
 
-static int shmem_setxattr(struct dentry *dentry, const char *name,
-                         const void *value, size_t size, int flags)
+static int shmem_xattr_handler_set(const struct xattr_handler *handler,
+                                  struct dentry *dentry, const char *name,
+                                  const void *value, size_t size, int flags)
 {
        struct shmem_inode_info *info = SHMEM_I(d_inode(dentry));
-       int err;
-
-       /*
-        * If this is a request for a synthetic attribute in the system.*
-        * namespace use the generic infrastructure to resolve a handler
-        * for it via sb->s_xattr.
-        */
-       if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
-               return generic_setxattr(dentry, name, value, size, flags);
-
-       err = shmem_xattr_validate(name);
-       if (err)
-               return err;
 
+       name = xattr_full_name(handler, name);
        return simple_xattr_set(&info->xattrs, name, value, size, flags);
 }
 
-static int shmem_removexattr(struct dentry *dentry, const char *name)
-{
-       struct shmem_inode_info *info = SHMEM_I(d_inode(dentry));
-       int err;
-
-       /*
-        * If this is a request for a synthetic attribute in the system.*
-        * namespace use the generic infrastructure to resolve a handler
-        * for it via sb->s_xattr.
-        */
-       if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
-               return generic_removexattr(dentry, name);
+static const struct xattr_handler shmem_security_xattr_handler = {
+       .prefix = XATTR_SECURITY_PREFIX,
+       .get = shmem_xattr_handler_get,
+       .set = shmem_xattr_handler_set,
+};
 
-       err = shmem_xattr_validate(name);
-       if (err)
-               return err;
+static const struct xattr_handler shmem_trusted_xattr_handler = {
+       .prefix = XATTR_TRUSTED_PREFIX,
+       .get = shmem_xattr_handler_get,
+       .set = shmem_xattr_handler_set,
+};
 
-       return simple_xattr_remove(&info->xattrs, name);
-}
+static const struct xattr_handler *shmem_xattr_handlers[] = {
+#ifdef CONFIG_TMPFS_POSIX_ACL
+       &posix_acl_access_xattr_handler,
+       &posix_acl_default_xattr_handler,
+#endif
+       &shmem_security_xattr_handler,
+       &shmem_trusted_xattr_handler,
+       NULL
+};
 
 static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size)
 {
        struct shmem_inode_info *info = SHMEM_I(d_inode(dentry));
-       return simple_xattr_list(&info->xattrs, buffer, size);
+       return simple_xattr_list(d_inode(dentry), &info->xattrs, buffer, size);
 }
 #endif /* CONFIG_TMPFS_XATTR */
 
 static const struct inode_operations shmem_short_symlink_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = simple_follow_link,
+       .get_link       = simple_get_link,
 #ifdef CONFIG_TMPFS_XATTR
-       .setxattr       = shmem_setxattr,
-       .getxattr       = shmem_getxattr,
+       .setxattr       = generic_setxattr,
+       .getxattr       = generic_getxattr,
        .listxattr      = shmem_listxattr,
-       .removexattr    = shmem_removexattr,
+       .removexattr    = generic_removexattr,
 #endif
 };
 
 static const struct inode_operations shmem_symlink_inode_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = shmem_follow_link,
-       .put_link       = shmem_put_link,
+       .get_link       = shmem_get_link,
 #ifdef CONFIG_TMPFS_XATTR
-       .setxattr       = shmem_setxattr,
-       .getxattr       = shmem_getxattr,
+       .setxattr       = generic_setxattr,
+       .getxattr       = generic_getxattr,
        .listxattr      = shmem_listxattr,
-       .removexattr    = shmem_removexattr,
+       .removexattr    = generic_removexattr,
 #endif
 };
 
@@ -3142,10 +3103,10 @@ static const struct inode_operations shmem_inode_operations = {
        .getattr        = shmem_getattr,
        .setattr        = shmem_setattr,
 #ifdef CONFIG_TMPFS_XATTR
-       .setxattr       = shmem_setxattr,
-       .getxattr       = shmem_getxattr,
+       .setxattr       = generic_setxattr,
+       .getxattr       = generic_getxattr,
        .listxattr      = shmem_listxattr,
-       .removexattr    = shmem_removexattr,
+       .removexattr    = generic_removexattr,
        .set_acl        = simple_set_acl,
 #endif
 };
@@ -3164,10 +3125,10 @@ static const struct inode_operations shmem_dir_inode_operations = {
        .tmpfile        = shmem_tmpfile,
 #endif
 #ifdef CONFIG_TMPFS_XATTR
-       .setxattr       = shmem_setxattr,
-       .getxattr       = shmem_getxattr,
+       .setxattr       = generic_setxattr,
+       .getxattr       = generic_getxattr,
        .listxattr      = shmem_listxattr,
-       .removexattr    = shmem_removexattr,
+       .removexattr    = generic_removexattr,
 #endif
 #ifdef CONFIG_TMPFS_POSIX_ACL
        .setattr        = shmem_setattr,
@@ -3177,10 +3138,10 @@ static const struct inode_operations shmem_dir_inode_operations = {
 
 static const struct inode_operations shmem_special_inode_operations = {
 #ifdef CONFIG_TMPFS_XATTR
-       .setxattr       = shmem_setxattr,
-       .getxattr       = shmem_getxattr,
+       .setxattr       = generic_setxattr,
+       .getxattr       = generic_getxattr,
        .listxattr      = shmem_listxattr,
-       .removexattr    = shmem_removexattr,
+       .removexattr    = generic_removexattr,
 #endif
 #ifdef CONFIG_TMPFS_POSIX_ACL
        .setattr        = shmem_setattr,
index 0d5712b0206c7edb1236284fe71b7d926df29cee..c54fd2924f25af960462e474fa3583c633f9fcc8 100644 (file)
@@ -219,7 +219,7 @@ void set_pgdat_percpu_threshold(pg_data_t *pgdat,
  * particular counter cannot be updated from interrupt context.
  */
 void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
-                               int delta)
+                          long delta)
 {
        struct per_cpu_pageset __percpu *pcp = zone->pageset;
        s8 __percpu *p = pcp->vm_stat_diff + item;
@@ -318,8 +318,8 @@ EXPORT_SYMBOL(__dec_zone_page_state);
  *     1       Overstepping half of threshold
  *     -1      Overstepping minus half of threshold
 */
-static inline void mod_state(struct zone *zone,
-       enum zone_stat_item item, int delta, int overstep_mode)
+static inline void mod_state(struct zone *zone, enum zone_stat_item item,
+                            long delta, int overstep_mode)
 {
        struct per_cpu_pageset __percpu *pcp = zone->pageset;
        s8 __percpu *p = pcp->vm_stat_diff + item;
@@ -357,7 +357,7 @@ static inline void mod_state(struct zone *zone,
 }
 
 void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
-                                       int delta)
+                        long delta)
 {
        mod_state(zone, item, delta, 0);
 }
@@ -384,7 +384,7 @@ EXPORT_SYMBOL(dec_zone_page_state);
  * Use interrupt disable to serialize counter updates
  */
 void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
-                                       int delta)
+                        long delta)
 {
        unsigned long flags;
 
@@ -1483,6 +1483,7 @@ static void __init start_shepherd_timer(void)
                BUG();
        cpumask_copy(cpu_stat_off, cpu_online_mask);
 
+       vmstat_wq = alloc_workqueue("vmstat", WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
        schedule_delayed_work(&shepherd,
                round_jiffies_relative(sysctl_stat_interval));
 }
@@ -1550,7 +1551,6 @@ static int __init setup_vmstat(void)
 
        start_shepherd_timer();
        cpu_notifier_register_done();
-       vmstat_wq = alloc_workqueue("vmstat", WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
 #endif
 #ifdef CONFIG_PROC_FS
        proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations);
index 5396ff08af3215d1a532b853c8859fb64dfc6a1f..8a7ada8bb947f5129375e549c22af5a5b32c5a99 100644 (file)
@@ -39,7 +39,7 @@ void br_init_port(struct net_bridge_port *p)
        struct switchdev_attr attr = {
                .id = SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME,
                .flags = SWITCHDEV_F_SKIP_EOPNOTSUPP | SWITCHDEV_F_DEFER,
-               .u.ageing_time = p->br->ageing_time,
+               .u.ageing_time = jiffies_to_clock_t(p->br->ageing_time),
        };
        int err;
 
@@ -142,7 +142,10 @@ static void br_stp_start(struct net_bridge *br)
        char *envp[] = { NULL };
        struct net_bridge_port *p;
 
-       r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC);
+       if (net_eq(dev_net(br->dev), &init_net))
+               r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC);
+       else
+               r = -ENOENT;
 
        spin_lock_bh(&br->lock);
 
index e6dc77252fe9fa3e401529426079f094c9f6f999..a1656e3b8d72a66ff56656284205129ecfd30b3e 100644 (file)
@@ -301,12 +301,13 @@ void dst_release(struct dst_entry *dst)
 {
        if (dst) {
                int newrefcnt;
+               unsigned short nocache = dst->flags & DST_NOCACHE;
 
                newrefcnt = atomic_dec_return(&dst->__refcnt);
                if (unlikely(newrefcnt < 0))
                        net_warn_ratelimited("%s: dst:%p refcnt:%d\n",
                                             __func__, dst, newrefcnt);
-               if (!newrefcnt && unlikely(dst->flags & DST_NOCACHE))
+               if (!newrefcnt && unlikely(nocache))
                        call_rcu(&dst->rcu_head, dst_destroy_rcu);
        }
 }
index f34c31defafe083fcc9146affff5c39745150d04..a09fb0dec725a8827ba5d1e928597c103d1f9322 100644 (file)
@@ -253,9 +253,6 @@ ipip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 
        p.i_key = p.o_key = 0;
        p.i_flags = p.o_flags = 0;
-       if (p.iph.ttl)
-               p.iph.frag_off |= htons(IP_DF);
-
        err = ip_tunnel_ioctl(dev, &p, cmd);
        if (err)
                return err;
index 63e5be0abd86ddab6476221161c48aacef34d8c4..bc35f1842512bef8e4d87e76542d7bf11f8946fa 100644 (file)
@@ -601,8 +601,11 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
                            (inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0),
                           daddr, saddr, 0, 0);
 
-       if (!saddr && ipc.oif)
-               l3mdev_get_saddr(net, ipc.oif, &fl4);
+       if (!saddr && ipc.oif) {
+               err = l3mdev_get_saddr(net, ipc.oif, &fl4);
+               if (err < 0)
+                       goto done;
+       }
 
        if (!inet->hdrincl) {
                rfv.msg = msg;
index 2d656eef7f8e16458127ba591e0a4154365f6a83..d4c51158470f5afb7cee8a5c875b5f9ed5b04e14 100644 (file)
@@ -2478,6 +2478,9 @@ static void tcp_cwnd_reduction(struct sock *sk, const int prior_unsacked,
        int newly_acked_sacked = prior_unsacked -
                                 (tp->packets_out - tp->sacked_out);
 
+       if (newly_acked_sacked <= 0 || WARN_ON_ONCE(!tp->prior_cwnd))
+               return;
+
        tp->prr_delivered += newly_acked_sacked;
        if (delta < 0) {
                u64 dividend = (u64)tp->snd_ssthresh * tp->prr_delivered +
index 0c7b0e61b917158af7e431f9e7781f7bce313c83..c43890848641948b1e9c55244614ac9a48756753 100644 (file)
@@ -1025,8 +1025,11 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
                                   flow_flags,
                                   faddr, saddr, dport, inet->inet_sport);
 
-               if (!saddr && ipc.oif)
-                       l3mdev_get_saddr(net, ipc.oif, fl4);
+               if (!saddr && ipc.oif) {
+                       err = l3mdev_get_saddr(net, ipc.oif, fl4);
+                       if (err < 0)
+                               goto out;
+               }
 
                security_sk_classify_flow(sk, flowi4_to_flowi(fl4));
                rt = ip_route_output_flow(net, fl4, sk);
index 1e0c3c835a6349eedca54e2dff191ed56b437613..7b0edb37a1150427ef3b0d9a7f2be11421ef67b0 100644 (file)
@@ -259,7 +259,7 @@ static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
        xfrm_dst_ifdown(dst, dev);
 }
 
-static struct dst_ops xfrm4_dst_ops = {
+static struct dst_ops xfrm4_dst_ops_template = {
        .family =               AF_INET,
        .gc =                   xfrm4_garbage_collect,
        .update_pmtu =          xfrm4_update_pmtu,
@@ -273,7 +273,7 @@ static struct dst_ops xfrm4_dst_ops = {
 
 static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
        .family =               AF_INET,
-       .dst_ops =              &xfrm4_dst_ops,
+       .dst_ops =              &xfrm4_dst_ops_template,
        .dst_lookup =           xfrm4_dst_lookup,
        .get_saddr =            xfrm4_get_saddr,
        .decode_session =       _decode_session4,
@@ -295,7 +295,7 @@ static struct ctl_table xfrm4_policy_table[] = {
        { }
 };
 
-static int __net_init xfrm4_net_init(struct net *net)
+static int __net_init xfrm4_net_sysctl_init(struct net *net)
 {
        struct ctl_table *table;
        struct ctl_table_header *hdr;
@@ -323,7 +323,7 @@ err_alloc:
        return -ENOMEM;
 }
 
-static void __net_exit xfrm4_net_exit(struct net *net)
+static void __net_exit xfrm4_net_sysctl_exit(struct net *net)
 {
        struct ctl_table *table;
 
@@ -335,12 +335,44 @@ static void __net_exit xfrm4_net_exit(struct net *net)
        if (!net_eq(net, &init_net))
                kfree(table);
 }
+#else /* CONFIG_SYSCTL */
+static int inline xfrm4_net_sysctl_init(struct net *net)
+{
+       return 0;
+}
+
+static void inline xfrm4_net_sysctl_exit(struct net *net)
+{
+}
+#endif
+
+static int __net_init xfrm4_net_init(struct net *net)
+{
+       int ret;
+
+       memcpy(&net->xfrm.xfrm4_dst_ops, &xfrm4_dst_ops_template,
+              sizeof(xfrm4_dst_ops_template));
+       ret = dst_entries_init(&net->xfrm.xfrm4_dst_ops);
+       if (ret)
+               return ret;
+
+       ret = xfrm4_net_sysctl_init(net);
+       if (ret)
+               dst_entries_destroy(&net->xfrm.xfrm4_dst_ops);
+
+       return ret;
+}
+
+static void __net_exit xfrm4_net_exit(struct net *net)
+{
+       xfrm4_net_sysctl_exit(net);
+       dst_entries_destroy(&net->xfrm.xfrm4_dst_ops);
+}
 
 static struct pernet_operations __net_initdata xfrm4_net_ops = {
        .init   = xfrm4_net_init,
        .exit   = xfrm4_net_exit,
 };
-#endif
 
 static void __init xfrm4_policy_init(void)
 {
@@ -349,13 +381,9 @@ static void __init xfrm4_policy_init(void)
 
 void __init xfrm4_init(void)
 {
-       dst_entries_init(&xfrm4_dst_ops);
-
        xfrm4_state_init();
        xfrm4_policy_init();
        xfrm4_protocol_init();
-#ifdef CONFIG_SYSCTL
        register_pernet_subsys(&xfrm4_net_ops);
-#endif
 }
 
index 17f8e7ea133b49801f49791c5f9c1968e8584e88..1f21087accab258e5be6cc104f8b8ced13fedd6d 100644 (file)
@@ -5369,13 +5369,10 @@ static int addrconf_sysctl_stable_secret(struct ctl_table *ctl, int write,
                goto out;
        }
 
-       if (!write) {
-               err = snprintf(str, sizeof(str), "%pI6",
-                              &secret->secret);
-               if (err >= sizeof(str)) {
-                       err = -EIO;
-                       goto out;
-               }
+       err = snprintf(str, sizeof(str), "%pI6", &secret->secret);
+       if (err >= sizeof(str)) {
+               err = -EIO;
+               goto out;
        }
 
        err = proc_dostring(&lctl, write, buffer, lenp, ppos);
index 882124ebb438bd033765c4284ddf7ada9834d39d..a8f6986dcbe5ea5a36a3cc6fcf51becebb50c33b 100644 (file)
@@ -552,7 +552,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr *nlh)
 
        rcu_read_lock();
        p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index);
-       if (p && ip6addrlbl_hold(p))
+       if (p && !ip6addrlbl_hold(p))
                p = NULL;
        lseq = ip6addrlbl_table.seq;
        rcu_read_unlock();
index d6161e1c48c86f4a5dfa5cedc89d4b93f8e3d24a..84afb9a7727848038b51ee7a60eebb28d555f693 100644 (file)
@@ -1183,7 +1183,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
         */
        if (!in6_dev->cnf.accept_ra_from_local &&
            ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
-                         NULL, 0)) {
+                         in6_dev->dev, 0)) {
                ND_PRINTK(2, info,
                          "RA from local address detected on dev: %s: default router ignored\n",
                          skb->dev->name);
@@ -1337,7 +1337,7 @@ skip_linkparms:
 #ifdef CONFIG_IPV6_ROUTE_INFO
        if (!in6_dev->cnf.accept_ra_from_local &&
            ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
-                         NULL, 0)) {
+                         in6_dev->dev, 0)) {
                ND_PRINTK(2, info,
                          "RA from local address detected on dev: %s: router info ignored.\n",
                          skb->dev->name);
index 5643423fe67a238c05aee5398ac4064a77bafc16..c074771a10f761253f99611de8294172bdb0e142 100644 (file)
@@ -279,7 +279,7 @@ static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
        xfrm_dst_ifdown(dst, dev);
 }
 
-static struct dst_ops xfrm6_dst_ops = {
+static struct dst_ops xfrm6_dst_ops_template = {
        .family =               AF_INET6,
        .gc =                   xfrm6_garbage_collect,
        .update_pmtu =          xfrm6_update_pmtu,
@@ -293,7 +293,7 @@ static struct dst_ops xfrm6_dst_ops = {
 
 static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
        .family =               AF_INET6,
-       .dst_ops =              &xfrm6_dst_ops,
+       .dst_ops =              &xfrm6_dst_ops_template,
        .dst_lookup =           xfrm6_dst_lookup,
        .get_saddr =            xfrm6_get_saddr,
        .decode_session =       _decode_session6,
@@ -325,7 +325,7 @@ static struct ctl_table xfrm6_policy_table[] = {
        { }
 };
 
-static int __net_init xfrm6_net_init(struct net *net)
+static int __net_init xfrm6_net_sysctl_init(struct net *net)
 {
        struct ctl_table *table;
        struct ctl_table_header *hdr;
@@ -353,7 +353,7 @@ err_alloc:
        return -ENOMEM;
 }
 
-static void __net_exit xfrm6_net_exit(struct net *net)
+static void __net_exit xfrm6_net_sysctl_exit(struct net *net)
 {
        struct ctl_table *table;
 
@@ -365,24 +365,52 @@ static void __net_exit xfrm6_net_exit(struct net *net)
        if (!net_eq(net, &init_net))
                kfree(table);
 }
+#else /* CONFIG_SYSCTL */
+static int inline xfrm6_net_sysctl_init(struct net *net)
+{
+       return 0;
+}
+
+static void inline xfrm6_net_sysctl_exit(struct net *net)
+{
+}
+#endif
+
+static int __net_init xfrm6_net_init(struct net *net)
+{
+       int ret;
+
+       memcpy(&net->xfrm.xfrm6_dst_ops, &xfrm6_dst_ops_template,
+              sizeof(xfrm6_dst_ops_template));
+       ret = dst_entries_init(&net->xfrm.xfrm6_dst_ops);
+       if (ret)
+               return ret;
+
+       ret = xfrm6_net_sysctl_init(net);
+       if (ret)
+               dst_entries_destroy(&net->xfrm.xfrm6_dst_ops);
+
+       return ret;
+}
+
+static void __net_exit xfrm6_net_exit(struct net *net)
+{
+       xfrm6_net_sysctl_exit(net);
+       dst_entries_destroy(&net->xfrm.xfrm6_dst_ops);
+}
 
 static struct pernet_operations xfrm6_net_ops = {
        .init   = xfrm6_net_init,
        .exit   = xfrm6_net_exit,
 };
-#endif
 
 int __init xfrm6_init(void)
 {
        int ret;
 
-       dst_entries_init(&xfrm6_dst_ops);
-
        ret = xfrm6_policy_init();
-       if (ret) {
-               dst_entries_destroy(&xfrm6_dst_ops);
+       if (ret)
                goto out;
-       }
        ret = xfrm6_state_init();
        if (ret)
                goto out_policy;
@@ -391,9 +419,7 @@ int __init xfrm6_init(void)
        if (ret)
                goto out_state;
 
-#ifdef CONFIG_SYSCTL
        register_pernet_subsys(&xfrm6_net_ops);
-#endif
 out:
        return ret;
 out_state:
@@ -405,11 +431,8 @@ out_policy:
 
 void xfrm6_fini(void)
 {
-#ifdef CONFIG_SYSCTL
        unregister_pernet_subsys(&xfrm6_net_ops);
-#endif
        xfrm6_protocol_fini();
        xfrm6_policy_fini();
        xfrm6_state_fini();
-       dst_entries_destroy(&xfrm6_dst_ops);
 }
index 7b9c053ba75072276ee9227ea8d1e67ce3307715..edb3502f20161cf53d44e3fe84d9f0c63072be6a 100644 (file)
@@ -94,7 +94,7 @@ nft_do_chain_netdev(void *priv, struct sk_buff *skb,
 {
        struct nft_pktinfo pkt;
 
-       switch (eth_hdr(skb)->h_proto) {
+       switch (skb->protocol) {
        case htons(ETH_P_IP):
                nft_netdev_set_pktinfo_ipv4(&pkt, skb, state);
                break;
index 8cbca3432f90324f8a28df2bd67da88cdaf72b12..939921532764acdd61a4d33c352abd2b8e1d4756 100644 (file)
@@ -366,6 +366,7 @@ static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr)
                goto nla_put_failure;
 
        switch (priv->key) {
+       case NFT_CT_L3PROTOCOL:
        case NFT_CT_PROTOCOL:
        case NFT_CT_SRC:
        case NFT_CT_DST:
index 3e8892216f948f54afb75fde76bf2b1fa7b754ca..e004067ec24ac448467c0bd5a552eea019975e56 100644 (file)
@@ -698,6 +698,10 @@ int ovs_ct_copy_action(struct net *net, const struct nlattr *attr,
                OVS_NLERR(log, "Failed to allocate conntrack template");
                return -ENOMEM;
        }
+
+       __set_bit(IPS_CONFIRMED_BIT, &ct_info.ct->status);
+       nf_conntrack_get(&ct_info.ct->ct_general);
+
        if (helper) {
                err = ovs_ct_add_helper(&ct_info, helper, key, log);
                if (err)
@@ -709,8 +713,6 @@ int ovs_ct_copy_action(struct net *net, const struct nlattr *attr,
        if (err)
                goto err_free_ct;
 
-       __set_bit(IPS_CONFIRMED_BIT, &ct_info.ct->status);
-       nf_conntrack_get(&ct_info.ct->ct_general);
        return 0;
 err_free_ct:
        __ovs_ct_free_action(&ct_info);
index 907d6fd28ede695cc1b876570c101883ed0b4b0e..d1bd4a45ca2d64eca6439335d967aa21feff2b8b 100644 (file)
@@ -2434,7 +2434,10 @@ static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb)
                if (!start)
                        return -EMSGSIZE;
 
-               err = ovs_nla_put_tunnel_info(skb, tun_info);
+               err =  ip_tun_to_nlattr(skb, &tun_info->key,
+                                       ip_tunnel_info_opts(tun_info),
+                                       tun_info->options_len,
+                                       ip_tunnel_info_af(tun_info));
                if (err)
                        return err;
                nla_nest_end(skb, start);
index e82a1ad80aa521291fba4e704bb3828e88a009db..16bc83b2842a74616cd58dd923a5981942321f3e 100644 (file)
@@ -658,8 +658,10 @@ static void qdisc_rcu_free(struct rcu_head *head)
 {
        struct Qdisc *qdisc = container_of(head, struct Qdisc, rcu_head);
 
-       if (qdisc_is_percpu_stats(qdisc))
+       if (qdisc_is_percpu_stats(qdisc)) {
                free_percpu(qdisc->cpu_bstats);
+               free_percpu(qdisc->cpu_qstats);
+       }
 
        kfree((char *) qdisc - qdisc->padded);
 }
index cd34a4a3406578954d5831b8304162c7102d8cec..22c2bf367d7e8c7025065f33eabfd7e93a7f4021 100644 (file)
@@ -4829,7 +4829,8 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(
 
        retval = SCTP_DISPOSITION_CONSUME;
 
-       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
+       if (abort)
+               sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
 
        /* Even if we can't send the ABORT due to low memory delete the
         * TCB.  This is a departure from our typical NOMEM handling.
@@ -4966,7 +4967,8 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(
                        SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
        retval = SCTP_DISPOSITION_CONSUME;
 
-       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
+       if (abort)
+               sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
 
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_CLOSED));
index 9b6cc6de80d81a641456b5ccc5c279bb24fea901..ef1d90fdc773d2ca4104c9dabc96d1058e99629a 100644 (file)
@@ -1301,8 +1301,9 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
                                      int addrs_size,
                                      sctp_assoc_t *assoc_id)
 {
-       int err = 0;
        struct sockaddr *kaddrs;
+       gfp_t gfp = GFP_KERNEL;
+       int err = 0;
 
        pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n",
                 __func__, sk, addrs, addrs_size);
@@ -1315,7 +1316,9 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
                return -EFAULT;
 
        /* Alloc space for the address array in kernel memory.  */
-       kaddrs = kmalloc(addrs_size, GFP_KERNEL);
+       if (sk->sk_socket->file)
+               gfp = GFP_USER | __GFP_NOWARN;
+       kaddrs = kmalloc(addrs_size, gfp);
        if (unlikely(!kaddrs))
                return -ENOMEM;
 
@@ -1513,8 +1516,7 @@ static void sctp_close(struct sock *sk, long timeout)
                        struct sctp_chunk *chunk;
 
                        chunk = sctp_make_abort_user(asoc, NULL, 0);
-                       if (chunk)
-                               sctp_primitive_ABORT(net, asoc, chunk);
+                       sctp_primitive_ABORT(net, asoc, chunk);
                } else
                        sctp_primitive_SHUTDOWN(net, asoc, NULL);
        }
@@ -5773,7 +5775,7 @@ static int sctp_getsockopt_assoc_ids(struct sock *sk, int len,
 
        len = sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num;
 
-       ids = kmalloc(len, GFP_KERNEL);
+       ids = kmalloc(len, GFP_USER | __GFP_NOWARN);
        if (unlikely(!ids))
                return -ENOMEM;
 
@@ -7199,6 +7201,8 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk,
 
        if (newsk->sk_flags & SK_FLAGS_TIMESTAMP)
                net_enable_timestamp();
+
+       security_sk_clone(sk, newsk);
 }
 
 static inline void sctp_copy_descendant(struct sock *sk_to,
index 29822d6dd91ec3637cbca205de3c450d19ec5651..d730ef9dfbf02aba150d5229a0d2875ddc23aa4d 100644 (file)
@@ -257,6 +257,7 @@ static struct inode *sock_alloc_inode(struct super_block *sb)
        }
        init_waitqueue_head(&wq->wait);
        wq->fasync_list = NULL;
+       wq->flags = 0;
        RCU_INIT_POINTER(ei->socket.wq, wq);
 
        ei->socket.state = SS_UNCONNECTED;
index a4631477cedf94361d3390f8fc616409dc4fcc6c..ef05cd9403d4bb2c2ad0a3faddc71de611d892df 100644 (file)
@@ -953,32 +953,20 @@ fail:
        return NULL;
 }
 
-static int unix_mknod(const char *sun_path, umode_t mode, struct path *res)
+static int unix_mknod(struct dentry *dentry, struct path *path, umode_t mode,
+                     struct path *res)
 {
-       struct dentry *dentry;
-       struct path path;
-       int err = 0;
-       /*
-        * Get the parent directory, calculate the hash for last
-        * component.
-        */
-       dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0);
-       err = PTR_ERR(dentry);
-       if (IS_ERR(dentry))
-               return err;
+       int err;
 
-       /*
-        * All right, let's create it.
-        */
-       err = security_path_mknod(&path, dentry, mode, 0);
+       err = security_path_mknod(path, dentry, mode, 0);
        if (!err) {
-               err = vfs_mknod(d_inode(path.dentry), dentry, mode, 0);
+               err = vfs_mknod(d_inode(path->dentry), dentry, mode, 0);
                if (!err) {
-                       res->mnt = mntget(path.mnt);
+                       res->mnt = mntget(path->mnt);
                        res->dentry = dget(dentry);
                }
        }
-       done_path_create(&path, dentry);
+
        return err;
 }
 
@@ -989,10 +977,12 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        struct unix_sock *u = unix_sk(sk);
        struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
        char *sun_path = sunaddr->sun_path;
-       int err;
+       int err, name_err;
        unsigned int hash;
        struct unix_address *addr;
        struct hlist_head *list;
+       struct path path;
+       struct dentry *dentry;
 
        err = -EINVAL;
        if (sunaddr->sun_family != AF_UNIX)
@@ -1008,14 +998,34 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                goto out;
        addr_len = err;
 
+       name_err = 0;
+       dentry = NULL;
+       if (sun_path[0]) {
+               /* Get the parent directory, calculate the hash for last
+                * component.
+                */
+               dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0);
+
+               if (IS_ERR(dentry)) {
+                       /* delay report until after 'already bound' check */
+                       name_err = PTR_ERR(dentry);
+                       dentry = NULL;
+               }
+       }
+
        err = mutex_lock_interruptible(&u->readlock);
        if (err)
-               goto out;
+               goto out_path;
 
        err = -EINVAL;
        if (u->addr)
                goto out_up;
 
+       if (name_err) {
+               err = name_err == -EEXIST ? -EADDRINUSE : name_err;
+               goto out_up;
+       }
+
        err = -ENOMEM;
        addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL);
        if (!addr)
@@ -1026,11 +1036,11 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        addr->hash = hash ^ sk->sk_type;
        atomic_set(&addr->refcnt, 1);
 
-       if (sun_path[0]) {
-               struct path path;
+       if (dentry) {
+               struct path u_path;
                umode_t mode = S_IFSOCK |
                       (SOCK_INODE(sock)->i_mode & ~current_umask());
-               err = unix_mknod(sun_path, mode, &path);
+               err = unix_mknod(dentry, &path, mode, &u_path);
                if (err) {
                        if (err == -EEXIST)
                                err = -EADDRINUSE;
@@ -1038,9 +1048,9 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                        goto out_up;
                }
                addr->hash = UNIX_HASH_SIZE;
-               hash = d_backing_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE-1);
+               hash = d_backing_inode(dentry)->i_ino & (UNIX_HASH_SIZE - 1);
                spin_lock(&unix_table_lock);
-               u->path = path;
+               u->path = u_path;
                list = &unix_socket_table[hash];
        } else {
                spin_lock(&unix_table_lock);
@@ -1063,6 +1073,10 @@ out_unlock:
        spin_unlock(&unix_table_lock);
 out_up:
        mutex_unlock(&u->readlock);
+out_path:
+       if (dentry)
+               done_path_create(&path, dentry);
+
 out:
        return err;
 }
index 948fa5560de500a8634835c24fa666b37a1ea33b..b5e665b3cfb05f4d08970387802fee8aec8243dd 100644 (file)
@@ -2826,7 +2826,6 @@ static struct neighbour *xfrm_neigh_lookup(const struct dst_entry *dst,
 
 int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
 {
-       struct net *net;
        int err = 0;
        if (unlikely(afinfo == NULL))
                return -EINVAL;
@@ -2857,26 +2856,6 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
        }
        spin_unlock(&xfrm_policy_afinfo_lock);
 
-       rtnl_lock();
-       for_each_net(net) {
-               struct dst_ops *xfrm_dst_ops;
-
-               switch (afinfo->family) {
-               case AF_INET:
-                       xfrm_dst_ops = &net->xfrm.xfrm4_dst_ops;
-                       break;
-#if IS_ENABLED(CONFIG_IPV6)
-               case AF_INET6:
-                       xfrm_dst_ops = &net->xfrm.xfrm6_dst_ops;
-                       break;
-#endif
-               default:
-                       BUG();
-               }
-               *xfrm_dst_ops = *afinfo->dst_ops;
-       }
-       rtnl_unlock();
-
        return err;
 }
 EXPORT_SYMBOL(xfrm_policy_register_afinfo);
@@ -2912,22 +2891,6 @@ int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo)
 }
 EXPORT_SYMBOL(xfrm_policy_unregister_afinfo);
 
-static void __net_init xfrm_dst_ops_init(struct net *net)
-{
-       struct xfrm_policy_afinfo *afinfo;
-
-       rcu_read_lock();
-       afinfo = rcu_dereference(xfrm_policy_afinfo[AF_INET]);
-       if (afinfo)
-               net->xfrm.xfrm4_dst_ops = *afinfo->dst_ops;
-#if IS_ENABLED(CONFIG_IPV6)
-       afinfo = rcu_dereference(xfrm_policy_afinfo[AF_INET6]);
-       if (afinfo)
-               net->xfrm.xfrm6_dst_ops = *afinfo->dst_ops;
-#endif
-       rcu_read_unlock();
-}
-
 static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
@@ -3076,7 +3039,6 @@ static int __net_init xfrm_net_init(struct net *net)
        rv = xfrm_policy_init(net);
        if (rv < 0)
                goto out_policy;
-       xfrm_dst_ops_init(net);
        rv = xfrm_sysctl_init(net);
        if (rv < 0)
                goto out_sysctl;
index 198580d245e033b8b674fdad3d1aa1cb21f0fd2e..d154f0877fd806a93d234e6d4288da27d6c5d09f 100755 (executable)
@@ -2,7 +2,9 @@
 # extract linker version number from stdin and turn into single number
        {
        gsub(".*)", "");
+       gsub(".*version ", "");
+       gsub("-.*", "");
        split($1,a, ".");
-       print a[1]*10000000 + a[2]*100000 + a[3]*10000 + a[4]*100 + a[5];
+       print a[1]*100000000 + a[2]*1000000 + a[3]*10000 + a[4]*100 + a[5];
        exit
        }
index 301d70b0174f3b3ff3aaea7a721ffdd905a576f9..e167592793a70e8a1bac057d58ca7456e064db8e 100644 (file)
@@ -586,7 +586,7 @@ main(int argc, char *argv[])
                        do_file(file);
                        break;
                case SJ_FAIL:    /* error in do_file or below */
-                       sprintf("%s: failed\n", file);
+                       fprintf(stderr, "%s: failed\n", file);
                        ++n_error;
                        break;
                case SJ_SUCCEED:    /* premature success */
index fb111eafcb893e4f5146c74a84f8499d4e1553c4..1c3872aeed14ace421a9d43fc396c43afdd5b93c 100644 (file)
@@ -751,16 +751,16 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
 
        /* the key is probably readable - now try to read it */
 can_read_key:
-       ret = key_validate(key);
-       if (ret == 0) {
-               ret = -EOPNOTSUPP;
-               if (key->type->read) {
-                       /* read the data with the semaphore held (since we
-                        * might sleep) */
-                       down_read(&key->sem);
+       ret = -EOPNOTSUPP;
+       if (key->type->read) {
+               /* Read the data with the semaphore held (since we might sleep)
+                * to protect against the key being updated or revoked.
+                */
+               down_read(&key->sem);
+               ret = key_validate(key);
+               if (ret == 0)
                        ret = key->type->read(key, buffer, buflen);
-                       up_read(&key->sem);
-               }
+               up_read(&key->sem);
        }
 
 error2:
index ff81026f6ddbae7de368a1ae4bfbfeb1a66a9ae6..37fdd5416a64d54bd183f999cb90d86f1d53f91e 100644 (file)
@@ -1519,8 +1519,6 @@ static int smack_inode_getsecurity(const struct inode *inode,
  * @inode: the object
  * @buffer: where they go
  * @buffer_size: size of buffer
- *
- * Returns 0 on success, -EINVAL otherwise
  */
 static int smack_inode_listsecurity(struct inode *inode, char *buffer,
                                    size_t buffer_size)
index e0d9363dc7fd2435ef894a6a6060d53c48e68334..514f2604086e837dd3e986bf6433f8829b224977 100644 (file)
 #include <sound/initval.h>
 
 #ifdef CONFIG_SND_ES1968_RADIO
-#include <media/tea575x.h>
+#include <media/drv-intf/tea575x.h>
 #endif
 
 #define CARD_NAME "ESS Maestro1/2"
@@ -2605,7 +2605,7 @@ static void snd_es1968_tea575x_set_direction(struct snd_tea575x *tea, bool outpu
        }
 }
 
-static struct snd_tea575x_ops snd_es1968_tea_ops = {
+static const struct snd_tea575x_ops snd_es1968_tea_ops = {
        .set_pins = snd_es1968_tea575x_set_pins,
        .get_pins = snd_es1968_tea575x_get_pins,
        .set_direction = snd_es1968_tea575x_set_direction,
index 1fdd92b6f18f377585b2c36813fcb9ff444fc691..759295aa836684f4cff19abe571992d22e1c4f60 100644 (file)
@@ -30,7 +30,7 @@
 #include <sound/initval.h>
 
 #ifdef CONFIG_SND_FM801_TEA575X_BOOL
-#include <media/tea575x.h>
+#include <media/drv-intf/tea575x.h>
 #endif
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
@@ -815,7 +815,7 @@ static void snd_fm801_tea575x_set_direction(struct snd_tea575x *tea, bool output
        fm801_writew(chip, GPIO_CTRL, reg);
 }
 
-static struct snd_tea575x_ops snd_fm801_tea_ops = {
+static const struct snd_tea575x_ops snd_fm801_tea_ops = {
        .set_pins = snd_fm801_tea575x_set_pins,
        .get_pins = snd_fm801_tea575x_get_pins,
        .set_direction = snd_fm801_tea575x_set_direction,
index fe96428aa40343f362237121f246e67b734c0446..3a89d82f805759f5c4016c47df40d1a3b5522f49 100644 (file)
@@ -67,6 +67,10 @@ enum {
        ALC_HEADSET_TYPE_OMTP,
 };
 
+enum {
+       ALC_KEY_MICMUTE_INDEX,
+};
+
 struct alc_customize_define {
        unsigned int  sku_cfg;
        unsigned char port_connectivity;
@@ -123,6 +127,7 @@ struct alc_spec {
        unsigned int pll_coef_idx, pll_coef_bit;
        unsigned int coef0;
        struct input_dev *kb_dev;
+       u8 alc_mute_keycode_map[1];
 };
 
 /*
@@ -3462,12 +3467,43 @@ static void gpio2_mic_hotkey_event(struct hda_codec *codec,
 
        /* GPIO2 just toggles on a keypress/keyrelease cycle. Therefore
           send both key on and key off event for every interrupt. */
-       input_report_key(spec->kb_dev, KEY_MICMUTE, 1);
+       input_report_key(spec->kb_dev, spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX], 1);
        input_sync(spec->kb_dev);
-       input_report_key(spec->kb_dev, KEY_MICMUTE, 0);
+       input_report_key(spec->kb_dev, spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX], 0);
        input_sync(spec->kb_dev);
 }
 
+static int alc_register_micmute_input_device(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       int i;
+
+       spec->kb_dev = input_allocate_device();
+       if (!spec->kb_dev) {
+               codec_err(codec, "Out of memory (input_allocate_device)\n");
+               return -ENOMEM;
+       }
+
+       spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX] = KEY_MICMUTE;
+
+       spec->kb_dev->name = "Microphone Mute Button";
+       spec->kb_dev->evbit[0] = BIT_MASK(EV_KEY);
+       spec->kb_dev->keycodesize = sizeof(spec->alc_mute_keycode_map[0]);
+       spec->kb_dev->keycodemax = ARRAY_SIZE(spec->alc_mute_keycode_map);
+       spec->kb_dev->keycode = spec->alc_mute_keycode_map;
+       for (i = 0; i < ARRAY_SIZE(spec->alc_mute_keycode_map); i++)
+               set_bit(spec->alc_mute_keycode_map[i], spec->kb_dev->keybit);
+
+       if (input_register_device(spec->kb_dev)) {
+               codec_err(codec, "input_register_device failed\n");
+               input_free_device(spec->kb_dev);
+               spec->kb_dev = NULL;
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
 static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
                                             const struct hda_fixup *fix, int action)
 {
@@ -3485,20 +3521,8 @@ static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
        struct alc_spec *spec = codec->spec;
 
        if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->kb_dev = input_allocate_device();
-               if (!spec->kb_dev) {
-                       codec_err(codec, "Out of memory (input_allocate_device)\n");
+               if (alc_register_micmute_input_device(codec) != 0)
                        return;
-               }
-               spec->kb_dev->name = "Microphone Mute Button";
-               spec->kb_dev->evbit[0] = BIT_MASK(EV_KEY);
-               spec->kb_dev->keybit[BIT_WORD(KEY_MICMUTE)] = BIT_MASK(KEY_MICMUTE);
-               if (input_register_device(spec->kb_dev)) {
-                       codec_err(codec, "input_register_device failed\n");
-                       input_free_device(spec->kb_dev);
-                       spec->kb_dev = NULL;
-                       return;
-               }
 
                snd_hda_add_verbs(codec, gpio_init);
                snd_hda_codec_write_cache(codec, codec->core.afg, 0,
@@ -3528,6 +3552,47 @@ static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
        }
 }
 
+static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec,
+                                            const struct hda_fixup *fix, int action)
+{
+       /* Line2 = mic mute hotkey
+          GPIO2 = mic mute LED */
+       static const struct hda_verb gpio_init[] = {
+               { 0x01, AC_VERB_SET_GPIO_MASK, 0x04 },
+               { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 },
+               {}
+       };
+
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               if (alc_register_micmute_input_device(codec) != 0)
+                       return;
+
+               snd_hda_add_verbs(codec, gpio_init);
+               snd_hda_jack_detect_enable_callback(codec, 0x1b,
+                                                   gpio2_mic_hotkey_event);
+
+               spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
+               spec->gpio_led = 0;
+               spec->mute_led_polarity = 0;
+               spec->gpio_mic_led_mask = 0x04;
+               return;
+       }
+
+       if (!spec->kb_dev)
+               return;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PROBE:
+               spec->init_amp = ALC_INIT_DEFAULT;
+               break;
+       case HDA_FIXUP_ACT_FREE:
+               input_unregister_device(spec->kb_dev);
+               spec->kb_dev = NULL;
+       }
+}
+
 static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
                                const struct hda_fixup *fix, int action)
 {
@@ -4628,6 +4693,7 @@ enum {
        ALC275_FIXUP_DELL_XPS,
        ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE,
        ALC293_FIXUP_LENOVO_SPK_NOISE,
+       ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -5237,6 +5303,10 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC269_FIXUP_THINKPAD_ACPI
        },
+       [ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc233_fixup_lenovo_line2_mic_hotkey,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -5386,6 +5456,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x2223, "ThinkPad T550", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE),
+       SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
        SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
        SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
        SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
index b3ea24d64c5009cf4cc77e1877c894e3f21f4ee7..93b400800905d2fee18b066f11761cca524d9369 100644 (file)
@@ -1537,7 +1537,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
        bool reconfig;
        unsigned int aif_tx_state, aif_rx_state;
 
-       if (params_rate(params) % 8000)
+       if (params_rate(params) % 4000)
                rates = &arizona_44k1_bclk_rates[0];
        else
                rates = &arizona_48k_bclk_rates[0];
index ef76940f9dcb63196b10798f80d54528adc6109d..3e3c7f6be29d9a463f3b07bdefa78e0f2f29ace2 100644 (file)
@@ -1667,9 +1667,13 @@ static int rt5645_spk_event(struct snd_soc_dapm_widget *w,
                        RT5645_PWR_CLS_D_L,
                        RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
                        RT5645_PWR_CLS_D_L);
+               snd_soc_update_bits(codec, RT5645_GEN_CTRL3,
+                       RT5645_DET_CLK_MASK, RT5645_DET_CLK_MODE1);
                break;
 
        case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_update_bits(codec, RT5645_GEN_CTRL3,
+                       RT5645_DET_CLK_MASK, RT5645_DET_CLK_DIS);
                snd_soc_write(codec, RT5645_EQ_CTRL2, 0);
                snd_soc_update_bits(codec, RT5645_PWR_DIG1,
                        RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
index 093e46d559fbab24aa05efc5c74a2e8488fa49d0..205e0715c99abad45e771c0504b92a512f5b6adf 100644 (file)
@@ -2122,6 +2122,10 @@ enum {
 /* General Control3 (0xfc) */
 #define RT5645_JD_PSV_MODE                     (0x1 << 12)
 #define RT5645_IRQ_CLK_GATE_CTRL               (0x1 << 11)
+#define RT5645_DET_CLK_MASK                    (0x3 << 9)
+#define RT5645_DET_CLK_DIS                     (0x0 << 9)
+#define RT5645_DET_CLK_MODE1                   (0x1 << 9)
+#define RT5645_DET_CLK_MODE2                   (0x2 << 9)
 #define RT5645_MICINDET_MANU                   (0x1 << 7)
 #define RT5645_RING2_SLEEVE_GND                        (0x1 << 5)
 
index ffea427aeca8eab29809f049c53ba27f71b54393..ad4d0f82603e7f65292a6c02530d66413a80ca91 100644 (file)
@@ -1240,7 +1240,6 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus)
         */
        ret = snd_soc_tplg_component_load(&platform->component,
                                        &skl_tplg_ops, fw, 0);
-       release_firmware(fw);
        if (ret < 0) {
                dev_err(bus->dev, "tplg component load failed%d\n", ret);
                return -EINVAL;
@@ -1249,5 +1248,7 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus)
        skl->resource.max_mcps = SKL_MAX_MCPS;
        skl->resource.max_mem = SKL_FW_MAX_MEM;
 
+       skl->tplg = fw;
+
        return 0;
 }
index 5319529aedf7ae5030dbf47ce9b6056512f05c2d..caa69c4598a6f14eb27c91575b49aae9fd7d3e8a 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/pci.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_device.h>
+#include <linux/firmware.h>
 #include <sound/pcm.h>
 #include "skl.h"
 
@@ -520,6 +521,9 @@ static void skl_remove(struct pci_dev *pci)
        struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
        struct skl *skl = ebus_to_skl(ebus);
 
+       if (skl->tplg)
+               release_firmware(skl->tplg);
+
        if (pci_dev_run_wake(pci))
                pm_runtime_get_noresume(&pci->dev);
        pci_dev_put(pci);
index dd2e79ae45a8e6294c2766ef5eff7f4fac37befe..a0709e344d4419f4a37d28636cc3c79f368acd36 100644 (file)
@@ -68,6 +68,8 @@ struct skl {
        struct skl_dsp_resource resource;
        struct list_head ppl_list;
        struct list_head dapm_path_list;
+
+       const struct firmware *tplg;
 };
 
 #define skl_to_ebus(s) (&(s)->ebus)
index 7dc820a8c1f11b0973605aab313e2ecaa75ca1a6..0ba0df3b516f170ee6dd7684b21333560a70ea1b 100644 (file)
@@ -96,7 +96,7 @@ cgroup_install firewire_install hv_install lguest_install perf_install usb_insta
        $(call descend,$(@:_install=),install)
 
 selftests_install:
-       $(call descend,testing/$(@:_clean=),install)
+       $(call descend,testing/$(@:_install=),install)
 
 turbostat_install x86_energy_perf_policy_install:
        $(call descend,power/x86/$(@:_install=),install)
index a93036272d43cee505d43fee2ef3b1c347056f09..0d5a0e3a8fa9601fe8a58ff0e71142ebf2918df8 100644 (file)
@@ -25,7 +25,7 @@ export Q srctree CC LD
 MAKEFLAGS := --no-print-directory
 build     := -f $(srctree)/tools/build/Makefile.build dir=. obj
 
-all: fixdep
+all: $(OUTPUT)fixdep
 
 clean:
        $(call QUIET_CLEAN, fixdep)
index 37ff4c9f92f1b5d8c17f8df034f0dad567d146fa..02db3cdff20ff7653c8ca0db21d28ef7b508a9eb 100644 (file)
@@ -7,7 +7,7 @@ endif
 
 feature_check = $(eval $(feature_check_code))
 define feature_check_code
-  feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C $(feature_dir) test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0)
+  feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C $(feature_dir) $(OUTPUT_FEATURES)test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0)
 endef
 
 feature_set = $(eval $(feature_set_code))
@@ -101,7 +101,6 @@ ifeq ($(feature-all), 1)
   #
   $(foreach feat,$(FEATURE_TESTS),$(call feature_set,$(feat)))
 else
-  $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) -i -j -C $(feature_dir) $(addsuffix .bin,$(FEATURE_TESTS)) >/dev/null 2>&1)
   $(foreach feat,$(FEATURE_TESTS),$(call feature_check,$(feat)))
 endif
 
@@ -123,13 +122,31 @@ define feature_print_text_code
     MSG = $(shell printf '...%30s: %s' $(1) $(2))
 endef
 
+#
+# generates feature value assignment for name, like:
+#   $(call feature_assign,dwarf) == feature-dwarf=1
+#
+feature_assign = feature-$(1)=$(feature-$(1))
+
 FEATURE_DUMP_FILENAME = $(OUTPUT)FEATURE-DUMP$(FEATURE_USER)
-FEATURE_DUMP := $(foreach feat,$(FEATURE_DISPLAY),feature-$(feat)($(feature-$(feat))))
-FEATURE_DUMP_FILE := $(shell touch $(FEATURE_DUMP_FILENAME); cat $(FEATURE_DUMP_FILENAME))
+FEATURE_DUMP := $(shell touch $(FEATURE_DUMP_FILENAME); cat $(FEATURE_DUMP_FILENAME))
 
-ifeq ($(dwarf-post-unwind),1)
-  FEATURE_DUMP += dwarf-post-unwind($(dwarf-post-unwind-text))
-endif
+feature_dump_check = $(eval $(feature_dump_check_code))
+define feature_dump_check_code
+  ifeq ($(findstring $(1),$(FEATURE_DUMP)),)
+    $(2) := 1
+  endif
+endef
+
+#
+# First check if any test from FEATURE_DISPLAY
+# and set feature_display := 1 if it does
+$(foreach feat,$(FEATURE_DISPLAY),$(call feature_dump_check,$(call feature_assign,$(feat)),feature_display))
+
+#
+# Now also check if any other test changed,
+# so we force FEATURE-DUMP generation
+$(foreach feat,$(FEATURE_TESTS),$(call feature_dump_check,$(call feature_assign,$(feat)),feature_dump_changed))
 
 # The $(feature_display) controls the default detection message
 # output. It's set if:
@@ -138,13 +155,13 @@ endif
 # - one of the $(FEATURE_DISPLAY) is not detected
 # - VF is enabled
 
-ifneq ("$(FEATURE_DUMP)","$(FEATURE_DUMP_FILE)")
-  $(shell echo "$(FEATURE_DUMP)" > $(FEATURE_DUMP_FILENAME))
-  feature_display := 1
+ifeq ($(feature_dump_changed),1)
+  $(shell rm -f $(FEATURE_DUMP_FILENAME))
+  $(foreach feat,$(FEATURE_TESTS),$(shell echo "$(call feature_assign,$(feat))" >> $(FEATURE_DUMP_FILENAME)))
 endif
 
 feature_display_check = $(eval $(feature_check_display_code))
-define feature_display_check_code
+define feature_check_display_code
   ifneq ($(feature-$(1)), 1)
     feature_display := 1
   endif
@@ -161,11 +178,6 @@ ifeq ($(feature_display),1)
   $(info )
   $(info Auto-detecting system features:)
   $(foreach feat,$(FEATURE_DISPLAY),$(call feature_print_status,$(feat),))
-
-  ifeq ($(dwarf-post-unwind),1)
-    $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text))
-  endif
-
   ifneq ($(feature_verbose),1)
     $(info )
   endif
index 4e09ad617a607dd0884ada776d26df23bac407cb..be630bed66d2af1407eeaaca5089290bbf989392 100644 (file)
@@ -4,7 +4,7 @@ ifdef CROSS_COMPILE
 fixdep:
 else
 fixdep:
-       $(Q)$(MAKE) -C $(srctree)/tools/build fixdep
+       $(Q)$(MAKE) -C $(srctree)/tools/build CFLAGS= LDFLAGS= $(OUTPUT)fixdep
 endif
 
 .PHONY: fixdep
index cea04ce9f35cdfb7e5b217077d60b214894b6c48..bf8f0352264dcc8a5a1286bc4add2ca9de481357 100644 (file)
@@ -1,4 +1,3 @@
-
 FILES=                                 \
        test-all.bin                    \
        test-backtrace.bin              \
@@ -38,38 +37,40 @@ FILES=                                      \
        test-bpf.bin                    \
        test-get_cpuid.bin
 
+FILES := $(addprefix $(OUTPUT),$(FILES))
+
 CC := $(CROSS_COMPILE)gcc -MD
 PKG_CONFIG := $(CROSS_COMPILE)pkg-config
 
 all: $(FILES)
 
-__BUILD = $(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS)
-  BUILD = $(__BUILD) > $(OUTPUT)$(@:.bin=.make.output) 2>&1
+__BUILD = $(CC) $(CFLAGS) -Wall -Werror -o $@ $(patsubst %.bin,%.c,$(@F)) $(LDFLAGS)
+  BUILD = $(__BUILD) > $(@:.bin=.make.output) 2>&1
 
 ###############################
 
-test-all.bin:
+$(OUTPUT)test-all.bin:
        $(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz -llzma
 
-test-hello.bin:
+$(OUTPUT)test-hello.bin:
        $(BUILD)
 
-test-pthread-attr-setaffinity-np.bin:
+$(OUTPUT)test-pthread-attr-setaffinity-np.bin:
        $(BUILD) -D_GNU_SOURCE -lpthread
 
-test-stackprotector-all.bin:
+$(OUTPUT)test-stackprotector-all.bin:
        $(BUILD) -fstack-protector-all
 
-test-fortify-source.bin:
+$(OUTPUT)test-fortify-source.bin:
        $(BUILD) -O2 -D_FORTIFY_SOURCE=2
 
-test-bionic.bin:
+$(OUTPUT)test-bionic.bin:
        $(BUILD)
 
-test-libelf.bin:
+$(OUTPUT)test-libelf.bin:
        $(BUILD) -lelf
 
-test-glibc.bin:
+$(OUTPUT)test-glibc.bin:
        $(BUILD)
 
 DWARFLIBS := -ldw
@@ -77,37 +78,37 @@ ifeq ($(findstring -static,${LDFLAGS}),-static)
 DWARFLIBS += -lelf -lebl -lz -llzma -lbz2
 endif
 
-test-dwarf.bin:
+$(OUTPUT)test-dwarf.bin:
        $(BUILD) $(DWARFLIBS)
 
-test-libelf-mmap.bin:
+$(OUTPUT)test-libelf-mmap.bin:
        $(BUILD) -lelf
 
-test-libelf-getphdrnum.bin:
+$(OUTPUT)test-libelf-getphdrnum.bin:
        $(BUILD) -lelf
 
-test-libnuma.bin:
+$(OUTPUT)test-libnuma.bin:
        $(BUILD) -lnuma
 
-test-numa_num_possible_cpus.bin:
+$(OUTPUT)test-numa_num_possible_cpus.bin:
        $(BUILD) -lnuma
 
-test-libunwind.bin:
+$(OUTPUT)test-libunwind.bin:
        $(BUILD) -lelf
 
-test-libunwind-debug-frame.bin:
+$(OUTPUT)test-libunwind-debug-frame.bin:
        $(BUILD) -lelf
 
-test-libaudit.bin:
+$(OUTPUT)test-libaudit.bin:
        $(BUILD) -laudit
 
-test-libslang.bin:
+$(OUTPUT)test-libslang.bin:
        $(BUILD) -I/usr/include/slang -lslang
 
-test-gtk2.bin:
+$(OUTPUT)test-gtk2.bin:
        $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
 
-test-gtk2-infobar.bin:
+$(OUTPUT)test-gtk2-infobar.bin:
        $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
 
 grep-libs  = $(filter -l%,$(1))
@@ -119,63 +120,63 @@ PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
 PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
 FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
 
-test-libperl.bin:
+$(OUTPUT)test-libperl.bin:
        $(BUILD) $(FLAGS_PERL_EMBED)
 
-test-libpython.bin:
+$(OUTPUT)test-libpython.bin:
        $(BUILD)
 
-test-libpython-version.bin:
+$(OUTPUT)test-libpython-version.bin:
        $(BUILD)
 
-test-libbfd.bin:
+$(OUTPUT)test-libbfd.bin:
        $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl
 
-test-liberty.bin:
-       $(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty
+$(OUTPUT)test-liberty.bin:
+       $(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty
 
-test-liberty-z.bin:
-       $(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty -lz
+$(OUTPUT)test-liberty-z.bin:
+       $(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty -lz
 
-test-cplus-demangle.bin:
+$(OUTPUT)test-cplus-demangle.bin:
        $(BUILD) -liberty
 
-test-backtrace.bin:
+$(OUTPUT)test-backtrace.bin:
        $(BUILD)
 
-test-timerfd.bin:
+$(OUTPUT)test-timerfd.bin:
        $(BUILD)
 
-test-libdw-dwarf-unwind.bin:
+$(OUTPUT)test-libdw-dwarf-unwind.bin:
        $(BUILD) # -ldw provided by $(FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind)
 
-test-libbabeltrace.bin:
+$(OUTPUT)test-libbabeltrace.bin:
        $(BUILD) # -lbabeltrace provided by $(FEATURE_CHECK_LDFLAGS-libbabeltrace)
 
-test-sync-compare-and-swap.bin:
+$(OUTPUT)test-sync-compare-and-swap.bin:
        $(BUILD)
 
-test-compile-32.bin:
-       $(CC) -m32 -o $(OUTPUT)$@ test-compile.c
+$(OUTPUT)test-compile-32.bin:
+       $(CC) -m32 -o $@ test-compile.c
 
-test-compile-x32.bin:
-       $(CC) -mx32 -o $(OUTPUT)$@ test-compile.c
+$(OUTPUT)test-compile-x32.bin:
+       $(CC) -mx32 -o $@ test-compile.c
 
-test-zlib.bin:
+$(OUTPUT)test-zlib.bin:
        $(BUILD) -lz
 
-test-lzma.bin:
+$(OUTPUT)test-lzma.bin:
        $(BUILD) -llzma
 
-test-get_cpuid.bin:
+$(OUTPUT)test-get_cpuid.bin:
        $(BUILD)
 
-test-bpf.bin:
+$(OUTPUT)test-bpf.bin:
        $(BUILD)
 
--include *.d
+-include $(OUTPUT)*.d
 
 ###############################
 
 clean:
-       rm -f $(FILES) *.d $(FILES:.bin=.make.output)
+       rm -f $(FILES) $(OUTPUT)*.d $(FILES:.bin=.make.output)
diff --git a/tools/include/linux/bitmap.h b/tools/include/linux/bitmap.h
new file mode 100644 (file)
index 0000000..28f5493
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef _PERF_BITOPS_H
+#define _PERF_BITOPS_H
+
+#include <string.h>
+#include <linux/bitops.h>
+
+#define DECLARE_BITMAP(name,bits) \
+       unsigned long name[BITS_TO_LONGS(bits)]
+
+int __bitmap_weight(const unsigned long *bitmap, int bits);
+void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+                const unsigned long *bitmap2, int bits);
+
+#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1)))
+
+#define BITMAP_LAST_WORD_MASK(nbits)                                   \
+(                                                                      \
+       ((nbits) % BITS_PER_LONG) ?                                     \
+               (1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL               \
+)
+
+#define small_const_nbits(nbits) \
+       (__builtin_constant_p(nbits) && (nbits) <= BITS_PER_LONG)
+
+static inline void bitmap_zero(unsigned long *dst, int nbits)
+{
+       if (small_const_nbits(nbits))
+               *dst = 0UL;
+       else {
+               int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+               memset(dst, 0, len);
+       }
+}
+
+static inline int bitmap_weight(const unsigned long *src, int nbits)
+{
+       if (small_const_nbits(nbits))
+               return hweight_long(*src & BITMAP_LAST_WORD_MASK(nbits));
+       return __bitmap_weight(src, nbits);
+}
+
+static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
+                            const unsigned long *src2, int nbits)
+{
+       if (small_const_nbits(nbits))
+               *dst = *src1 | *src2;
+       else
+               __bitmap_or(dst, src1, src2, nbits);
+}
+
+/**
+ * test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ */
+static inline int test_and_set_bit(int nr, unsigned long *addr)
+{
+       unsigned long mask = BIT_MASK(nr);
+       unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+       unsigned long old;
+
+       old = *p;
+       *p = old | mask;
+
+       return (old & mask) != 0;
+}
+
+#endif /* _PERF_BITOPS_H */
diff --git a/tools/include/linux/string.h b/tools/include/linux/string.h
new file mode 100644 (file)
index 0000000..e26223f
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _TOOLS_LINUX_STRING_H_
+#define _TOOLS_LINUX_STRING_H_
+
+
+#include <linux/types.h>       /* for size_t */
+
+void *memdup(const void *src, size_t len);
+
+int strtobool(const char *s, bool *res);
+
+#ifndef __UCLIBC__
+extern size_t strlcpy(char *dest, const char *src, size_t size);
+#endif
+
+#endif /* _LINUX_STRING_H_ */
diff --git a/tools/lib/bitmap.c b/tools/lib/bitmap.c
new file mode 100644 (file)
index 0000000..0a1adc1
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * From lib/bitmap.c
+ * Helper functions for bitmap.h.
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+#include <linux/bitmap.h>
+
+int __bitmap_weight(const unsigned long *bitmap, int bits)
+{
+       int k, w = 0, lim = bits/BITS_PER_LONG;
+
+       for (k = 0; k < lim; k++)
+               w += hweight_long(bitmap[k]);
+
+       if (bits % BITS_PER_LONG)
+               w += hweight_long(bitmap[k] & BITMAP_LAST_WORD_MASK(bits));
+
+       return w;
+}
+
+void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+                const unsigned long *bitmap2, int bits)
+{
+       int k;
+       int nr = BITS_TO_LONGS(bits);
+
+       for (k = 0; k < nr; k++)
+               dst[k] = bitmap1[k] | bitmap2[k];
+}
index a3caaf3eafbdbc6c7afda606cbf35b6888324ef4..919b71780710005008ced1101dce7157e9600486 100644 (file)
@@ -71,7 +71,21 @@ FEATURE_DISPLAY = libelf bpf
 INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/arch/$(ARCH)/include/uapi -I$(srctree)/include/uapi
 FEATURE_CHECK_CFLAGS-bpf = $(INCLUDES)
 
+check_feat := 1
+NON_CHECK_FEAT_TARGETS := clean TAGS tags cscope help
+ifdef MAKECMDGOALS
+ifeq ($(filter-out $(NON_CHECK_FEAT_TARGETS),$(MAKECMDGOALS)),)
+  check_feat := 0
+endif
+endif
+
+ifeq ($(check_feat),1)
+ifeq ($(FEATURES_DUMP),)
 include $(srctree)/tools/build/Makefile.feature
+else
+include $(FEATURES_DUMP)
+endif
+endif
 
 export prefix libdir src obj
 
index a6331050ab79dbe7e32e38435ee5436c2867c3e1..5bdc6eab6852bd7159584629d2a9798fa03b2df2 100644 (file)
@@ -83,3 +83,17 @@ int bpf_load_program(enum bpf_prog_type type, struct bpf_insn *insns,
        log_buf[0] = 0;
        return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
 }
+
+int bpf_map_update_elem(int fd, void *key, void *value,
+                       u64 flags)
+{
+       union bpf_attr attr;
+
+       bzero(&attr, sizeof(attr));
+       attr.map_fd = fd;
+       attr.key = ptr_to_u64(key);
+       attr.value = ptr_to_u64(value);
+       attr.flags = flags;
+
+       return sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
+}
index 854b7361b784380fdff7741a55deeb86c370ccca..a7646554129299bff7ba189506bd51cea406ec1d 100644 (file)
@@ -20,4 +20,6 @@ int bpf_load_program(enum bpf_prog_type type, struct bpf_insn *insns,
                     u32 kern_version, char *log_buf,
                     size_t log_buf_sz);
 
+int bpf_map_update_elem(int fd, void *key, void *value,
+                       u64 flags);
 #endif
index e176bad19bcb73689665ea9bd083075dff0e73fa..8334a5a9d5d7f55e97144e1d7462c52deec02e02 100644 (file)
@@ -152,29 +152,36 @@ struct bpf_program {
        } *reloc_desc;
        int nr_reloc;
 
-       int fd;
+       struct {
+               int nr;
+               int *fds;
+       } instances;
+       bpf_program_prep_t preprocessor;
 
        struct bpf_object *obj;
        void *priv;
        bpf_program_clear_priv_t clear_priv;
 };
 
+struct bpf_map {
+       int fd;
+       char *name;
+       struct bpf_map_def def;
+       void *priv;
+       bpf_map_clear_priv_t clear_priv;
+};
+
 static LIST_HEAD(bpf_objects_list);
 
 struct bpf_object {
        char license[64];
        u32 kern_version;
-       void *maps_buf;
-       size_t maps_buf_sz;
 
        struct bpf_program *programs;
        size_t nr_programs;
-       int *map_fds;
-       /*
-        * This field is required because maps_buf will be freed and
-        * maps_buf_sz will be set to 0 after loaded.
-        */
-       size_t nr_map_fds;
+       struct bpf_map *maps;
+       size_t nr_maps;
+
        bool loaded;
 
        /*
@@ -188,6 +195,7 @@ struct bpf_object {
                Elf *elf;
                GElf_Ehdr ehdr;
                Elf_Data *symbols;
+               size_t strtabidx;
                struct {
                        GElf_Shdr shdr;
                        Elf_Data *data;
@@ -206,10 +214,25 @@ struct bpf_object {
 
 static void bpf_program__unload(struct bpf_program *prog)
 {
+       int i;
+
        if (!prog)
                return;
 
-       zclose(prog->fd);
+       /*
+        * If the object is opened but the program was never loaded,
+        * it is possible that prog->instances.nr == -1.
+        */
+       if (prog->instances.nr > 0) {
+               for (i = 0; i < prog->instances.nr; i++)
+                       zclose(prog->instances.fds[i]);
+       } else if (prog->instances.nr != -1) {
+               pr_warning("Internal error: instances.nr is %d\n",
+                          prog->instances.nr);
+       }
+
+       prog->instances.nr = -1;
+       zfree(&prog->instances.fds);
 }
 
 static void bpf_program__exit(struct bpf_program *prog)
@@ -260,7 +283,8 @@ bpf_program__init(void *data, size_t size, char *name, int idx,
        memcpy(prog->insns, data,
               prog->insns_cnt * sizeof(struct bpf_insn));
        prog->idx = idx;
-       prog->fd = -1;
+       prog->instances.fds = NULL;
+       prog->instances.nr = -1;
 
        return 0;
 errout:
@@ -469,21 +493,77 @@ static int
 bpf_object__init_maps(struct bpf_object *obj, void *data,
                      size_t size)
 {
-       if (size == 0) {
+       size_t nr_maps;
+       int i;
+
+       nr_maps = size / sizeof(struct bpf_map_def);
+       if (!data || !nr_maps) {
                pr_debug("%s doesn't need map definition\n",
                         obj->path);
                return 0;
        }
 
-       obj->maps_buf = malloc(size);
-       if (!obj->maps_buf) {
-               pr_warning("malloc maps failed: %s\n", obj->path);
+       pr_debug("maps in %s: %zd bytes\n", obj->path, size);
+
+       obj->maps = calloc(nr_maps, sizeof(obj->maps[0]));
+       if (!obj->maps) {
+               pr_warning("alloc maps for object failed\n");
                return -ENOMEM;
        }
+       obj->nr_maps = nr_maps;
 
-       obj->maps_buf_sz = size;
-       memcpy(obj->maps_buf, data, size);
-       pr_debug("maps in %s: %ld bytes\n", obj->path, (long)size);
+       for (i = 0; i < nr_maps; i++) {
+               struct bpf_map_def *def = &obj->maps[i].def;
+
+               /*
+                * fill all fd with -1 so won't close incorrect
+                * fd (fd=0 is stdin) when failure (zclose won't close
+                * negative fd)).
+                */
+               obj->maps[i].fd = -1;
+
+               /* Save map definition into obj->maps */
+               *def = ((struct bpf_map_def *)data)[i];
+       }
+       return 0;
+}
+
+static int
+bpf_object__init_maps_name(struct bpf_object *obj, int maps_shndx)
+{
+       int i;
+       Elf_Data *symbols = obj->efile.symbols;
+
+       if (!symbols || maps_shndx < 0)
+               return -EINVAL;
+
+       for (i = 0; i < symbols->d_size / sizeof(GElf_Sym); i++) {
+               GElf_Sym sym;
+               size_t map_idx;
+               const char *map_name;
+
+               if (!gelf_getsym(symbols, i, &sym))
+                       continue;
+               if (sym.st_shndx != maps_shndx)
+                       continue;
+
+               map_name = elf_strptr(obj->efile.elf,
+                                     obj->efile.strtabidx,
+                                     sym.st_name);
+               map_idx = sym.st_value / sizeof(struct bpf_map_def);
+               if (map_idx >= obj->nr_maps) {
+                       pr_warning("index of map \"%s\" is buggy: %zu > %zu\n",
+                                  map_name, map_idx, obj->nr_maps);
+                       continue;
+               }
+               obj->maps[map_idx].name = strdup(map_name);
+               if (!obj->maps[map_idx].name) {
+                       pr_warning("failed to alloc map name\n");
+                       return -ENOMEM;
+               }
+               pr_debug("map %zu is \"%s\"\n", map_idx,
+                        obj->maps[map_idx].name);
+       }
        return 0;
 }
 
@@ -492,7 +572,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
        Elf *elf = obj->efile.elf;
        GElf_Ehdr *ep = &obj->efile.ehdr;
        Elf_Scn *scn = NULL;
-       int idx = 0, err = 0;
+       int idx = 0, err = 0, maps_shndx = -1;
 
        /* Elf is corrupted/truncated, avoid calling elf_strptr. */
        if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) {
@@ -542,16 +622,19 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
                        err = bpf_object__init_kversion(obj,
                                                        data->d_buf,
                                                        data->d_size);
-               else if (strcmp(name, "maps") == 0)
+               else if (strcmp(name, "maps") == 0) {
                        err = bpf_object__init_maps(obj, data->d_buf,
                                                    data->d_size);
-               else if (sh.sh_type == SHT_SYMTAB) {
+                       maps_shndx = idx;
+               } else if (sh.sh_type == SHT_SYMTAB) {
                        if (obj->efile.symbols) {
                                pr_warning("bpf: multiple SYMTAB in %s\n",
                                           obj->path);
                                err = -LIBBPF_ERRNO__FORMAT;
-                       } else
+                       } else {
                                obj->efile.symbols = data;
+                               obj->efile.strtabidx = sh.sh_link;
+                       }
                } else if ((sh.sh_type == SHT_PROGBITS) &&
                           (sh.sh_flags & SHF_EXECINSTR) &&
                           (data->d_size > 0)) {
@@ -586,6 +669,13 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
                if (err)
                        goto out;
        }
+
+       if (!obj->efile.strtabidx || obj->efile.strtabidx >= idx) {
+               pr_warning("Corrupted ELF file: index of strtab invalid\n");
+               return LIBBPF_ERRNO__FORMAT;
+       }
+       if (maps_shndx >= 0)
+               err = bpf_object__init_maps_name(obj, maps_shndx);
 out:
        return err;
 }
@@ -668,37 +758,15 @@ static int
 bpf_object__create_maps(struct bpf_object *obj)
 {
        unsigned int i;
-       size_t nr_maps;
-       int *pfd;
-
-       nr_maps = obj->maps_buf_sz / sizeof(struct bpf_map_def);
-       if (!obj->maps_buf || !nr_maps) {
-               pr_debug("don't need create maps for %s\n",
-                        obj->path);
-               return 0;
-       }
-
-       obj->map_fds = malloc(sizeof(int) * nr_maps);
-       if (!obj->map_fds) {
-               pr_warning("realloc perf_bpf_map_fds failed\n");
-               return -ENOMEM;
-       }
-       obj->nr_map_fds = nr_maps;
 
-       /* fill all fd with -1 */
-       memset(obj->map_fds, -1, sizeof(int) * nr_maps);
-
-       pfd = obj->map_fds;
-       for (i = 0; i < nr_maps; i++) {
-               struct bpf_map_def def;
+       for (i = 0; i < obj->nr_maps; i++) {
+               struct bpf_map_def *def = &obj->maps[i].def;
+               int *pfd = &obj->maps[i].fd;
 
-               def = *(struct bpf_map_def *)(obj->maps_buf +
-                               i * sizeof(struct bpf_map_def));
-
-               *pfd = bpf_create_map(def.type,
-                                     def.key_size,
-                                     def.value_size,
-                                     def.max_entries);
+               *pfd = bpf_create_map(def->type,
+                                     def->key_size,
+                                     def->value_size,
+                                     def->max_entries);
                if (*pfd < 0) {
                        size_t j;
                        int err = *pfd;
@@ -706,22 +774,17 @@ bpf_object__create_maps(struct bpf_object *obj)
                        pr_warning("failed to create map: %s\n",
                                   strerror(errno));
                        for (j = 0; j < i; j++)
-                               zclose(obj->map_fds[j]);
-                       obj->nr_map_fds = 0;
-                       zfree(&obj->map_fds);
+                               zclose(obj->maps[j].fd);
                        return err;
                }
                pr_debug("create map: fd=%d\n", *pfd);
-               pfd++;
        }
 
-       zfree(&obj->maps_buf);
-       obj->maps_buf_sz = 0;
        return 0;
 }
 
 static int
-bpf_program__relocate(struct bpf_program *prog, int *map_fds)
+bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj)
 {
        int i;
 
@@ -741,7 +804,7 @@ bpf_program__relocate(struct bpf_program *prog, int *map_fds)
                        return -LIBBPF_ERRNO__RELOC;
                }
                insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD;
-               insns[insn_idx].imm = map_fds[map_idx];
+               insns[insn_idx].imm = obj->maps[map_idx].fd;
        }
 
        zfree(&prog->reloc_desc);
@@ -760,7 +823,7 @@ bpf_object__relocate(struct bpf_object *obj)
        for (i = 0; i < obj->nr_programs; i++) {
                prog = &obj->programs[i];
 
-               err = bpf_program__relocate(prog, obj->map_fds);
+               err = bpf_program__relocate(prog, obj);
                if (err) {
                        pr_warning("failed to relocate '%s'\n",
                                   prog->section_name);
@@ -784,8 +847,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)
                Elf_Data *data = obj->efile.reloc[i].data;
                int idx = shdr->sh_info;
                struct bpf_program *prog;
-               size_t nr_maps = obj->maps_buf_sz /
-                                sizeof(struct bpf_map_def);
+               size_t nr_maps = obj->nr_maps;
 
                if (shdr->sh_type != SHT_REL) {
                        pr_warning("internal error at %d\n", __LINE__);
@@ -860,13 +922,73 @@ static int
 bpf_program__load(struct bpf_program *prog,
                  char *license, u32 kern_version)
 {
-       int err, fd;
+       int err = 0, fd, i;
 
-       err = load_program(prog->insns, prog->insns_cnt,
-                          license, kern_version, &fd);
-       if (!err)
-               prog->fd = fd;
+       if (prog->instances.nr < 0 || !prog->instances.fds) {
+               if (prog->preprocessor) {
+                       pr_warning("Internal error: can't load program '%s'\n",
+                                  prog->section_name);
+                       return -LIBBPF_ERRNO__INTERNAL;
+               }
+
+               prog->instances.fds = malloc(sizeof(int));
+               if (!prog->instances.fds) {
+                       pr_warning("Not enough memory for BPF fds\n");
+                       return -ENOMEM;
+               }
+               prog->instances.nr = 1;
+               prog->instances.fds[0] = -1;
+       }
+
+       if (!prog->preprocessor) {
+               if (prog->instances.nr != 1) {
+                       pr_warning("Program '%s' is inconsistent: nr(%d) != 1\n",
+                                  prog->section_name, prog->instances.nr);
+               }
+               err = load_program(prog->insns, prog->insns_cnt,
+                                  license, kern_version, &fd);
+               if (!err)
+                       prog->instances.fds[0] = fd;
+               goto out;
+       }
+
+       for (i = 0; i < prog->instances.nr; i++) {
+               struct bpf_prog_prep_result result;
+               bpf_program_prep_t preprocessor = prog->preprocessor;
+
+               bzero(&result, sizeof(result));
+               err = preprocessor(prog, i, prog->insns,
+                                  prog->insns_cnt, &result);
+               if (err) {
+                       pr_warning("Preprocessing the %dth instance of program '%s' failed\n",
+                                  i, prog->section_name);
+                       goto out;
+               }
+
+               if (!result.new_insn_ptr || !result.new_insn_cnt) {
+                       pr_debug("Skip loading the %dth instance of program '%s'\n",
+                                i, prog->section_name);
+                       prog->instances.fds[i] = -1;
+                       if (result.pfd)
+                               *result.pfd = -1;
+                       continue;
+               }
+
+               err = load_program(result.new_insn_ptr,
+                                  result.new_insn_cnt,
+                                  license, kern_version, &fd);
+
+               if (err) {
+                       pr_warning("Loading the %dth instance of program '%s' failed\n",
+                                       i, prog->section_name);
+                       goto out;
+               }
 
+               if (result.pfd)
+                       *result.pfd = fd;
+               prog->instances.fds[i] = fd;
+       }
+out:
        if (err)
                pr_warning("failed to load program '%s'\n",
                           prog->section_name);
@@ -970,10 +1092,8 @@ int bpf_object__unload(struct bpf_object *obj)
        if (!obj)
                return -EINVAL;
 
-       for (i = 0; i < obj->nr_map_fds; i++)
-               zclose(obj->map_fds[i]);
-       zfree(&obj->map_fds);
-       obj->nr_map_fds = 0;
+       for (i = 0; i < obj->nr_maps; i++)
+               zclose(obj->maps[i].fd);
 
        for (i = 0; i < obj->nr_programs; i++)
                bpf_program__unload(&obj->programs[i]);
@@ -1016,7 +1136,16 @@ void bpf_object__close(struct bpf_object *obj)
        bpf_object__elf_finish(obj);
        bpf_object__unload(obj);
 
-       zfree(&obj->maps_buf);
+       for (i = 0; i < obj->nr_maps; i++) {
+               zfree(&obj->maps[i].name);
+               if (obj->maps[i].clear_priv)
+                       obj->maps[i].clear_priv(&obj->maps[i],
+                                               obj->maps[i].priv);
+               obj->maps[i].priv = NULL;
+               obj->maps[i].clear_priv = NULL;
+       }
+       zfree(&obj->maps);
+       obj->nr_maps = 0;
 
        if (obj->programs && obj->nr_programs) {
                for (i = 0; i < obj->nr_programs; i++)
@@ -1121,5 +1250,142 @@ const char *bpf_program__title(struct bpf_program *prog, bool needs_copy)
 
 int bpf_program__fd(struct bpf_program *prog)
 {
-       return prog->fd;
+       return bpf_program__nth_fd(prog, 0);
+}
+
+int bpf_program__set_prep(struct bpf_program *prog, int nr_instances,
+                         bpf_program_prep_t prep)
+{
+       int *instances_fds;
+
+       if (nr_instances <= 0 || !prep)
+               return -EINVAL;
+
+       if (prog->instances.nr > 0 || prog->instances.fds) {
+               pr_warning("Can't set pre-processor after loading\n");
+               return -EINVAL;
+       }
+
+       instances_fds = malloc(sizeof(int) * nr_instances);
+       if (!instances_fds) {
+               pr_warning("alloc memory failed for fds\n");
+               return -ENOMEM;
+       }
+
+       /* fill all fd with -1 */
+       memset(instances_fds, -1, sizeof(int) * nr_instances);
+
+       prog->instances.nr = nr_instances;
+       prog->instances.fds = instances_fds;
+       prog->preprocessor = prep;
+       return 0;
+}
+
+int bpf_program__nth_fd(struct bpf_program *prog, int n)
+{
+       int fd;
+
+       if (n >= prog->instances.nr || n < 0) {
+               pr_warning("Can't get the %dth fd from program %s: only %d instances\n",
+                          n, prog->section_name, prog->instances.nr);
+               return -EINVAL;
+       }
+
+       fd = prog->instances.fds[n];
+       if (fd < 0) {
+               pr_warning("%dth instance of program '%s' is invalid\n",
+                          n, prog->section_name);
+               return -ENOENT;
+       }
+
+       return fd;
+}
+
+int bpf_map__get_fd(struct bpf_map *map)
+{
+       if (!map)
+               return -EINVAL;
+
+       return map->fd;
+}
+
+int bpf_map__get_def(struct bpf_map *map, struct bpf_map_def *pdef)
+{
+       if (!map || !pdef)
+               return -EINVAL;
+
+       *pdef = map->def;
+       return 0;
+}
+
+const char *bpf_map__get_name(struct bpf_map *map)
+{
+       if (!map)
+               return NULL;
+       return map->name;
+}
+
+int bpf_map__set_private(struct bpf_map *map, void *priv,
+                        bpf_map_clear_priv_t clear_priv)
+{
+       if (!map)
+               return -EINVAL;
+
+       if (map->priv) {
+               if (map->clear_priv)
+                       map->clear_priv(map, map->priv);
+       }
+
+       map->priv = priv;
+       map->clear_priv = clear_priv;
+       return 0;
+}
+
+int bpf_map__get_private(struct bpf_map *map, void **ppriv)
+{
+       if (!map)
+               return -EINVAL;
+
+       if (ppriv)
+               *ppriv = map->priv;
+       return 0;
+}
+
+struct bpf_map *
+bpf_map__next(struct bpf_map *prev, struct bpf_object *obj)
+{
+       size_t idx;
+       struct bpf_map *s, *e;
+
+       if (!obj || !obj->maps)
+               return NULL;
+
+       s = obj->maps;
+       e = obj->maps + obj->nr_maps;
+
+       if (prev == NULL)
+               return s;
+
+       if ((prev < s) || (prev >= e)) {
+               pr_warning("error in %s: map handler doesn't belong to object\n",
+                          __func__);
+               return NULL;
+       }
+
+       idx = (prev - obj->maps) + 1;
+       if (idx >= obj->nr_maps)
+               return NULL;
+       return &obj->maps[idx];
+}
+
+struct bpf_map *
+bpf_object__get_map_by_name(struct bpf_object *obj, const char *name)
+{
+       struct bpf_map *pos;
+
+       bpf_map__for_each(pos, obj) {
+               if (pos->name && !strcmp(pos->name, name))
+                       return pos;
+       }
+       return NULL;
 }
index c9a9aef2806cbfbef033668920ab8cae02ca2e8d..a51594c7b51865140f6e6b42c8d1400b951bea82 100644 (file)
@@ -88,6 +88,70 @@ const char *bpf_program__title(struct bpf_program *prog, bool needs_copy);
 
 int bpf_program__fd(struct bpf_program *prog);
 
+struct bpf_insn;
+
+/*
+ * Libbpf allows callers to adjust BPF programs before being loaded
+ * into kernel. One program in an object file can be transform into
+ * multiple variants to be attached to different code.
+ *
+ * bpf_program_prep_t, bpf_program__set_prep and bpf_program__nth_fd
+ * are APIs for this propose.
+ *
+ * - bpf_program_prep_t:
+ *   It defines 'preprocessor', which is a caller defined function
+ *   passed to libbpf through bpf_program__set_prep(), and will be
+ *   called before program is loaded. The processor should adjust
+ *   the program one time for each instances according to the number
+ *   passed to it.
+ *
+ * - bpf_program__set_prep:
+ *   Attachs a preprocessor to a BPF program. The number of instances
+ *   whould be created is also passed through this function.
+ *
+ * - bpf_program__nth_fd:
+ *   After the program is loaded, get resuling fds from bpf program for
+ *   each instances.
+ *
+ * If bpf_program__set_prep() is not used, the program whould be loaded
+ * without adjustment during bpf_object__load(). The program has only
+ * one instance. In this case bpf_program__fd(prog) is equal to
+ * bpf_program__nth_fd(prog, 0).
+ */
+
+struct bpf_prog_prep_result {
+       /*
+        * If not NULL, load new instruction array.
+        * If set to NULL, don't load this instance.
+        */
+       struct bpf_insn *new_insn_ptr;
+       int new_insn_cnt;
+
+       /* If not NULL, result fd is set to it */
+       int *pfd;
+};
+
+/*
+ * Parameters of bpf_program_prep_t:
+ *  - prog:    The bpf_program being loaded.
+ *  - n:       Index of instance being generated.
+ *  - insns:   BPF instructions array.
+ *  - insns_cnt:Number of instructions in insns.
+ *  - res:     Output parameter, result of transformation.
+ *
+ * Return value:
+ *  - Zero: pre-processing success.
+ *  - Non-zero: pre-processing, stop loading.
+ */
+typedef int (*bpf_program_prep_t)(struct bpf_program *prog, int n,
+                                 struct bpf_insn *insns, int insns_cnt,
+                                 struct bpf_prog_prep_result *res);
+
+int bpf_program__set_prep(struct bpf_program *prog, int nr_instance,
+                         bpf_program_prep_t prep);
+
+int bpf_program__nth_fd(struct bpf_program *prog, int n);
+
 /*
  * We don't need __attribute__((packed)) now since it is
  * unnecessary for 'bpf_map_def' because they are all aligned.
@@ -101,4 +165,28 @@ struct bpf_map_def {
        unsigned int max_entries;
 };
 
+/*
+ * There is another 'struct bpf_map' in include/linux/map.h. However,
+ * it is not a uapi header so no need to consider name clash.
+ */
+struct bpf_map;
+struct bpf_map *
+bpf_object__get_map_by_name(struct bpf_object *obj, const char *name);
+
+struct bpf_map *
+bpf_map__next(struct bpf_map *map, struct bpf_object *obj);
+#define bpf_map__for_each(pos, obj)            \
+       for ((pos) = bpf_map__next(NULL, (obj));        \
+            (pos) != NULL;                             \
+            (pos) = bpf_map__next((pos), (obj)))
+
+int bpf_map__get_fd(struct bpf_map *map);
+int bpf_map__get_def(struct bpf_map *map, struct bpf_map_def *pdef);
+const char *bpf_map__get_name(struct bpf_map *map);
+
+typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *);
+int bpf_map__set_private(struct bpf_map *map, void *priv,
+                        bpf_map_clear_priv_t clear_priv);
+int bpf_map__get_private(struct bpf_map *map, void **ppriv);
+
 #endif
diff --git a/tools/lib/find_bit.c b/tools/lib/find_bit.c
new file mode 100644 (file)
index 0000000..9122a9e
--- /dev/null
@@ -0,0 +1,84 @@
+/* bit search implementation
+ *
+ * Copied from lib/find_bit.c to tools/lib/find_bit.c
+ *
+ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * Copyright (C) 2008 IBM Corporation
+ * 'find_last_bit' is written by Rusty Russell <rusty@rustcorp.com.au>
+ * (Inspired by David Howell's find_next_bit implementation)
+ *
+ * Rewritten by Yury Norov <yury.norov@gmail.com> to decrease
+ * size and improve performance, 2015.
+ *
+ * This program is 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/bitops.h>
+#include <linux/bitmap.h>
+#include <linux/kernel.h>
+
+#if !defined(find_next_bit)
+
+/*
+ * This is a common helper function for find_next_bit and
+ * find_next_zero_bit.  The difference is the "invert" argument, which
+ * is XORed with each fetched word before searching it for one bits.
+ */
+static unsigned long _find_next_bit(const unsigned long *addr,
+               unsigned long nbits, unsigned long start, unsigned long invert)
+{
+       unsigned long tmp;
+
+       if (!nbits || start >= nbits)
+               return nbits;
+
+       tmp = addr[start / BITS_PER_LONG] ^ invert;
+
+       /* Handle 1st word. */
+       tmp &= BITMAP_FIRST_WORD_MASK(start);
+       start = round_down(start, BITS_PER_LONG);
+
+       while (!tmp) {
+               start += BITS_PER_LONG;
+               if (start >= nbits)
+                       return nbits;
+
+               tmp = addr[start / BITS_PER_LONG] ^ invert;
+       }
+
+       return min(start + __ffs(tmp), nbits);
+}
+#endif
+
+#ifndef find_next_bit
+/*
+ * Find the next set bit in a memory region.
+ */
+unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
+                           unsigned long offset)
+{
+       return _find_next_bit(addr, size, offset, 0UL);
+}
+#endif
+
+#ifndef find_first_bit
+/*
+ * Find the first set bit in a memory region.
+ */
+unsigned long find_first_bit(const unsigned long *addr, unsigned long size)
+{
+       unsigned long idx;
+
+       for (idx = 0; idx * BITS_PER_LONG < size; idx++) {
+               if (addr[idx])
+                       return min(idx * BITS_PER_LONG + __ffs(addr[idx]), size);
+       }
+
+       return size;
+}
+#endif
diff --git a/tools/lib/string.c b/tools/lib/string.c
new file mode 100644 (file)
index 0000000..bd239bc
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ *  linux/tools/lib/string.c
+ *
+ *  Copied from linux/lib/string.c, where it is:
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  More specifically, the first copied function was strtobool, which
+ *  was introduced by:
+ *
+ *  d0f1fed29e6e ("Add a strtobool function matching semantics of existing in kernel equivalents")
+ *  Author: Jonathan Cameron <jic23@cam.ac.uk>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <linux/string.h>
+#include <linux/compiler.h>
+
+/**
+ * memdup - duplicate region of memory
+ *
+ * @src: memory region to duplicate
+ * @len: memory region length
+ */
+void *memdup(const void *src, size_t len)
+{
+       void *p = malloc(len);
+
+       if (p)
+               memcpy(p, src, len);
+
+       return p;
+}
+
+/**
+ * strtobool - convert common user inputs into boolean values
+ * @s: input string
+ * @res: result
+ *
+ * This routine returns 0 iff the first character is one of 'Yy1Nn0'.
+ * Otherwise it will return -EINVAL.  Value pointed to by res is
+ * updated upon finding a match.
+ */
+int strtobool(const char *s, bool *res)
+{
+       switch (s[0]) {
+       case 'y':
+       case 'Y':
+       case '1':
+               *res = true;
+               break;
+       case 'n':
+       case 'N':
+       case '0':
+               *res = false;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/**
+ * strlcpy - Copy a C-string into a sized buffer
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @size: size of destination buffer
+ *
+ * Compatible with *BSD: the result is always a valid
+ * NUL-terminated string that fits in the buffer (unless,
+ * of course, the buffer size is zero). It does not pad
+ * out the result like strncpy() does.
+ *
+ * If libc has strlcpy() then that version will override this
+ * implementation:
+ */
+size_t __weak strlcpy(char *dest, const char *src, size_t size)
+{
+       size_t ret = strlen(src);
+
+       if (size) {
+               size_t len = (ret >= size) ? size - 1 : ret;
+               memcpy(dest, src, len);
+               dest[len] = '\0';
+       }
+       return ret;
+}
diff --git a/tools/lib/subcmd/Build b/tools/lib/subcmd/Build
new file mode 100644 (file)
index 0000000..ee31288
--- /dev/null
@@ -0,0 +1,7 @@
+libsubcmd-y += exec-cmd.o
+libsubcmd-y += help.o
+libsubcmd-y += pager.o
+libsubcmd-y += parse-options.o
+libsubcmd-y += run-command.o
+libsubcmd-y += sigchain.o
+libsubcmd-y += subcmd-config.o
diff --git a/tools/lib/subcmd/Makefile b/tools/lib/subcmd/Makefile
new file mode 100644 (file)
index 0000000..629cf8c
--- /dev/null
@@ -0,0 +1,48 @@
+include ../../scripts/Makefile.include
+include ../../perf/config/utilities.mak                # QUIET_CLEAN
+
+ifeq ($(srctree),)
+srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+#$(info Determined 'srctree' to be $(srctree))
+endif
+
+CC = $(CROSS_COMPILE)gcc
+AR = $(CROSS_COMPILE)ar
+RM = rm -f
+
+MAKEFLAGS += --no-print-directory
+
+LIBFILE = $(OUTPUT)libsubcmd.a
+
+CFLAGS := $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
+CFLAGS += -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fPIC
+CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
+
+CFLAGS += -I$(srctree)/tools/include/
+CFLAGS += -I$(srctree)/include/uapi
+CFLAGS += -I$(srctree)/include
+
+SUBCMD_IN := $(OUTPUT)libsubcmd-in.o
+
+all:
+
+export srctree OUTPUT CC LD CFLAGS V
+include $(srctree)/tools/build/Makefile.include
+
+all: fixdep $(LIBFILE)
+
+$(SUBCMD_IN): FORCE
+       @$(MAKE) $(build)=libsubcmd
+
+$(LIBFILE): $(SUBCMD_IN)
+       $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(SUBCMD_IN)
+
+clean:
+       $(call QUIET_CLEAN, libsubcmd) $(RM) $(LIBFILE); \
+       find $(if $(OUTPUT),$(OUTPUT),.) -name \*.o -or -name \*.o.cmd -or -name \*.o.d | xargs $(RM)
+
+FORCE:
+
+.PHONY: clean FORCE
diff --git a/tools/lib/subcmd/exec-cmd.c b/tools/lib/subcmd/exec-cmd.c
new file mode 100644 (file)
index 0000000..1ae833a
--- /dev/null
@@ -0,0 +1,209 @@
+#include <linux/compiler.h>
+#include <linux/string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "subcmd-util.h"
+#include "exec-cmd.h"
+#include "subcmd-config.h"
+
+#define MAX_ARGS       32
+#define PATH_MAX       4096
+
+static const char *argv_exec_path;
+static const char *argv0_path;
+
+void exec_cmd_init(const char *exec_name, const char *prefix,
+                  const char *exec_path, const char *exec_path_env)
+{
+       subcmd_config.exec_name         = exec_name;
+       subcmd_config.prefix            = prefix;
+       subcmd_config.exec_path         = exec_path;
+       subcmd_config.exec_path_env     = exec_path_env;
+}
+
+#define is_dir_sep(c) ((c) == '/')
+
+static int is_absolute_path(const char *path)
+{
+       return path[0] == '/';
+}
+
+static const char *get_pwd_cwd(void)
+{
+       static char cwd[PATH_MAX + 1];
+       char *pwd;
+       struct stat cwd_stat, pwd_stat;
+       if (getcwd(cwd, PATH_MAX) == NULL)
+               return NULL;
+       pwd = getenv("PWD");
+       if (pwd && strcmp(pwd, cwd)) {
+               stat(cwd, &cwd_stat);
+               if (!stat(pwd, &pwd_stat) &&
+                   pwd_stat.st_dev == cwd_stat.st_dev &&
+                   pwd_stat.st_ino == cwd_stat.st_ino) {
+                       strlcpy(cwd, pwd, PATH_MAX);
+               }
+       }
+       return cwd;
+}
+
+static const char *make_nonrelative_path(const char *path)
+{
+       static char buf[PATH_MAX + 1];
+
+       if (is_absolute_path(path)) {
+               if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
+                       die("Too long path: %.*s", 60, path);
+       } else {
+               const char *cwd = get_pwd_cwd();
+               if (!cwd)
+                       die("Cannot determine the current working directory");
+               if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX)
+                       die("Too long path: %.*s", 60, path);
+       }
+       return buf;
+}
+
+char *system_path(const char *path)
+{
+       char *buf = NULL;
+
+       if (is_absolute_path(path))
+               return strdup(path);
+
+       astrcatf(&buf, "%s/%s", subcmd_config.prefix, path);
+
+       return buf;
+}
+
+const char *extract_argv0_path(const char *argv0)
+{
+       const char *slash;
+
+       if (!argv0 || !*argv0)
+               return NULL;
+       slash = argv0 + strlen(argv0);
+
+       while (argv0 <= slash && !is_dir_sep(*slash))
+               slash--;
+
+       if (slash >= argv0) {
+               argv0_path = strndup(argv0, slash - argv0);
+               return argv0_path ? slash + 1 : NULL;
+       }
+
+       return argv0;
+}
+
+void set_argv_exec_path(const char *exec_path)
+{
+       argv_exec_path = exec_path;
+       /*
+        * Propagate this setting to external programs.
+        */
+       setenv(subcmd_config.exec_path_env, exec_path, 1);
+}
+
+
+/* Returns the highest-priority location to look for subprograms. */
+char *get_argv_exec_path(void)
+{
+       char *env;
+
+       if (argv_exec_path)
+               return strdup(argv_exec_path);
+
+       env = getenv(subcmd_config.exec_path_env);
+       if (env && *env)
+               return strdup(env);
+
+       return system_path(subcmd_config.exec_path);
+}
+
+static void add_path(char **out, const char *path)
+{
+       if (path && *path) {
+               if (is_absolute_path(path))
+                       astrcat(out, path);
+               else
+                       astrcat(out, make_nonrelative_path(path));
+
+               astrcat(out, ":");
+       }
+}
+
+void setup_path(void)
+{
+       const char *old_path = getenv("PATH");
+       char *new_path = NULL;
+       char *tmp = get_argv_exec_path();
+
+       add_path(&new_path, tmp);
+       add_path(&new_path, argv0_path);
+       free(tmp);
+
+       if (old_path)
+               astrcat(&new_path, old_path);
+       else
+               astrcat(&new_path, "/usr/local/bin:/usr/bin:/bin");
+
+       setenv("PATH", new_path, 1);
+
+       free(new_path);
+}
+
+static const char **prepare_exec_cmd(const char **argv)
+{
+       int argc;
+       const char **nargv;
+
+       for (argc = 0; argv[argc]; argc++)
+               ; /* just counting */
+       nargv = malloc(sizeof(*nargv) * (argc + 2));
+
+       nargv[0] = subcmd_config.exec_name;
+       for (argc = 0; argv[argc]; argc++)
+               nargv[argc + 1] = argv[argc];
+       nargv[argc + 1] = NULL;
+       return nargv;
+}
+
+int execv_cmd(const char **argv) {
+       const char **nargv = prepare_exec_cmd(argv);
+
+       /* execvp() can only ever return if it fails */
+       execvp(subcmd_config.exec_name, (char **)nargv);
+
+       free(nargv);
+       return -1;
+}
+
+
+int execl_cmd(const char *cmd,...)
+{
+       int argc;
+       const char *argv[MAX_ARGS + 1];
+       const char *arg;
+       va_list param;
+
+       va_start(param, cmd);
+       argv[0] = cmd;
+       argc = 1;
+       while (argc < MAX_ARGS) {
+               arg = argv[argc++] = va_arg(param, char *);
+               if (!arg)
+                       break;
+       }
+       va_end(param);
+       if (MAX_ARGS <= argc) {
+               fprintf(stderr, " Error: too many args to run %s\n", cmd);
+               return -1;
+       }
+
+       argv[argc] = NULL;
+       return execv_cmd(argv);
+}
diff --git a/tools/lib/subcmd/exec-cmd.h b/tools/lib/subcmd/exec-cmd.h
new file mode 100644 (file)
index 0000000..5d08bda
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __SUBCMD_EXEC_CMD_H
+#define __SUBCMD_EXEC_CMD_H
+
+extern void exec_cmd_init(const char *exec_name, const char *prefix,
+                         const char *exec_path, const char *exec_path_env);
+
+extern void set_argv_exec_path(const char *exec_path);
+extern const char *extract_argv0_path(const char *path);
+extern void setup_path(void);
+extern int execv_cmd(const char **argv); /* NULL terminated */
+extern int execl_cmd(const char *cmd, ...);
+/* get_argv_exec_path and system_path return malloc'd string, caller must free it */
+extern char *get_argv_exec_path(void);
+extern char *system_path(const char *path);
+
+#endif /* __SUBCMD_EXEC_CMD_H */
diff --git a/tools/lib/subcmd/help.c b/tools/lib/subcmd/help.c
new file mode 100644 (file)
index 0000000..e228c3c
--- /dev/null
@@ -0,0 +1,268 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include "subcmd-util.h"
+#include "help.h"
+#include "exec-cmd.h"
+
+void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
+{
+       struct cmdname *ent = malloc(sizeof(*ent) + len + 1);
+
+       ent->len = len;
+       memcpy(ent->name, name, len);
+       ent->name[len] = 0;
+
+       ALLOC_GROW(cmds->names, cmds->cnt + 1, cmds->alloc);
+       cmds->names[cmds->cnt++] = ent;
+}
+
+void clean_cmdnames(struct cmdnames *cmds)
+{
+       unsigned int i;
+
+       for (i = 0; i < cmds->cnt; ++i)
+               zfree(&cmds->names[i]);
+       zfree(&cmds->names);
+       cmds->cnt = 0;
+       cmds->alloc = 0;
+}
+
+int cmdname_compare(const void *a_, const void *b_)
+{
+       struct cmdname *a = *(struct cmdname **)a_;
+       struct cmdname *b = *(struct cmdname **)b_;
+       return strcmp(a->name, b->name);
+}
+
+void uniq(struct cmdnames *cmds)
+{
+       unsigned int i, j;
+
+       if (!cmds->cnt)
+               return;
+
+       for (i = j = 1; i < cmds->cnt; i++)
+               if (strcmp(cmds->names[i]->name, cmds->names[i-1]->name))
+                       cmds->names[j++] = cmds->names[i];
+
+       cmds->cnt = j;
+}
+
+void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
+{
+       size_t ci, cj, ei;
+       int cmp;
+
+       ci = cj = ei = 0;
+       while (ci < cmds->cnt && ei < excludes->cnt) {
+               cmp = strcmp(cmds->names[ci]->name, excludes->names[ei]->name);
+               if (cmp < 0)
+                       cmds->names[cj++] = cmds->names[ci++];
+               else if (cmp == 0)
+                       ci++, ei++;
+               else if (cmp > 0)
+                       ei++;
+       }
+
+       while (ci < cmds->cnt)
+               cmds->names[cj++] = cmds->names[ci++];
+
+       cmds->cnt = cj;
+}
+
+static void get_term_dimensions(struct winsize *ws)
+{
+       char *s = getenv("LINES");
+
+       if (s != NULL) {
+               ws->ws_row = atoi(s);
+               s = getenv("COLUMNS");
+               if (s != NULL) {
+                       ws->ws_col = atoi(s);
+                       if (ws->ws_row && ws->ws_col)
+                               return;
+               }
+       }
+#ifdef TIOCGWINSZ
+       if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
+           ws->ws_row && ws->ws_col)
+               return;
+#endif
+       ws->ws_row = 25;
+       ws->ws_col = 80;
+}
+
+static void pretty_print_string_list(struct cmdnames *cmds, int longest)
+{
+       int cols = 1, rows;
+       int space = longest + 1; /* min 1 SP between words */
+       struct winsize win;
+       int max_cols;
+       int i, j;
+
+       get_term_dimensions(&win);
+       max_cols = win.ws_col - 1; /* don't print *on* the edge */
+
+       if (space < max_cols)
+               cols = max_cols / space;
+       rows = (cmds->cnt + cols - 1) / cols;
+
+       for (i = 0; i < rows; i++) {
+               printf("  ");
+
+               for (j = 0; j < cols; j++) {
+                       unsigned int n = j * rows + i;
+                       unsigned int size = space;
+
+                       if (n >= cmds->cnt)
+                               break;
+                       if (j == cols-1 || n + rows >= cmds->cnt)
+                               size = 1;
+                       printf("%-*s", size, cmds->names[n]->name);
+               }
+               putchar('\n');
+       }
+}
+
+static int is_executable(const char *name)
+{
+       struct stat st;
+
+       if (stat(name, &st) || /* stat, not lstat */
+           !S_ISREG(st.st_mode))
+               return 0;
+
+       return st.st_mode & S_IXUSR;
+}
+
+static int has_extension(const char *filename, const char *ext)
+{
+       size_t len = strlen(filename);
+       size_t extlen = strlen(ext);
+
+       return len > extlen && !memcmp(filename + len - extlen, ext, extlen);
+}
+
+static void list_commands_in_dir(struct cmdnames *cmds,
+                                        const char *path,
+                                        const char *prefix)
+{
+       int prefix_len;
+       DIR *dir = opendir(path);
+       struct dirent *de;
+       char *buf = NULL;
+
+       if (!dir)
+               return;
+       if (!prefix)
+               prefix = "perf-";
+       prefix_len = strlen(prefix);
+
+       astrcatf(&buf, "%s/", path);
+
+       while ((de = readdir(dir)) != NULL) {
+               int entlen;
+
+               if (prefixcmp(de->d_name, prefix))
+                       continue;
+
+               astrcat(&buf, de->d_name);
+               if (!is_executable(buf))
+                       continue;
+
+               entlen = strlen(de->d_name) - prefix_len;
+               if (has_extension(de->d_name, ".exe"))
+                       entlen -= 4;
+
+               add_cmdname(cmds, de->d_name + prefix_len, entlen);
+       }
+       closedir(dir);
+       free(buf);
+}
+
+void load_command_list(const char *prefix,
+               struct cmdnames *main_cmds,
+               struct cmdnames *other_cmds)
+{
+       const char *env_path = getenv("PATH");
+       char *exec_path = get_argv_exec_path();
+
+       if (exec_path) {
+               list_commands_in_dir(main_cmds, exec_path, prefix);
+               qsort(main_cmds->names, main_cmds->cnt,
+                     sizeof(*main_cmds->names), cmdname_compare);
+               uniq(main_cmds);
+       }
+
+       if (env_path) {
+               char *paths, *path, *colon;
+               path = paths = strdup(env_path);
+               while (1) {
+                       if ((colon = strchr(path, ':')))
+                               *colon = 0;
+                       if (!exec_path || strcmp(path, exec_path))
+                               list_commands_in_dir(other_cmds, path, prefix);
+
+                       if (!colon)
+                               break;
+                       path = colon + 1;
+               }
+               free(paths);
+
+               qsort(other_cmds->names, other_cmds->cnt,
+                     sizeof(*other_cmds->names), cmdname_compare);
+               uniq(other_cmds);
+       }
+       free(exec_path);
+       exclude_cmds(other_cmds, main_cmds);
+}
+
+void list_commands(const char *title, struct cmdnames *main_cmds,
+                  struct cmdnames *other_cmds)
+{
+       unsigned int i, longest = 0;
+
+       for (i = 0; i < main_cmds->cnt; i++)
+               if (longest < main_cmds->names[i]->len)
+                       longest = main_cmds->names[i]->len;
+       for (i = 0; i < other_cmds->cnt; i++)
+               if (longest < other_cmds->names[i]->len)
+                       longest = other_cmds->names[i]->len;
+
+       if (main_cmds->cnt) {
+               char *exec_path = get_argv_exec_path();
+               printf("available %s in '%s'\n", title, exec_path);
+               printf("----------------");
+               mput_char('-', strlen(title) + strlen(exec_path));
+               putchar('\n');
+               pretty_print_string_list(main_cmds, longest);
+               putchar('\n');
+               free(exec_path);
+       }
+
+       if (other_cmds->cnt) {
+               printf("%s available from elsewhere on your $PATH\n", title);
+               printf("---------------------------------------");
+               mput_char('-', strlen(title));
+               putchar('\n');
+               pretty_print_string_list(other_cmds, longest);
+               putchar('\n');
+       }
+}
+
+int is_in_cmdlist(struct cmdnames *c, const char *s)
+{
+       unsigned int i;
+
+       for (i = 0; i < c->cnt; i++)
+               if (!strcmp(s, c->names[i]->name))
+                       return 1;
+       return 0;
+}
diff --git a/tools/lib/subcmd/help.h b/tools/lib/subcmd/help.h
new file mode 100644 (file)
index 0000000..e145a02
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __SUBCMD_HELP_H
+#define __SUBCMD_HELP_H
+
+#include <sys/types.h>
+
+struct cmdnames {
+       size_t alloc;
+       size_t cnt;
+       struct cmdname {
+               size_t len; /* also used for similarity index in help.c */
+               char name[];
+       } **names;
+};
+
+static inline void mput_char(char c, unsigned int num)
+{
+       while(num--)
+               putchar(c);
+}
+
+void load_command_list(const char *prefix,
+               struct cmdnames *main_cmds,
+               struct cmdnames *other_cmds);
+void add_cmdname(struct cmdnames *cmds, const char *name, size_t len);
+void clean_cmdnames(struct cmdnames *cmds);
+int cmdname_compare(const void *a, const void *b);
+void uniq(struct cmdnames *cmds);
+/* Here we require that excludes is a sorted list. */
+void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
+int is_in_cmdlist(struct cmdnames *c, const char *s);
+void list_commands(const char *title, struct cmdnames *main_cmds,
+                  struct cmdnames *other_cmds);
+
+#endif /* __SUBCMD_HELP_H */
diff --git a/tools/lib/subcmd/pager.c b/tools/lib/subcmd/pager.c
new file mode 100644 (file)
index 0000000..d50f3b5
--- /dev/null
@@ -0,0 +1,100 @@
+#include <sys/select.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include "pager.h"
+#include "run-command.h"
+#include "sigchain.h"
+#include "subcmd-config.h"
+
+/*
+ * This is split up from the rest of git so that we can do
+ * something different on Windows.
+ */
+
+static int spawned_pager;
+
+void pager_init(const char *pager_env)
+{
+       subcmd_config.pager_env = pager_env;
+}
+
+static void pager_preexec(void)
+{
+       /*
+        * Work around bug in "less" by not starting it until we
+        * have real input
+        */
+       fd_set in;
+
+       FD_ZERO(&in);
+       FD_SET(0, &in);
+       select(1, &in, NULL, &in, NULL);
+
+       setenv("LESS", "FRSX", 0);
+}
+
+static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
+static struct child_process pager_process;
+
+static void wait_for_pager(void)
+{
+       fflush(stdout);
+       fflush(stderr);
+       /* signal EOF to pager */
+       close(1);
+       close(2);
+       finish_command(&pager_process);
+}
+
+static void wait_for_pager_signal(int signo)
+{
+       wait_for_pager();
+       sigchain_pop(signo);
+       raise(signo);
+}
+
+void setup_pager(void)
+{
+       const char *pager = getenv(subcmd_config.pager_env);
+
+       if (!isatty(1))
+               return;
+       if (!pager)
+               pager = getenv("PAGER");
+       if (!(pager || access("/usr/bin/pager", X_OK)))
+               pager = "/usr/bin/pager";
+       if (!(pager || access("/usr/bin/less", X_OK)))
+               pager = "/usr/bin/less";
+       if (!pager)
+               pager = "cat";
+       if (!*pager || !strcmp(pager, "cat"))
+               return;
+
+       spawned_pager = 1; /* means we are emitting to terminal */
+
+       /* spawn the pager */
+       pager_argv[2] = pager;
+       pager_process.argv = pager_argv;
+       pager_process.in = -1;
+       pager_process.preexec_cb = pager_preexec;
+
+       if (start_command(&pager_process))
+               return;
+
+       /* original process continues, but writes to the pipe */
+       dup2(pager_process.in, 1);
+       if (isatty(2))
+               dup2(pager_process.in, 2);
+       close(pager_process.in);
+
+       /* this makes sure that the parent terminates after the pager */
+       sigchain_push_common(wait_for_pager_signal);
+       atexit(wait_for_pager);
+}
+
+int pager_in_use(void)
+{
+       return spawned_pager;
+}
diff --git a/tools/lib/subcmd/pager.h b/tools/lib/subcmd/pager.h
new file mode 100644 (file)
index 0000000..8b83714
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __SUBCMD_PAGER_H
+#define __SUBCMD_PAGER_H
+
+extern void pager_init(const char *pager_env);
+
+extern void setup_pager(void);
+extern int pager_in_use(void);
+
+#endif /* __SUBCMD_PAGER_H */
diff --git a/tools/lib/subcmd/parse-options.c b/tools/lib/subcmd/parse-options.c
new file mode 100644 (file)
index 0000000..981bb44
--- /dev/null
@@ -0,0 +1,983 @@
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <ctype.h>
+#include "subcmd-util.h"
+#include "parse-options.h"
+#include "subcmd-config.h"
+#include "pager.h"
+
+#define OPT_SHORT 1
+#define OPT_UNSET 2
+
+char *error_buf;
+
+static int opterror(const struct option *opt, const char *reason, int flags)
+{
+       if (flags & OPT_SHORT)
+               fprintf(stderr, " Error: switch `%c' %s", opt->short_name, reason);
+       else if (flags & OPT_UNSET)
+               fprintf(stderr, " Error: option `no-%s' %s", opt->long_name, reason);
+       else
+               fprintf(stderr, " Error: option `%s' %s", opt->long_name, reason);
+
+       return -1;
+}
+
+static const char *skip_prefix(const char *str, const char *prefix)
+{
+       size_t len = strlen(prefix);
+       return strncmp(str, prefix, len) ? NULL : str + len;
+}
+
+static void optwarning(const struct option *opt, const char *reason, int flags)
+{
+       if (flags & OPT_SHORT)
+               fprintf(stderr, " Warning: switch `%c' %s", opt->short_name, reason);
+       else if (flags & OPT_UNSET)
+               fprintf(stderr, " Warning: option `no-%s' %s", opt->long_name, reason);
+       else
+               fprintf(stderr, " Warning: option `%s' %s", opt->long_name, reason);
+}
+
+static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
+                  int flags, const char **arg)
+{
+       const char *res;
+
+       if (p->opt) {
+               res = p->opt;
+               p->opt = NULL;
+       } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
+                   **(p->argv + 1) == '-')) {
+               res = (const char *)opt->defval;
+       } else if (p->argc > 1) {
+               p->argc--;
+               res = *++p->argv;
+       } else
+               return opterror(opt, "requires a value", flags);
+       if (arg)
+               *arg = res;
+       return 0;
+}
+
+static int get_value(struct parse_opt_ctx_t *p,
+                    const struct option *opt, int flags)
+{
+       const char *s, *arg = NULL;
+       const int unset = flags & OPT_UNSET;
+       int err;
+
+       if (unset && p->opt)
+               return opterror(opt, "takes no value", flags);
+       if (unset && (opt->flags & PARSE_OPT_NONEG))
+               return opterror(opt, "isn't available", flags);
+       if (opt->flags & PARSE_OPT_DISABLED)
+               return opterror(opt, "is not usable", flags);
+
+       if (opt->flags & PARSE_OPT_EXCLUSIVE) {
+               if (p->excl_opt && p->excl_opt != opt) {
+                       char msg[128];
+
+                       if (((flags & OPT_SHORT) && p->excl_opt->short_name) ||
+                           p->excl_opt->long_name == NULL) {
+                               snprintf(msg, sizeof(msg), "cannot be used with switch `%c'",
+                                        p->excl_opt->short_name);
+                       } else {
+                               snprintf(msg, sizeof(msg), "cannot be used with %s",
+                                        p->excl_opt->long_name);
+                       }
+                       opterror(opt, msg, flags);
+                       return -3;
+               }
+               p->excl_opt = opt;
+       }
+       if (!(flags & OPT_SHORT) && p->opt) {
+               switch (opt->type) {
+               case OPTION_CALLBACK:
+                       if (!(opt->flags & PARSE_OPT_NOARG))
+                               break;
+                       /* FALLTHROUGH */
+               case OPTION_BOOLEAN:
+               case OPTION_INCR:
+               case OPTION_BIT:
+               case OPTION_SET_UINT:
+               case OPTION_SET_PTR:
+                       return opterror(opt, "takes no value", flags);
+               case OPTION_END:
+               case OPTION_ARGUMENT:
+               case OPTION_GROUP:
+               case OPTION_STRING:
+               case OPTION_INTEGER:
+               case OPTION_UINTEGER:
+               case OPTION_LONG:
+               case OPTION_U64:
+               default:
+                       break;
+               }
+       }
+
+       if (opt->flags & PARSE_OPT_NOBUILD) {
+               char reason[128];
+               bool noarg = false;
+
+               err = snprintf(reason, sizeof(reason),
+                               opt->flags & PARSE_OPT_CANSKIP ?
+                                       "is being ignored because %s " :
+                                       "is not available because %s",
+                               opt->build_opt);
+               reason[sizeof(reason) - 1] = '\0';
+
+               if (err < 0)
+                       strncpy(reason, opt->flags & PARSE_OPT_CANSKIP ?
+                                       "is being ignored" :
+                                       "is not available",
+                                       sizeof(reason));
+
+               if (!(opt->flags & PARSE_OPT_CANSKIP))
+                       return opterror(opt, reason, flags);
+
+               err = 0;
+               if (unset)
+                       noarg = true;
+               if (opt->flags & PARSE_OPT_NOARG)
+                       noarg = true;
+               if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
+                       noarg = true;
+
+               switch (opt->type) {
+               case OPTION_BOOLEAN:
+               case OPTION_INCR:
+               case OPTION_BIT:
+               case OPTION_SET_UINT:
+               case OPTION_SET_PTR:
+               case OPTION_END:
+               case OPTION_ARGUMENT:
+               case OPTION_GROUP:
+                       noarg = true;
+                       break;
+               case OPTION_CALLBACK:
+               case OPTION_STRING:
+               case OPTION_INTEGER:
+               case OPTION_UINTEGER:
+               case OPTION_LONG:
+               case OPTION_U64:
+               default:
+                       break;
+               }
+
+               if (!noarg)
+                       err = get_arg(p, opt, flags, NULL);
+               if (err)
+                       return err;
+
+               optwarning(opt, reason, flags);
+               return 0;
+       }
+
+       switch (opt->type) {
+       case OPTION_BIT:
+               if (unset)
+                       *(int *)opt->value &= ~opt->defval;
+               else
+                       *(int *)opt->value |= opt->defval;
+               return 0;
+
+       case OPTION_BOOLEAN:
+               *(bool *)opt->value = unset ? false : true;
+               if (opt->set)
+                       *(bool *)opt->set = true;
+               return 0;
+
+       case OPTION_INCR:
+               *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
+               return 0;
+
+       case OPTION_SET_UINT:
+               *(unsigned int *)opt->value = unset ? 0 : opt->defval;
+               return 0;
+
+       case OPTION_SET_PTR:
+               *(void **)opt->value = unset ? NULL : (void *)opt->defval;
+               return 0;
+
+       case OPTION_STRING:
+               err = 0;
+               if (unset)
+                       *(const char **)opt->value = NULL;
+               else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
+                       *(const char **)opt->value = (const char *)opt->defval;
+               else
+                       err = get_arg(p, opt, flags, (const char **)opt->value);
+
+               /* PARSE_OPT_NOEMPTY: Allow NULL but disallow empty string. */
+               if (opt->flags & PARSE_OPT_NOEMPTY) {
+                       const char *val = *(const char **)opt->value;
+
+                       if (!val)
+                               return err;
+
+                       /* Similar to unset if we are given an empty string. */
+                       if (val[0] == '\0') {
+                               *(const char **)opt->value = NULL;
+                               return 0;
+                       }
+               }
+
+               return err;
+
+       case OPTION_CALLBACK:
+               if (unset)
+                       return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
+               if (opt->flags & PARSE_OPT_NOARG)
+                       return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
+               if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
+                       return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
+               if (get_arg(p, opt, flags, &arg))
+                       return -1;
+               return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
+
+       case OPTION_INTEGER:
+               if (unset) {
+                       *(int *)opt->value = 0;
+                       return 0;
+               }
+               if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
+                       *(int *)opt->value = opt->defval;
+                       return 0;
+               }
+               if (get_arg(p, opt, flags, &arg))
+                       return -1;
+               *(int *)opt->value = strtol(arg, (char **)&s, 10);
+               if (*s)
+                       return opterror(opt, "expects a numerical value", flags);
+               return 0;
+
+       case OPTION_UINTEGER:
+               if (unset) {
+                       *(unsigned int *)opt->value = 0;
+                       return 0;
+               }
+               if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
+                       *(unsigned int *)opt->value = opt->defval;
+                       return 0;
+               }
+               if (get_arg(p, opt, flags, &arg))
+                       return -1;
+               *(unsigned int *)opt->value = strtol(arg, (char **)&s, 10);
+               if (*s)
+                       return opterror(opt, "expects a numerical value", flags);
+               return 0;
+
+       case OPTION_LONG:
+               if (unset) {
+                       *(long *)opt->value = 0;
+                       return 0;
+               }
+               if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
+                       *(long *)opt->value = opt->defval;
+                       return 0;
+               }
+               if (get_arg(p, opt, flags, &arg))
+                       return -1;
+               *(long *)opt->value = strtol(arg, (char **)&s, 10);
+               if (*s)
+                       return opterror(opt, "expects a numerical value", flags);
+               return 0;
+
+       case OPTION_U64:
+               if (unset) {
+                       *(u64 *)opt->value = 0;
+                       return 0;
+               }
+               if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
+                       *(u64 *)opt->value = opt->defval;
+                       return 0;
+               }
+               if (get_arg(p, opt, flags, &arg))
+                       return -1;
+               *(u64 *)opt->value = strtoull(arg, (char **)&s, 10);
+               if (*s)
+                       return opterror(opt, "expects a numerical value", flags);
+               return 0;
+
+       case OPTION_END:
+       case OPTION_ARGUMENT:
+       case OPTION_GROUP:
+       default:
+               die("should not happen, someone must be hit on the forehead");
+       }
+}
+
+static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
+{
+       for (; options->type != OPTION_END; options++) {
+               if (options->short_name == *p->opt) {
+                       p->opt = p->opt[1] ? p->opt + 1 : NULL;
+                       return get_value(p, options, OPT_SHORT);
+               }
+       }
+       return -2;
+}
+
+static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
+                          const struct option *options)
+{
+       const char *arg_end = strchr(arg, '=');
+       const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
+       int abbrev_flags = 0, ambiguous_flags = 0;
+
+       if (!arg_end)
+               arg_end = arg + strlen(arg);
+
+       for (; options->type != OPTION_END; options++) {
+               const char *rest;
+               int flags = 0;
+
+               if (!options->long_name)
+                       continue;
+
+               rest = skip_prefix(arg, options->long_name);
+               if (options->type == OPTION_ARGUMENT) {
+                       if (!rest)
+                               continue;
+                       if (*rest == '=')
+                               return opterror(options, "takes no value", flags);
+                       if (*rest)
+                               continue;
+                       p->out[p->cpidx++] = arg - 2;
+                       return 0;
+               }
+               if (!rest) {
+                       if (!prefixcmp(options->long_name, "no-")) {
+                               /*
+                                * The long name itself starts with "no-", so
+                                * accept the option without "no-" so that users
+                                * do not have to enter "no-no-" to get the
+                                * negation.
+                                */
+                               rest = skip_prefix(arg, options->long_name + 3);
+                               if (rest) {
+                                       flags |= OPT_UNSET;
+                                       goto match;
+                               }
+                               /* Abbreviated case */
+                               if (!prefixcmp(options->long_name + 3, arg)) {
+                                       flags |= OPT_UNSET;
+                                       goto is_abbreviated;
+                               }
+                       }
+                       /* abbreviated? */
+                       if (!strncmp(options->long_name, arg, arg_end - arg)) {
+is_abbreviated:
+                               if (abbrev_option) {
+                                       /*
+                                        * If this is abbreviated, it is
+                                        * ambiguous. So when there is no
+                                        * exact match later, we need to
+                                        * error out.
+                                        */
+                                       ambiguous_option = abbrev_option;
+                                       ambiguous_flags = abbrev_flags;
+                               }
+                               if (!(flags & OPT_UNSET) && *arg_end)
+                                       p->opt = arg_end + 1;
+                               abbrev_option = options;
+                               abbrev_flags = flags;
+                               continue;
+                       }
+                       /* negated and abbreviated very much? */
+                       if (!prefixcmp("no-", arg)) {
+                               flags |= OPT_UNSET;
+                               goto is_abbreviated;
+                       }
+                       /* negated? */
+                       if (strncmp(arg, "no-", 3))
+                               continue;
+                       flags |= OPT_UNSET;
+                       rest = skip_prefix(arg + 3, options->long_name);
+                       /* abbreviated and negated? */
+                       if (!rest && !prefixcmp(options->long_name, arg + 3))
+                               goto is_abbreviated;
+                       if (!rest)
+                               continue;
+               }
+match:
+               if (*rest) {
+                       if (*rest != '=')
+                               continue;
+                       p->opt = rest + 1;
+               }
+               return get_value(p, options, flags);
+       }
+
+       if (ambiguous_option) {
+                fprintf(stderr,
+                        " Error: Ambiguous option: %s (could be --%s%s or --%s%s)",
+                        arg,
+                        (ambiguous_flags & OPT_UNSET) ?  "no-" : "",
+                        ambiguous_option->long_name,
+                        (abbrev_flags & OPT_UNSET) ?  "no-" : "",
+                        abbrev_option->long_name);
+                return -1;
+       }
+       if (abbrev_option)
+               return get_value(p, abbrev_option, abbrev_flags);
+       return -2;
+}
+
+static void check_typos(const char *arg, const struct option *options)
+{
+       if (strlen(arg) < 3)
+               return;
+
+       if (!prefixcmp(arg, "no-")) {
+               fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)", arg);
+               exit(129);
+       }
+
+       for (; options->type != OPTION_END; options++) {
+               if (!options->long_name)
+                       continue;
+               if (!prefixcmp(options->long_name, arg)) {
+                       fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)", arg);
+                       exit(129);
+               }
+       }
+}
+
+static void parse_options_start(struct parse_opt_ctx_t *ctx,
+                               int argc, const char **argv, int flags)
+{
+       memset(ctx, 0, sizeof(*ctx));
+       ctx->argc = argc - 1;
+       ctx->argv = argv + 1;
+       ctx->out  = argv;
+       ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
+       ctx->flags = flags;
+       if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
+           (flags & PARSE_OPT_STOP_AT_NON_OPTION))
+               die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
+}
+
+static int usage_with_options_internal(const char * const *,
+                                      const struct option *, int,
+                                      struct parse_opt_ctx_t *);
+
+static int parse_options_step(struct parse_opt_ctx_t *ctx,
+                             const struct option *options,
+                             const char * const usagestr[])
+{
+       int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
+       int excl_short_opt = 1;
+       const char *arg;
+
+       /* we must reset ->opt, unknown short option leave it dangling */
+       ctx->opt = NULL;
+
+       for (; ctx->argc; ctx->argc--, ctx->argv++) {
+               arg = ctx->argv[0];
+               if (*arg != '-' || !arg[1]) {
+                       if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
+                               break;
+                       ctx->out[ctx->cpidx++] = ctx->argv[0];
+                       continue;
+               }
+
+               if (arg[1] != '-') {
+                       ctx->opt = ++arg;
+                       if (internal_help && *ctx->opt == 'h') {
+                               return usage_with_options_internal(usagestr, options, 0, ctx);
+                       }
+                       switch (parse_short_opt(ctx, options)) {
+                       case -1:
+                               return parse_options_usage(usagestr, options, arg, 1);
+                       case -2:
+                               goto unknown;
+                       case -3:
+                               goto exclusive;
+                       default:
+                               break;
+                       }
+                       if (ctx->opt)
+                               check_typos(arg, options);
+                       while (ctx->opt) {
+                               if (internal_help && *ctx->opt == 'h')
+                                       return usage_with_options_internal(usagestr, options, 0, ctx);
+                               arg = ctx->opt;
+                               switch (parse_short_opt(ctx, options)) {
+                               case -1:
+                                       return parse_options_usage(usagestr, options, arg, 1);
+                               case -2:
+                                       /* fake a short option thing to hide the fact that we may have
+                                        * started to parse aggregated stuff
+                                        *
+                                        * This is leaky, too bad.
+                                        */
+                                       ctx->argv[0] = strdup(ctx->opt - 1);
+                                       *(char *)ctx->argv[0] = '-';
+                                       goto unknown;
+                               case -3:
+                                       goto exclusive;
+                               default:
+                                       break;
+                               }
+                       }
+                       continue;
+               }
+
+               if (!arg[2]) { /* "--" */
+                       if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
+                               ctx->argc--;
+                               ctx->argv++;
+                       }
+                       break;
+               }
+
+               arg += 2;
+               if (internal_help && !strcmp(arg, "help-all"))
+                       return usage_with_options_internal(usagestr, options, 1, ctx);
+               if (internal_help && !strcmp(arg, "help"))
+                       return usage_with_options_internal(usagestr, options, 0, ctx);
+               if (!strcmp(arg, "list-opts"))
+                       return PARSE_OPT_LIST_OPTS;
+               if (!strcmp(arg, "list-cmds"))
+                       return PARSE_OPT_LIST_SUBCMDS;
+               switch (parse_long_opt(ctx, arg, options)) {
+               case -1:
+                       return parse_options_usage(usagestr, options, arg, 0);
+               case -2:
+                       goto unknown;
+               case -3:
+                       excl_short_opt = 0;
+                       goto exclusive;
+               default:
+                       break;
+               }
+               continue;
+unknown:
+               if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
+                       return PARSE_OPT_UNKNOWN;
+               ctx->out[ctx->cpidx++] = ctx->argv[0];
+               ctx->opt = NULL;
+       }
+       return PARSE_OPT_DONE;
+
+exclusive:
+       parse_options_usage(usagestr, options, arg, excl_short_opt);
+       if ((excl_short_opt && ctx->excl_opt->short_name) ||
+           ctx->excl_opt->long_name == NULL) {
+               char opt = ctx->excl_opt->short_name;
+               parse_options_usage(NULL, options, &opt, 1);
+       } else {
+               parse_options_usage(NULL, options, ctx->excl_opt->long_name, 0);
+       }
+       return PARSE_OPT_HELP;
+}
+
+static int parse_options_end(struct parse_opt_ctx_t *ctx)
+{
+       memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
+       ctx->out[ctx->cpidx + ctx->argc] = NULL;
+       return ctx->cpidx + ctx->argc;
+}
+
+int parse_options_subcommand(int argc, const char **argv, const struct option *options,
+                       const char *const subcommands[], const char *usagestr[], int flags)
+{
+       struct parse_opt_ctx_t ctx;
+
+       /* build usage string if it's not provided */
+       if (subcommands && !usagestr[0]) {
+               char *buf = NULL;
+
+               astrcatf(&buf, "%s %s [<options>] {", subcmd_config.exec_name, argv[0]);
+
+               for (int i = 0; subcommands[i]; i++) {
+                       if (i)
+                               astrcat(&buf, "|");
+                       astrcat(&buf, subcommands[i]);
+               }
+               astrcat(&buf, "}");
+
+               usagestr[0] = buf;
+       }
+
+       parse_options_start(&ctx, argc, argv, flags);
+       switch (parse_options_step(&ctx, options, usagestr)) {
+       case PARSE_OPT_HELP:
+               exit(129);
+       case PARSE_OPT_DONE:
+               break;
+       case PARSE_OPT_LIST_OPTS:
+               while (options->type != OPTION_END) {
+                       if (options->long_name)
+                               printf("--%s ", options->long_name);
+                       options++;
+               }
+               putchar('\n');
+               exit(130);
+       case PARSE_OPT_LIST_SUBCMDS:
+               if (subcommands) {
+                       for (int i = 0; subcommands[i]; i++)
+                               printf("%s ", subcommands[i]);
+               }
+               putchar('\n');
+               exit(130);
+       default: /* PARSE_OPT_UNKNOWN */
+               if (ctx.argv[0][1] == '-')
+                       astrcatf(&error_buf, "unknown option `%s'",
+                                ctx.argv[0] + 2);
+               else
+                       astrcatf(&error_buf, "unknown switch `%c'", *ctx.opt);
+               usage_with_options(usagestr, options);
+       }
+
+       return parse_options_end(&ctx);
+}
+
+int parse_options(int argc, const char **argv, const struct option *options,
+                 const char * const usagestr[], int flags)
+{
+       return parse_options_subcommand(argc, argv, options, NULL,
+                                       (const char **) usagestr, flags);
+}
+
+#define USAGE_OPTS_WIDTH 24
+#define USAGE_GAP         2
+
+static void print_option_help(const struct option *opts, int full)
+{
+       size_t pos;
+       int pad;
+
+       if (opts->type == OPTION_GROUP) {
+               fputc('\n', stderr);
+               if (*opts->help)
+                       fprintf(stderr, "%s\n", opts->help);
+               return;
+       }
+       if (!full && (opts->flags & PARSE_OPT_HIDDEN))
+               return;
+       if (opts->flags & PARSE_OPT_DISABLED)
+               return;
+
+       pos = fprintf(stderr, "    ");
+       if (opts->short_name)
+               pos += fprintf(stderr, "-%c", opts->short_name);
+       else
+               pos += fprintf(stderr, "    ");
+
+       if (opts->long_name && opts->short_name)
+               pos += fprintf(stderr, ", ");
+       if (opts->long_name)
+               pos += fprintf(stderr, "--%s", opts->long_name);
+
+       switch (opts->type) {
+       case OPTION_ARGUMENT:
+               break;
+       case OPTION_LONG:
+       case OPTION_U64:
+       case OPTION_INTEGER:
+       case OPTION_UINTEGER:
+               if (opts->flags & PARSE_OPT_OPTARG)
+                       if (opts->long_name)
+                               pos += fprintf(stderr, "[=<n>]");
+                       else
+                               pos += fprintf(stderr, "[<n>]");
+               else
+                       pos += fprintf(stderr, " <n>");
+               break;
+       case OPTION_CALLBACK:
+               if (opts->flags & PARSE_OPT_NOARG)
+                       break;
+               /* FALLTHROUGH */
+       case OPTION_STRING:
+               if (opts->argh) {
+                       if (opts->flags & PARSE_OPT_OPTARG)
+                               if (opts->long_name)
+                                       pos += fprintf(stderr, "[=<%s>]", opts->argh);
+                               else
+                                       pos += fprintf(stderr, "[<%s>]", opts->argh);
+                       else
+                               pos += fprintf(stderr, " <%s>", opts->argh);
+               } else {
+                       if (opts->flags & PARSE_OPT_OPTARG)
+                               if (opts->long_name)
+                                       pos += fprintf(stderr, "[=...]");
+                               else
+                                       pos += fprintf(stderr, "[...]");
+                       else
+                               pos += fprintf(stderr, " ...");
+               }
+               break;
+       default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
+       case OPTION_END:
+       case OPTION_GROUP:
+       case OPTION_BIT:
+       case OPTION_BOOLEAN:
+       case OPTION_INCR:
+       case OPTION_SET_UINT:
+       case OPTION_SET_PTR:
+               break;
+       }
+
+       if (pos <= USAGE_OPTS_WIDTH)
+               pad = USAGE_OPTS_WIDTH - pos;
+       else {
+               fputc('\n', stderr);
+               pad = USAGE_OPTS_WIDTH;
+       }
+       fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
+       if (opts->flags & PARSE_OPT_NOBUILD)
+               fprintf(stderr, "%*s(not built-in because %s)\n",
+                       USAGE_OPTS_WIDTH + USAGE_GAP, "",
+                       opts->build_opt);
+}
+
+static int option__cmp(const void *va, const void *vb)
+{
+       const struct option *a = va, *b = vb;
+       int sa = tolower(a->short_name), sb = tolower(b->short_name), ret;
+
+       if (sa == 0)
+               sa = 'z' + 1;
+       if (sb == 0)
+               sb = 'z' + 1;
+
+       ret = sa - sb;
+
+       if (ret == 0) {
+               const char *la = a->long_name ?: "",
+                          *lb = b->long_name ?: "";
+               ret = strcmp(la, lb);
+       }
+
+       return ret;
+}
+
+static struct option *options__order(const struct option *opts)
+{
+       int nr_opts = 0, len;
+       const struct option *o = opts;
+       struct option *ordered;
+
+       for (o = opts; o->type != OPTION_END; o++)
+               ++nr_opts;
+
+       len = sizeof(*o) * (nr_opts + 1);
+       ordered = malloc(len);
+       if (!ordered)
+               goto out;
+       memcpy(ordered, opts, len);
+
+       qsort(ordered, nr_opts, sizeof(*o), option__cmp);
+out:
+       return ordered;
+}
+
+static bool option__in_argv(const struct option *opt, const struct parse_opt_ctx_t *ctx)
+{
+       int i;
+
+       for (i = 1; i < ctx->argc; ++i) {
+               const char *arg = ctx->argv[i];
+
+               if (arg[0] != '-') {
+                       if (arg[1] == '\0') {
+                               if (arg[0] == opt->short_name)
+                                       return true;
+                               continue;
+                       }
+
+                       if (opt->long_name && strcmp(opt->long_name, arg) == 0)
+                               return true;
+
+                       if (opt->help && strcasestr(opt->help, arg) != NULL)
+                               return true;
+
+                       continue;
+               }
+
+               if (arg[1] == opt->short_name ||
+                   (arg[1] == '-' && opt->long_name && strcmp(opt->long_name, arg + 2) == 0))
+                       return true;
+       }
+
+       return false;
+}
+
+static int usage_with_options_internal(const char * const *usagestr,
+                                      const struct option *opts, int full,
+                                      struct parse_opt_ctx_t *ctx)
+{
+       struct option *ordered;
+
+       if (!usagestr)
+               return PARSE_OPT_HELP;
+
+       setup_pager();
+
+       if (error_buf) {
+               fprintf(stderr, "  Error: %s\n", error_buf);
+               zfree(&error_buf);
+       }
+
+       fprintf(stderr, "\n Usage: %s\n", *usagestr++);
+       while (*usagestr && **usagestr)
+               fprintf(stderr, "    or: %s\n", *usagestr++);
+       while (*usagestr) {
+               fprintf(stderr, "%s%s\n",
+                               **usagestr ? "    " : "",
+                               *usagestr);
+               usagestr++;
+       }
+
+       if (opts->type != OPTION_GROUP)
+               fputc('\n', stderr);
+
+       ordered = options__order(opts);
+       if (ordered)
+               opts = ordered;
+
+       for (  ; opts->type != OPTION_END; opts++) {
+               if (ctx && ctx->argc > 1 && !option__in_argv(opts, ctx))
+                       continue;
+               print_option_help(opts, full);
+       }
+
+       fputc('\n', stderr);
+
+       free(ordered);
+
+       return PARSE_OPT_HELP;
+}
+
+void usage_with_options(const char * const *usagestr,
+                       const struct option *opts)
+{
+       usage_with_options_internal(usagestr, opts, 0, NULL);
+       exit(129);
+}
+
+void usage_with_options_msg(const char * const *usagestr,
+                           const struct option *opts, const char *fmt, ...)
+{
+       va_list ap;
+       char *tmp = error_buf;
+
+       va_start(ap, fmt);
+       if (vasprintf(&error_buf, fmt, ap) == -1)
+               die("vasprintf failed");
+       va_end(ap);
+
+       free(tmp);
+
+       usage_with_options_internal(usagestr, opts, 0, NULL);
+       exit(129);
+}
+
+int parse_options_usage(const char * const *usagestr,
+                       const struct option *opts,
+                       const char *optstr, bool short_opt)
+{
+       if (!usagestr)
+               goto opt;
+
+       fprintf(stderr, "\n Usage: %s\n", *usagestr++);
+       while (*usagestr && **usagestr)
+               fprintf(stderr, "    or: %s\n", *usagestr++);
+       while (*usagestr) {
+               fprintf(stderr, "%s%s\n",
+                               **usagestr ? "    " : "",
+                               *usagestr);
+               usagestr++;
+       }
+       fputc('\n', stderr);
+
+opt:
+       for (  ; opts->type != OPTION_END; opts++) {
+               if (short_opt) {
+                       if (opts->short_name == *optstr) {
+                               print_option_help(opts, 0);
+                               break;
+                       }
+                       continue;
+               }
+
+               if (opts->long_name == NULL)
+                       continue;
+
+               if (!prefixcmp(opts->long_name, optstr))
+                       print_option_help(opts, 0);
+               if (!prefixcmp("no-", optstr) &&
+                   !prefixcmp(opts->long_name, optstr + 3))
+                       print_option_help(opts, 0);
+       }
+
+       return PARSE_OPT_HELP;
+}
+
+
+int parse_opt_verbosity_cb(const struct option *opt,
+                          const char *arg __maybe_unused,
+                          int unset)
+{
+       int *target = opt->value;
+
+       if (unset)
+               /* --no-quiet, --no-verbose */
+               *target = 0;
+       else if (opt->short_name == 'v') {
+               if (*target >= 0)
+                       (*target)++;
+               else
+                       *target = 1;
+       } else {
+               if (*target <= 0)
+                       (*target)--;
+               else
+                       *target = -1;
+       }
+       return 0;
+}
+
+static struct option *
+find_option(struct option *opts, int shortopt, const char *longopt)
+{
+       for (; opts->type != OPTION_END; opts++) {
+               if ((shortopt && opts->short_name == shortopt) ||
+                   (opts->long_name && longopt &&
+                    !strcmp(opts->long_name, longopt)))
+                       return opts;
+       }
+       return NULL;
+}
+
+void set_option_flag(struct option *opts, int shortopt, const char *longopt,
+                    int flag)
+{
+       struct option *opt = find_option(opts, shortopt, longopt);
+
+       if (opt)
+               opt->flags |= flag;
+       return;
+}
+
+void set_option_nobuild(struct option *opts, int shortopt,
+                       const char *longopt,
+                       const char *build_opt,
+                       bool can_skip)
+{
+       struct option *opt = find_option(opts, shortopt, longopt);
+
+       if (!opt)
+               return;
+
+       opt->flags |= PARSE_OPT_NOBUILD;
+       opt->flags |= can_skip ? PARSE_OPT_CANSKIP : 0;
+       opt->build_opt = build_opt;
+}
diff --git a/tools/lib/subcmd/parse-options.h b/tools/lib/subcmd/parse-options.h
new file mode 100644 (file)
index 0000000..13a2cc1
--- /dev/null
@@ -0,0 +1,229 @@
+#ifndef __SUBCMD_PARSE_OPTIONS_H
+#define __SUBCMD_PARSE_OPTIONS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+enum parse_opt_type {
+       /* special types */
+       OPTION_END,
+       OPTION_ARGUMENT,
+       OPTION_GROUP,
+       /* options with no arguments */
+       OPTION_BIT,
+       OPTION_BOOLEAN,
+       OPTION_INCR,
+       OPTION_SET_UINT,
+       OPTION_SET_PTR,
+       /* options with arguments (usually) */
+       OPTION_STRING,
+       OPTION_INTEGER,
+       OPTION_LONG,
+       OPTION_CALLBACK,
+       OPTION_U64,
+       OPTION_UINTEGER,
+};
+
+enum parse_opt_flags {
+       PARSE_OPT_KEEP_DASHDASH = 1,
+       PARSE_OPT_STOP_AT_NON_OPTION = 2,
+       PARSE_OPT_KEEP_ARGV0 = 4,
+       PARSE_OPT_KEEP_UNKNOWN = 8,
+       PARSE_OPT_NO_INTERNAL_HELP = 16,
+};
+
+enum parse_opt_option_flags {
+       PARSE_OPT_OPTARG  = 1,
+       PARSE_OPT_NOARG   = 2,
+       PARSE_OPT_NONEG   = 4,
+       PARSE_OPT_HIDDEN  = 8,
+       PARSE_OPT_LASTARG_DEFAULT = 16,
+       PARSE_OPT_DISABLED = 32,
+       PARSE_OPT_EXCLUSIVE = 64,
+       PARSE_OPT_NOEMPTY  = 128,
+       PARSE_OPT_NOBUILD  = 256,
+       PARSE_OPT_CANSKIP  = 512,
+};
+
+struct option;
+typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
+
+/*
+ * `type`::
+ *   holds the type of the option, you must have an OPTION_END last in your
+ *   array.
+ *
+ * `short_name`::
+ *   the character to use as a short option name, '\0' if none.
+ *
+ * `long_name`::
+ *   the long option name, without the leading dashes, NULL if none.
+ *
+ * `value`::
+ *   stores pointers to the values to be filled.
+ *
+ * `argh`::
+ *   token to explain the kind of argument this option wants. Keep it
+ *   homogenous across the repository.
+ *
+ * `help`::
+ *   the short help associated to what the option does.
+ *   Must never be NULL (except for OPTION_END).
+ *   OPTION_GROUP uses this pointer to store the group header.
+ *
+ * `flags`::
+ *   mask of parse_opt_option_flags.
+ *   PARSE_OPT_OPTARG: says that the argument is optionnal (not for BOOLEANs)
+ *   PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs
+ *   PARSE_OPT_NONEG: says that this option cannot be negated
+ *   PARSE_OPT_HIDDEN this option is skipped in the default usage, showed in
+ *                    the long one.
+ *
+ * `callback`::
+ *   pointer to the callback to use for OPTION_CALLBACK.
+ *
+ * `defval`::
+ *   default value to fill (*->value) with for PARSE_OPT_OPTARG.
+ *   OPTION_{BIT,SET_UINT,SET_PTR} store the {mask,integer,pointer} to put in
+ *   the value when met.
+ *   CALLBACKS can use it like they want.
+ *
+ * `set`::
+ *   whether an option was set by the user
+ */
+struct option {
+       enum parse_opt_type type;
+       int short_name;
+       const char *long_name;
+       void *value;
+       const char *argh;
+       const char *help;
+       const char *build_opt;
+
+       int flags;
+       parse_opt_cb *callback;
+       intptr_t defval;
+       bool *set;
+       void *data;
+};
+
+#define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v )
+
+#define OPT_END()                   { .type = OPTION_END }
+#define OPT_ARGUMENT(l, h)          { .type = OPTION_ARGUMENT, .long_name = (l), .help = (h) }
+#define OPT_GROUP(h)                { .type = OPTION_GROUP, .help = (h) }
+#define OPT_BIT(s, l, v, h, b)      { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h), .defval = (b) }
+#define OPT_BOOLEAN(s, l, v, h)     { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h) }
+#define OPT_BOOLEAN_FLAG(s, l, v, h, f)     { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h), .flags = (f) }
+#define OPT_BOOLEAN_SET(s, l, v, os, h) \
+       { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), \
+       .value = check_vtype(v, bool *), .help = (h), \
+       .set = check_vtype(os, bool *)}
+#define OPT_INCR(s, l, v, h)        { .type = OPTION_INCR, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) }
+#define OPT_SET_UINT(s, l, v, h, i)  { .type = OPTION_SET_UINT, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h), .defval = (i) }
+#define OPT_SET_PTR(s, l, v, h, p)  { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) }
+#define OPT_INTEGER(s, l, v, h)     { .type = OPTION_INTEGER, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) }
+#define OPT_UINTEGER(s, l, v, h)    { .type = OPTION_UINTEGER, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h) }
+#define OPT_LONG(s, l, v, h)        { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = check_vtype(v, long *), .help = (h) }
+#define OPT_U64(s, l, v, h)         { .type = OPTION_U64, .short_name = (s), .long_name = (l), .value = check_vtype(v, u64 *), .help = (h) }
+#define OPT_STRING(s, l, v, a, h)   { .type = OPTION_STRING,  .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h) }
+#define OPT_STRING_OPTARG(s, l, v, a, h, d) \
+       { .type = OPTION_STRING,  .short_name = (s), .long_name = (l), \
+         .value = check_vtype(v, const char **), (a), .help = (h), \
+         .flags = PARSE_OPT_OPTARG, .defval = (intptr_t)(d) }
+#define OPT_STRING_NOEMPTY(s, l, v, a, h)   { .type = OPTION_STRING,  .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h), .flags = PARSE_OPT_NOEMPTY}
+#define OPT_DATE(s, l, v, h) \
+       { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }
+#define OPT_CALLBACK(s, l, v, a, h, f) \
+       { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f) }
+#define OPT_CALLBACK_NOOPT(s, l, v, a, h, f) \
+       { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .flags = PARSE_OPT_NOARG }
+#define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \
+       { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT }
+#define OPT_CALLBACK_DEFAULT_NOOPT(s, l, v, a, h, f, d) \
+       { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\
+       .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\
+       .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG}
+#define OPT_CALLBACK_OPTARG(s, l, v, d, a, h, f) \
+       { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), \
+         .value = (v), (a), .help = (h), .callback = (f), \
+         .flags = PARSE_OPT_OPTARG, .data = (d) }
+
+/* parse_options() will filter out the processed options and leave the
+ * non-option argments in argv[].
+ * Returns the number of arguments left in argv[].
+ *
+ * NOTE: parse_options() and parse_options_subcommand() may call exit() in the
+ * case of an error (or for 'special' options like --list-cmds or --list-opts).
+ */
+extern int parse_options(int argc, const char **argv,
+                         const struct option *options,
+                         const char * const usagestr[], int flags);
+
+extern int parse_options_subcommand(int argc, const char **argv,
+                               const struct option *options,
+                               const char *const subcommands[],
+                               const char *usagestr[], int flags);
+
+extern NORETURN void usage_with_options(const char * const *usagestr,
+                                        const struct option *options);
+extern NORETURN __attribute__((format(printf,3,4)))
+void usage_with_options_msg(const char * const *usagestr,
+                           const struct option *options,
+                           const char *fmt, ...);
+
+/*----- incremantal advanced APIs -----*/
+
+enum {
+       PARSE_OPT_HELP = -1,
+       PARSE_OPT_DONE,
+       PARSE_OPT_LIST_OPTS,
+       PARSE_OPT_LIST_SUBCMDS,
+       PARSE_OPT_UNKNOWN,
+};
+
+/*
+ * It's okay for the caller to consume argv/argc in the usual way.
+ * Other fields of that structure are private to parse-options and should not
+ * be modified in any way.
+ */
+struct parse_opt_ctx_t {
+       const char **argv;
+       const char **out;
+       int argc, cpidx;
+       const char *opt;
+       const struct option *excl_opt;
+       int flags;
+};
+
+extern int parse_options_usage(const char * const *usagestr,
+                              const struct option *opts,
+                              const char *optstr,
+                              bool short_opt);
+
+
+/*----- some often used options -----*/
+extern int parse_opt_abbrev_cb(const struct option *, const char *, int);
+extern int parse_opt_approxidate_cb(const struct option *, const char *, int);
+extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
+
+#define OPT__VERBOSE(var)  OPT_BOOLEAN('v', "verbose", (var), "be verbose")
+#define OPT__QUIET(var)    OPT_BOOLEAN('q', "quiet",   (var), "be quiet")
+#define OPT__VERBOSITY(var) \
+       { OPTION_CALLBACK, 'v', "verbose", (var), NULL, "be more verbose", \
+         PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }, \
+       { OPTION_CALLBACK, 'q', "quiet", (var), NULL, "be more quiet", \
+         PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }
+#define OPT__DRY_RUN(var)  OPT_BOOLEAN('n', "dry-run", (var), "dry run")
+#define OPT__ABBREV(var)  \
+       { OPTION_CALLBACK, 0, "abbrev", (var), "n", \
+         "use <n> digits to display SHA-1s", \
+         PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
+
+extern const char *parse_options_fix_filename(const char *prefix, const char *file);
+
+void set_option_flag(struct option *opts, int sopt, const char *lopt, int flag);
+void set_option_nobuild(struct option *opts, int shortopt, const char *longopt,
+                       const char *build_opt, bool can_skip);
+
+#endif /* __SUBCMD_PARSE_OPTIONS_H */
diff --git a/tools/lib/subcmd/run-command.c b/tools/lib/subcmd/run-command.c
new file mode 100644 (file)
index 0000000..f4f6c9e
--- /dev/null
@@ -0,0 +1,227 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include "subcmd-util.h"
+#include "run-command.h"
+#include "exec-cmd.h"
+
+#define STRERR_BUFSIZE 128
+
+static inline void close_pair(int fd[2])
+{
+       close(fd[0]);
+       close(fd[1]);
+}
+
+static inline void dup_devnull(int to)
+{
+       int fd = open("/dev/null", O_RDWR);
+       dup2(fd, to);
+       close(fd);
+}
+
+int start_command(struct child_process *cmd)
+{
+       int need_in, need_out, need_err;
+       int fdin[2], fdout[2], fderr[2];
+       char sbuf[STRERR_BUFSIZE];
+
+       /*
+        * In case of errors we must keep the promise to close FDs
+        * that have been passed in via ->in and ->out.
+        */
+
+       need_in = !cmd->no_stdin && cmd->in < 0;
+       if (need_in) {
+               if (pipe(fdin) < 0) {
+                       if (cmd->out > 0)
+                               close(cmd->out);
+                       return -ERR_RUN_COMMAND_PIPE;
+               }
+               cmd->in = fdin[1];
+       }
+
+       need_out = !cmd->no_stdout
+               && !cmd->stdout_to_stderr
+               && cmd->out < 0;
+       if (need_out) {
+               if (pipe(fdout) < 0) {
+                       if (need_in)
+                               close_pair(fdin);
+                       else if (cmd->in)
+                               close(cmd->in);
+                       return -ERR_RUN_COMMAND_PIPE;
+               }
+               cmd->out = fdout[0];
+       }
+
+       need_err = !cmd->no_stderr && cmd->err < 0;
+       if (need_err) {
+               if (pipe(fderr) < 0) {
+                       if (need_in)
+                               close_pair(fdin);
+                       else if (cmd->in)
+                               close(cmd->in);
+                       if (need_out)
+                               close_pair(fdout);
+                       else if (cmd->out)
+                               close(cmd->out);
+                       return -ERR_RUN_COMMAND_PIPE;
+               }
+               cmd->err = fderr[0];
+       }
+
+       fflush(NULL);
+       cmd->pid = fork();
+       if (!cmd->pid) {
+               if (cmd->no_stdin)
+                       dup_devnull(0);
+               else if (need_in) {
+                       dup2(fdin[0], 0);
+                       close_pair(fdin);
+               } else if (cmd->in) {
+                       dup2(cmd->in, 0);
+                       close(cmd->in);
+               }
+
+               if (cmd->no_stderr)
+                       dup_devnull(2);
+               else if (need_err) {
+                       dup2(fderr[1], 2);
+                       close_pair(fderr);
+               }
+
+               if (cmd->no_stdout)
+                       dup_devnull(1);
+               else if (cmd->stdout_to_stderr)
+                       dup2(2, 1);
+               else if (need_out) {
+                       dup2(fdout[1], 1);
+                       close_pair(fdout);
+               } else if (cmd->out > 1) {
+                       dup2(cmd->out, 1);
+                       close(cmd->out);
+               }
+
+               if (cmd->dir && chdir(cmd->dir))
+                       die("exec %s: cd to %s failed (%s)", cmd->argv[0],
+                           cmd->dir, strerror_r(errno, sbuf, sizeof(sbuf)));
+               if (cmd->env) {
+                       for (; *cmd->env; cmd->env++) {
+                               if (strchr(*cmd->env, '='))
+                                       putenv((char*)*cmd->env);
+                               else
+                                       unsetenv(*cmd->env);
+                       }
+               }
+               if (cmd->preexec_cb)
+                       cmd->preexec_cb();
+               if (cmd->exec_cmd) {
+                       execv_cmd(cmd->argv);
+               } else {
+                       execvp(cmd->argv[0], (char *const*) cmd->argv);
+               }
+               exit(127);
+       }
+
+       if (cmd->pid < 0) {
+               int err = errno;
+               if (need_in)
+                       close_pair(fdin);
+               else if (cmd->in)
+                       close(cmd->in);
+               if (need_out)
+                       close_pair(fdout);
+               else if (cmd->out)
+                       close(cmd->out);
+               if (need_err)
+                       close_pair(fderr);
+               return err == ENOENT ?
+                       -ERR_RUN_COMMAND_EXEC :
+                       -ERR_RUN_COMMAND_FORK;
+       }
+
+       if (need_in)
+               close(fdin[0]);
+       else if (cmd->in)
+               close(cmd->in);
+
+       if (need_out)
+               close(fdout[1]);
+       else if (cmd->out)
+               close(cmd->out);
+
+       if (need_err)
+               close(fderr[1]);
+
+       return 0;
+}
+
+static int wait_or_whine(pid_t pid)
+{
+       char sbuf[STRERR_BUFSIZE];
+
+       for (;;) {
+               int status, code;
+               pid_t waiting = waitpid(pid, &status, 0);
+
+               if (waiting < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       fprintf(stderr, " Error: waitpid failed (%s)",
+                               strerror_r(errno, sbuf, sizeof(sbuf)));
+                       return -ERR_RUN_COMMAND_WAITPID;
+               }
+               if (waiting != pid)
+                       return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
+               if (WIFSIGNALED(status))
+                       return -ERR_RUN_COMMAND_WAITPID_SIGNAL;
+
+               if (!WIFEXITED(status))
+                       return -ERR_RUN_COMMAND_WAITPID_NOEXIT;
+               code = WEXITSTATUS(status);
+               switch (code) {
+               case 127:
+                       return -ERR_RUN_COMMAND_EXEC;
+               case 0:
+                       return 0;
+               default:
+                       return -code;
+               }
+       }
+}
+
+int finish_command(struct child_process *cmd)
+{
+       return wait_or_whine(cmd->pid);
+}
+
+int run_command(struct child_process *cmd)
+{
+       int code = start_command(cmd);
+       if (code)
+               return code;
+       return finish_command(cmd);
+}
+
+static void prepare_run_command_v_opt(struct child_process *cmd,
+                                     const char **argv,
+                                     int opt)
+{
+       memset(cmd, 0, sizeof(*cmd));
+       cmd->argv = argv;
+       cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
+       cmd->exec_cmd = opt & RUN_EXEC_CMD ? 1 : 0;
+       cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
+}
+
+int run_command_v_opt(const char **argv, int opt)
+{
+       struct child_process cmd;
+       prepare_run_command_v_opt(&cmd, argv, opt);
+       return run_command(&cmd);
+}
diff --git a/tools/lib/subcmd/run-command.h b/tools/lib/subcmd/run-command.h
new file mode 100644 (file)
index 0000000..fe2befe
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef __SUBCMD_RUN_COMMAND_H
+#define __SUBCMD_RUN_COMMAND_H
+
+#include <unistd.h>
+
+enum {
+       ERR_RUN_COMMAND_FORK = 10000,
+       ERR_RUN_COMMAND_EXEC,
+       ERR_RUN_COMMAND_PIPE,
+       ERR_RUN_COMMAND_WAITPID,
+       ERR_RUN_COMMAND_WAITPID_WRONG_PID,
+       ERR_RUN_COMMAND_WAITPID_SIGNAL,
+       ERR_RUN_COMMAND_WAITPID_NOEXIT,
+};
+#define IS_RUN_COMMAND_ERR(x) (-(x) >= ERR_RUN_COMMAND_FORK)
+
+struct child_process {
+       const char **argv;
+       pid_t pid;
+       /*
+        * Using .in, .out, .err:
+        * - Specify 0 for no redirections (child inherits stdin, stdout,
+        *   stderr from parent).
+        * - Specify -1 to have a pipe allocated as follows:
+        *     .in: returns the writable pipe end; parent writes to it,
+        *          the readable pipe end becomes child's stdin
+        *     .out, .err: returns the readable pipe end; parent reads from
+        *          it, the writable pipe end becomes child's stdout/stderr
+        *   The caller of start_command() must close the returned FDs
+        *   after it has completed reading from/writing to it!
+        * - Specify > 0 to set a channel to a particular FD as follows:
+        *     .in: a readable FD, becomes child's stdin
+        *     .out: a writable FD, becomes child's stdout/stderr
+        *     .err > 0 not supported
+        *   The specified FD is closed by start_command(), even in case
+        *   of errors!
+        */
+       int in;
+       int out;
+       int err;
+       const char *dir;
+       const char *const *env;
+       unsigned no_stdin:1;
+       unsigned no_stdout:1;
+       unsigned no_stderr:1;
+       unsigned exec_cmd:1; /* if this is to be external sub-command */
+       unsigned stdout_to_stderr:1;
+       void (*preexec_cb)(void);
+};
+
+int start_command(struct child_process *);
+int finish_command(struct child_process *);
+int run_command(struct child_process *);
+
+#define RUN_COMMAND_NO_STDIN 1
+#define RUN_EXEC_CMD        2  /*If this is to be external sub-command */
+#define RUN_COMMAND_STDOUT_TO_STDERR 4
+int run_command_v_opt(const char **argv, int opt);
+
+#endif /* __SUBCMD_RUN_COMMAND_H */
diff --git a/tools/lib/subcmd/sigchain.c b/tools/lib/subcmd/sigchain.c
new file mode 100644 (file)
index 0000000..3537c34
--- /dev/null
@@ -0,0 +1,53 @@
+#include <signal.h>
+#include "subcmd-util.h"
+#include "sigchain.h"
+
+#define SIGCHAIN_MAX_SIGNALS 32
+
+struct sigchain_signal {
+       sigchain_fun *old;
+       int n;
+       int alloc;
+};
+static struct sigchain_signal signals[SIGCHAIN_MAX_SIGNALS];
+
+static void check_signum(int sig)
+{
+       if (sig < 1 || sig >= SIGCHAIN_MAX_SIGNALS)
+               die("BUG: signal out of range: %d", sig);
+}
+
+static int sigchain_push(int sig, sigchain_fun f)
+{
+       struct sigchain_signal *s = signals + sig;
+       check_signum(sig);
+
+       ALLOC_GROW(s->old, s->n + 1, s->alloc);
+       s->old[s->n] = signal(sig, f);
+       if (s->old[s->n] == SIG_ERR)
+               return -1;
+       s->n++;
+       return 0;
+}
+
+int sigchain_pop(int sig)
+{
+       struct sigchain_signal *s = signals + sig;
+       check_signum(sig);
+       if (s->n < 1)
+               return 0;
+
+       if (signal(sig, s->old[s->n - 1]) == SIG_ERR)
+               return -1;
+       s->n--;
+       return 0;
+}
+
+void sigchain_push_common(sigchain_fun f)
+{
+       sigchain_push(SIGINT, f);
+       sigchain_push(SIGHUP, f);
+       sigchain_push(SIGTERM, f);
+       sigchain_push(SIGQUIT, f);
+       sigchain_push(SIGPIPE, f);
+}
diff --git a/tools/lib/subcmd/sigchain.h b/tools/lib/subcmd/sigchain.h
new file mode 100644 (file)
index 0000000..0c919f2
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __SUBCMD_SIGCHAIN_H
+#define __SUBCMD_SIGCHAIN_H
+
+typedef void (*sigchain_fun)(int);
+
+int sigchain_pop(int sig);
+
+void sigchain_push_common(sigchain_fun f);
+
+#endif /* __SUBCMD_SIGCHAIN_H */
diff --git a/tools/lib/subcmd/subcmd-config.c b/tools/lib/subcmd/subcmd-config.c
new file mode 100644 (file)
index 0000000..d017c72
--- /dev/null
@@ -0,0 +1,11 @@
+#include "subcmd-config.h"
+
+#define UNDEFINED "SUBCMD_HAS_NOT_BEEN_INITIALIZED"
+
+struct subcmd_config subcmd_config = {
+       .exec_name      = UNDEFINED,
+       .prefix         = UNDEFINED,
+       .exec_path      = UNDEFINED,
+       .exec_path_env  = UNDEFINED,
+       .pager_env      = UNDEFINED,
+};
diff --git a/tools/lib/subcmd/subcmd-config.h b/tools/lib/subcmd/subcmd-config.h
new file mode 100644 (file)
index 0000000..cc85140
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __PERF_SUBCMD_CONFIG_H
+#define __PERF_SUBCMD_CONFIG_H
+
+struct subcmd_config {
+       const char *exec_name;
+       const char *prefix;
+       const char *exec_path;
+       const char *exec_path_env;
+       const char *pager_env;
+};
+
+extern struct subcmd_config subcmd_config;
+
+#endif /* __PERF_SUBCMD_CONFIG_H */
diff --git a/tools/lib/subcmd/subcmd-util.h b/tools/lib/subcmd/subcmd-util.h
new file mode 100644 (file)
index 0000000..fc2e45d
--- /dev/null
@@ -0,0 +1,91 @@
+#ifndef __SUBCMD_UTIL_H
+#define __SUBCMD_UTIL_H
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define NORETURN __attribute__((__noreturn__))
+
+static inline void report(const char *prefix, const char *err, va_list params)
+{
+       char msg[1024];
+       vsnprintf(msg, sizeof(msg), err, params);
+       fprintf(stderr, " %s%s\n", prefix, msg);
+}
+
+static NORETURN inline void die(const char *err, ...)
+{
+       va_list params;
+
+       va_start(params, err);
+       report(" Fatal: ", err, params);
+       exit(128);
+       va_end(params);
+}
+
+#define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
+
+#define alloc_nr(x) (((x)+16)*3/2)
+
+/*
+ * Realloc the buffer pointed at by variable 'x' so that it can hold
+ * at least 'nr' entries; the number of entries currently allocated
+ * is 'alloc', using the standard growing factor alloc_nr() macro.
+ *
+ * DO NOT USE any expression with side-effect for 'x' or 'alloc'.
+ */
+#define ALLOC_GROW(x, nr, alloc) \
+       do { \
+               if ((nr) > alloc) { \
+                       if (alloc_nr(alloc) < (nr)) \
+                               alloc = (nr); \
+                       else \
+                               alloc = alloc_nr(alloc); \
+                       x = xrealloc((x), alloc * sizeof(*(x))); \
+               } \
+       } while(0)
+
+static inline void *xrealloc(void *ptr, size_t size)
+{
+       void *ret = realloc(ptr, size);
+       if (!ret && !size)
+               ret = realloc(ptr, 1);
+       if (!ret) {
+               ret = realloc(ptr, size);
+               if (!ret && !size)
+                       ret = realloc(ptr, 1);
+               if (!ret)
+                       die("Out of memory, realloc failed");
+       }
+       return ret;
+}
+
+#define astrcatf(out, fmt, ...)                                                \
+({                                                                     \
+       char *tmp = *(out);                                             \
+       if (asprintf((out), "%s" fmt, tmp ?: "", ## __VA_ARGS__) == -1) \
+               die("asprintf failed");                                 \
+       free(tmp);                                                      \
+})
+
+static inline void astrcat(char **out, const char *add)
+{
+       char *tmp = *out;
+
+       if (asprintf(out, "%s%s", tmp ?: "", add) == -1)
+               die("asprintf failed");
+
+       free(tmp);
+}
+
+static inline int prefixcmp(const char *str, const char *prefix)
+{
+       for (; ; str++, prefix++)
+               if (!*prefix)
+                       return 0;
+               else if (*str != *prefix)
+                       return (unsigned char)*prefix - (unsigned char)*str;
+}
+
+#endif /* __SUBCMD_UTIL_H */
index 2a912df6771bf5c6abd880667fbece1dcf1e1005..ea69ce35e902a828b40839cfd7beb14bb9ff29c8 100644 (file)
@@ -4735,73 +4735,80 @@ static int is_printable_array(char *p, unsigned int len)
        return 1;
 }
 
-static void print_event_fields(struct trace_seq *s, void *data,
-                              int size __maybe_unused,
-                              struct event_format *event)
+void pevent_print_field(struct trace_seq *s, void *data,
+                       struct format_field *field)
 {
-       struct format_field *field;
        unsigned long long val;
        unsigned int offset, len, i;
-
-       field = event->format.fields;
-       while (field) {
-               trace_seq_printf(s, " %s=", field->name);
-               if (field->flags & FIELD_IS_ARRAY) {
-                       offset = field->offset;
-                       len = field->size;
-                       if (field->flags & FIELD_IS_DYNAMIC) {
-                               val = pevent_read_number(event->pevent, data + offset, len);
-                               offset = val;
-                               len = offset >> 16;
-                               offset &= 0xffff;
-                       }
-                       if (field->flags & FIELD_IS_STRING &&
-                           is_printable_array(data + offset, len)) {
-                               trace_seq_printf(s, "%s", (char *)data + offset);
-                       } else {
-                               trace_seq_puts(s, "ARRAY[");
-                               for (i = 0; i < len; i++) {
-                                       if (i)
-                                               trace_seq_puts(s, ", ");
-                                       trace_seq_printf(s, "%02x",
-                                                        *((unsigned char *)data + offset + i));
-                               }
-                               trace_seq_putc(s, ']');
-                               field->flags &= ~FIELD_IS_STRING;
-                       }
+       struct pevent *pevent = field->event->pevent;
+
+       if (field->flags & FIELD_IS_ARRAY) {
+               offset = field->offset;
+               len = field->size;
+               if (field->flags & FIELD_IS_DYNAMIC) {
+                       val = pevent_read_number(pevent, data + offset, len);
+                       offset = val;
+                       len = offset >> 16;
+                       offset &= 0xffff;
+               }
+               if (field->flags & FIELD_IS_STRING &&
+                   is_printable_array(data + offset, len)) {
+                       trace_seq_printf(s, "%s", (char *)data + offset);
                } else {
-                       val = pevent_read_number(event->pevent, data + field->offset,
-                                                field->size);
-                       if (field->flags & FIELD_IS_POINTER) {
-                               trace_seq_printf(s, "0x%llx", val);
-                       } else if (field->flags & FIELD_IS_SIGNED) {
-                               switch (field->size) {
-                               case 4:
-                                       /*
-                                        * If field is long then print it in hex.
-                                        * A long usually stores pointers.
-                                        */
-                                       if (field->flags & FIELD_IS_LONG)
-                                               trace_seq_printf(s, "0x%x", (int)val);
-                                       else
-                                               trace_seq_printf(s, "%d", (int)val);
-                                       break;
-                               case 2:
-                                       trace_seq_printf(s, "%2d", (short)val);
-                                       break;
-                               case 1:
-                                       trace_seq_printf(s, "%1d", (char)val);
-                                       break;
-                               default:
-                                       trace_seq_printf(s, "%lld", val);
-                               }
-                       } else {
+                       trace_seq_puts(s, "ARRAY[");
+                       for (i = 0; i < len; i++) {
+                               if (i)
+                                       trace_seq_puts(s, ", ");
+                               trace_seq_printf(s, "%02x",
+                                                *((unsigned char *)data + offset + i));
+                       }
+                       trace_seq_putc(s, ']');
+                       field->flags &= ~FIELD_IS_STRING;
+               }
+       } else {
+               val = pevent_read_number(pevent, data + field->offset,
+                                        field->size);
+               if (field->flags & FIELD_IS_POINTER) {
+                       trace_seq_printf(s, "0x%llx", val);
+               } else if (field->flags & FIELD_IS_SIGNED) {
+                       switch (field->size) {
+                       case 4:
+                               /*
+                                * If field is long then print it in hex.
+                                * A long usually stores pointers.
+                                */
                                if (field->flags & FIELD_IS_LONG)
-                                       trace_seq_printf(s, "0x%llx", val);
+                                       trace_seq_printf(s, "0x%x", (int)val);
                                else
-                                       trace_seq_printf(s, "%llu", val);
+                                       trace_seq_printf(s, "%d", (int)val);
+                               break;
+                       case 2:
+                               trace_seq_printf(s, "%2d", (short)val);
+                               break;
+                       case 1:
+                               trace_seq_printf(s, "%1d", (char)val);
+                               break;
+                       default:
+                               trace_seq_printf(s, "%lld", val);
                        }
+               } else {
+                       if (field->flags & FIELD_IS_LONG)
+                               trace_seq_printf(s, "0x%llx", val);
+                       else
+                               trace_seq_printf(s, "%llu", val);
                }
+       }
+}
+
+void pevent_print_fields(struct trace_seq *s, void *data,
+                        int size __maybe_unused, struct event_format *event)
+{
+       struct format_field *field;
+
+       field = event->format.fields;
+       while (field) {
+               trace_seq_printf(s, " %s=", field->name);
+               pevent_print_field(s, data, field);
                field = field->next;
        }
 }
@@ -4827,7 +4834,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
 
        if (event->flags & EVENT_FL_FAILED) {
                trace_seq_printf(s, "[FAILED TO PARSE]");
-               print_event_fields(s, data, size, event);
+               pevent_print_fields(s, data, size, event);
                return;
        }
 
@@ -4968,13 +4975,12 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
                                    sizeof(long) != 8) {
                                        char *p;
 
-                                       ls = 2;
                                        /* make %l into %ll */
-                                       p = strchr(format, 'l');
-                                       if (p)
+                                       if (ls == 1 && (p = strchr(format, 'l')))
                                                memmove(p+1, p, strlen(p)+1);
                                        else if (strcmp(format, "%p") == 0)
                                                strcpy(format, "0x%llx");
+                                       ls = 2;
                                }
                                switch (ls) {
                                case -2:
@@ -5302,7 +5308,7 @@ void pevent_event_info(struct trace_seq *s, struct event_format *event,
        int print_pretty = 1;
 
        if (event->pevent->print_raw || (event->flags & EVENT_FL_PRINTRAW))
-               print_event_fields(s, record->data, record->size, event);
+               pevent_print_fields(s, record->data, record->size, event);
        else {
 
                if (event->handler && !(event->flags & EVENT_FL_NOHANDLE))
index 6fc83c7edbe918b01be04667699ae56a87d8676e..706d9bc24066cf308ba17d718eafd95c4ff5550c 100644 (file)
@@ -705,6 +705,10 @@ struct cmdline *pevent_data_pid_from_comm(struct pevent *pevent, const char *com
                                          struct cmdline *next);
 int pevent_cmdline_pid(struct pevent *pevent, struct cmdline *cmdline);
 
+void pevent_print_field(struct trace_seq *s, void *data,
+                       struct format_field *field);
+void pevent_print_fields(struct trace_seq *s, void *data,
+                        int size __maybe_unused, struct event_format *event);
 void pevent_event_info(struct trace_seq *s, struct event_format *event,
                       struct pevent_record *record);
 int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum,
diff --git a/tools/lib/util/find_next_bit.c b/tools/lib/util/find_next_bit.c
deleted file mode 100644 (file)
index 41b44f6..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/* find_next_bit.c: fallback find next bit implementation
- *
- * Copied from lib/find_next_bit.c to tools/lib/next_bit.c
- *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/bitops.h>
-#include <asm/types.h>
-#include <asm/byteorder.h>
-
-#define BITOP_WORD(nr)         ((nr) / BITS_PER_LONG)
-
-#ifndef find_next_bit
-/*
- * Find the next set bit in a memory region.
- */
-unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
-                           unsigned long offset)
-{
-       const unsigned long *p = addr + BITOP_WORD(offset);
-       unsigned long result = offset & ~(BITS_PER_LONG-1);
-       unsigned long tmp;
-
-       if (offset >= size)
-               return size;
-       size -= result;
-       offset %= BITS_PER_LONG;
-       if (offset) {
-               tmp = *(p++);
-               tmp &= (~0UL << offset);
-               if (size < BITS_PER_LONG)
-                       goto found_first;
-               if (tmp)
-                       goto found_middle;
-               size -= BITS_PER_LONG;
-               result += BITS_PER_LONG;
-       }
-       while (size & ~(BITS_PER_LONG-1)) {
-               if ((tmp = *(p++)))
-                       goto found_middle;
-               result += BITS_PER_LONG;
-               size -= BITS_PER_LONG;
-       }
-       if (!size)
-               return result;
-       tmp = *p;
-
-found_first:
-       tmp &= (~0UL >> (BITS_PER_LONG - size));
-       if (tmp == 0UL)         /* Are any bits set? */
-               return result + size;   /* Nope. */
-found_middle:
-       return result + __ffs(tmp);
-}
-#endif
-
-#ifndef find_first_bit
-/*
- * Find the first set bit in a memory region.
- */
-unsigned long find_first_bit(const unsigned long *addr, unsigned long size)
-{
-       const unsigned long *p = addr;
-       unsigned long result = 0;
-       unsigned long tmp;
-
-       while (size & ~(BITS_PER_LONG-1)) {
-               if ((tmp = *(p++)))
-                       goto found;
-               result += BITS_PER_LONG;
-               size -= BITS_PER_LONG;
-       }
-       if (!size)
-               return result;
-
-       tmp = (*p) & (~0UL >> (BITS_PER_LONG - size));
-       if (tmp == 0UL)         /* Are any bits set? */
-               return result + size;   /* Nope. */
-found:
-       return result + __ffs(tmp);
-}
-#endif
index 72237455b4003aeb72fccf3afdf40f2f5588f1d2..6b67e6f4179f53bca6e134da0f844f1f709c9586 100644 (file)
@@ -1,5 +1,6 @@
 perf-y += builtin-bench.o
 perf-y += builtin-annotate.o
+perf-y += builtin-config.o
 perf-y += builtin-diff.o
 perf-y += builtin-evlist.o
 perf-y += builtin-help.o
@@ -19,6 +20,7 @@ perf-y += builtin-kvm.o
 perf-y += builtin-inject.o
 perf-y += builtin-mem.o
 perf-y += builtin-data.o
+perf-y += builtin-version.o
 
 perf-$(CONFIG_AUDIT) += builtin-trace.o
 perf-$(CONFIG_LIBELF) += builtin-probe.o
@@ -34,8 +36,12 @@ paths += -DPERF_MAN_PATH="BUILD_STR($(mandir_SQ))"
 
 CFLAGS_builtin-help.o      += $(paths)
 CFLAGS_builtin-timechart.o += $(paths)
-CFLAGS_perf.o              += -DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))" -include $(OUTPUT)PERF-VERSION-FILE
+CFLAGS_perf.o              += -DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))"      \
+                             -DPERF_EXEC_PATH="BUILD_STR($(perfexecdir_SQ))"   \
+                             -DPREFIX="BUILD_STR($(prefix_SQ))"                \
+                             -include $(OUTPUT)PERF-VERSION-FILE
 CFLAGS_builtin-trace.o    += -DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_SQ))"
+CFLAGS_builtin-report.o           += -DTIPDIR="BUILD_STR($(tipdir_SQ))"
 
 libperf-y += util/
 libperf-y += arch/
diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
new file mode 100644 (file)
index 0000000..b9ca1e3
--- /dev/null
@@ -0,0 +1,103 @@
+perf-config(1)
+==============
+
+NAME
+----
+perf-config - Get and set variables in a configuration file.
+
+SYNOPSIS
+--------
+[verse]
+'perf config' -l | --list
+
+DESCRIPTION
+-----------
+You can manage variables in a configuration file with this command.
+
+OPTIONS
+-------
+
+-l::
+--list::
+       Show current config variables, name and value, for all sections.
+
+CONFIGURATION FILE
+------------------
+
+The perf configuration file contains many variables to change various
+aspects of each of its tools, including output, disk usage, etc.
+The '$HOME/.perfconfig' file is used to store a per-user configuration.
+The file '$(sysconfdir)/perfconfig' can be used to
+store a system-wide default configuration.
+
+Syntax
+~~~~~~
+
+The file consist of sections. A section starts with its name
+surrounded by square brackets and continues till the next section
+begins. Each variable must be in a section, and have the form
+'name = value', for example:
+
+       [section]
+               name1 = value1
+               name2 = value2
+
+Section names are case sensitive and can contain any characters except
+newline (double quote `"` and backslash have to be escaped as `\"` and `\\`,
+respectively). Section headers can't span multiple lines.
+
+Example
+~~~~~~~
+
+Given a $HOME/.perfconfig like this:
+
+#
+# This is the config file, and
+# a '#' and ';' character indicates a comment
+#
+
+       [colors]
+               # Color variables
+               top = red, default
+               medium = green, default
+               normal = lightgray, default
+               selected = white, lightgray
+               code = blue, default
+               addr = magenta, default
+               root = white, blue
+
+       [tui]
+               # Defaults if linked with libslang
+               report = on
+               annotate = on
+               top = on
+
+       [buildid]
+               # Default, disable using /dev/null
+               dir = ~/.debug
+
+       [annotate]
+               # Defaults
+               hide_src_code = false
+               use_offset = true
+               jump_arrows = true
+               show_nr_jumps = false
+
+       [help]
+               # Format can be man, info, web or html
+               format = man
+               autocorrect = 0
+
+       [ui]
+               show-headers = true
+
+       [call-graph]
+               # fp (framepointer), dwarf
+               record-mode = fp
+               print-type = graph
+               order = caller
+               sort-key = function
+
+SEE ALSO
+--------
+linkperf:perf[1]
index 1ceb3700ffbb4f6807d5a77fa4071fedb0aa60f6..6f7200fb85cf2e509d8d17bc5c3ff7ed6d7a7331 100644 (file)
@@ -32,6 +32,9 @@ OPTIONS
 --group::
        Show event group information.
 
+--trace-fields::
+       Show tracepoint field names.
+
 SEE ALSO
 --------
 linkperf:perf-record[1], linkperf:perf-list[1],
index e630a7d2c3483cc6b11f33190d289b19c2d43b85..3a1a32f5479f99d2d1744ec9135daae63fa34979 100644 (file)
@@ -207,11 +207,23 @@ comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-
 In per-thread mode with inheritance mode on (default), samples are captured only when
 the thread executes on the designated CPUs. Default is to monitor all CPUs.
 
+-B::
+--no-buildid::
+Do not save the build ids of binaries in the perf.data files. This skips
+post processing after recording, which sometimes makes the final step in
+the recording process to take a long time, as it needs to process all
+events looking for mmap records. The downside is that it can misresolve
+symbols if the workload binaries used when recording get locally rebuilt
+or upgraded, because the only key available in this case is the
+pathname. You can also set the "record.build-id" config variable to
+'skip to have this behaviour permanently.
+
 -N::
 --no-buildid-cache::
 Do not update the buildid cache. This saves some overhead in situations
 where the information in the perf.data file (which includes buildids)
-is sufficient.
+is sufficient.  You can also set the "record.build-id" config variable to
+'no-cache' to have the same effect.
 
 -G name,...::
 --cgroup name,...::
@@ -314,11 +326,17 @@ This option sets the time out limit. The default value is 500 ms.
 Record context switch events i.e. events of type PERF_RECORD_SWITCH or
 PERF_RECORD_SWITCH_CPU_WIDE.
 
---clang-path::
+--clang-path=PATH::
 Path to clang binary to use for compiling BPF scriptlets.
+(enabled when BPF support is on)
 
---clang-opt::
+--clang-opt=OPTIONS::
 Options passed to clang when compiling BPF scriptlets.
+(enabled when BPF support is on)
+
+--vmlinux=PATH::
+Specify vmlinux path which has debuginfo.
+(enabled when BPF prologue is on)
 
 SEE ALSO
 --------
index 5ce8da1e1256f2295c0b3273c48516463db8ce23..8a301f6afb37ad855351fcd5fba1644d12dc2529 100644 (file)
@@ -117,6 +117,30 @@ OPTIONS
        And default sort keys are changed to comm, dso_from, symbol_from, dso_to
        and symbol_to, see '--branch-stack'.
 
+       If the data file has tracepoint event(s), following (dynamic) sort keys
+       are also available:
+       trace, trace_fields, [<event>.]<field>[/raw]
+
+       - trace: pretty printed trace output in a single column
+       - trace_fields: fields in tracepoints in separate columns
+       - <field name>: optional event and field name for a specific field
+
+       The last form consists of event and field names.  If event name is
+       omitted, it searches all events for matching field name.  The matched
+       field will be shown only for the event has the field.  The event name
+       supports substring match so user doesn't need to specify full subsystem
+       and event name everytime.  For example, 'sched:sched_switch' event can
+       be shortened to 'switch' as long as it's not ambiguous.  Also event can
+       be specified by its index (starting from 1) preceded by the '%'.
+       So '%1' is the first event, '%2' is the second, and so on.
+
+       The field name can have '/raw' suffix which disables pretty printing
+       and shows raw field value like hex numbers.  The --raw-trace option
+       has the same effect for all dynamic sort keys.
+
+       The default sort keys are changed to 'trace' if all events in the data
+       file are tracepoint.
+
 -F::
 --fields=::
        Specify output field - multiple keys can be specified in CSV format.
@@ -170,17 +194,18 @@ OPTIONS
         Dump raw trace in ASCII.
 
 -g::
---call-graph=<print_type,threshold[,print_limit],order,sort_key,branch>::
+--call-graph=<print_type,threshold[,print_limit],order,sort_key[,branch],value>::
         Display call chains using type, min percent threshold, print limit,
-       call order, sort key and branch.  Note that ordering of parameters is not
-       fixed so any parement can be given in an arbitraty order.  One exception
-       is the print_limit which should be preceded by threshold.
+       call order, sort key, optional branch and value.  Note that ordering of
+       parameters is not fixed so any parement can be given in an arbitraty order.
+       One exception is the print_limit which should be preceded by threshold.
 
        print_type can be either:
        - flat: single column, linear exposure of call chains.
        - graph: use a graph tree, displaying absolute overhead rates. (default)
        - fractal: like graph, but displays relative rates. Each branch of
                 the tree is considered as a new profiled object.
+       - folded: call chains are displayed in a line, separated by semicolons
        - none: disable call chain display.
 
        threshold is a percentage value which specifies a minimum percent to be
@@ -204,6 +229,11 @@ OPTIONS
        - branch: include last branch information in callgraph when available.
                  Usually more convenient to use --branch-history for this.
 
+       value can be:
+       - percent: diplay overhead percent (default)
+       - period: display event period
+       - count: display event count
+
 --children::
        Accumulate callchain of children to parent entry so that then can
        show up in the output.  The output will have a new "Children" column
@@ -365,6 +395,9 @@ include::itrace.txt[]
 --socket-filter::
        Only report the samples on the processor socket that match with this filter
 
+--raw-trace::
+       When displaying traceevent output, do not use print fmt or plugins.
+
 include::callchain-overhead-calculation.txt[]
 
 SEE ALSO
index 4e074a6608269793d52a2ea4f28061532bb9798b..52ef7a9d50aacbc3d3fbb0366852457d39718cdf 100644 (file)
@@ -10,6 +10,8 @@ SYNOPSIS
 [verse]
 'perf stat' [-e <EVENT> | --event=EVENT] [-a] <command>
 'perf stat' [-e <EVENT> | --event=EVENT] [-a] -- <command> [<options>]
+'perf stat' [-e <EVENT> | --event=EVENT] [-a] record [-o file] -- <command> [<options>]
+'perf stat' report [-i file]
 
 DESCRIPTION
 -----------
@@ -22,6 +24,11 @@ OPTIONS
 <command>...::
        Any command you can specify in a shell.
 
+record::
+       See STAT RECORD.
+
+report::
+       See STAT REPORT.
 
 -e::
 --event=::
@@ -159,6 +166,33 @@ filter out the startup phase of the program, which is often very different.
 
 Print statistics of transactional execution if supported.
 
+STAT RECORD
+-----------
+Stores stat data into perf data file.
+
+-o file::
+--output file::
+Output file name.
+
+STAT REPORT
+-----------
+Reads and reports stat data from perf data file.
+
+-i file::
+--input file::
+Input file name.
+
+--per-socket::
+Aggregate counts per processor socket for system-wide mode measurements.
+
+--per-core::
+Aggregate counts per physical processor for system-wide mode measurements.
+
+-A::
+--no-aggr::
+Do not aggregate counts across all monitored CPUs.
+
+
 EXAMPLES
 --------
 
index 556cec09bf50cc4d5d9a50104d8efabd7879e2c7..b0e60e17db389d89efafa7025cd47fd44fe625c3 100644 (file)
@@ -230,6 +230,9 @@ Default is to monitor all CPUS.
        The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k
        Note that this feature may not be available on all processors.
 
+--raw-trace::
+       When displaying traceevent output, do not use print fmt or plugins.
+
 INTERACTIVE PROMPTING KEYS
 --------------------------
 
diff --git a/tools/perf/Documentation/tips.txt b/tools/perf/Documentation/tips.txt
new file mode 100644 (file)
index 0000000..a1c10e3
--- /dev/null
@@ -0,0 +1,14 @@
+For a higher level overview, try: perf report --sort comm,dso
+Sample related events with: perf record -e '{cycles,instructions}:S'
+Compare performance results with: perf diff [<old file> <new file>]
+Boolean options have negative forms, e.g.: perf report --no-children
+Customize output of perf script with: perf script -F event,ip,sym
+Generate a script for your data: perf script -g <lang>
+Save output of perf stat using: perf stat record <target workload>
+Create an archive with symtabs to analyse on other machine: perf archive
+Search options using a keyword: perf report -h <keyword>
+Use parent filter to see specific call path: perf report -p <regex>
+List events using substring match: perf list <keyword>
+To see list of saved events and attributes: perf evlist -v
+Use --symfs <dir> if your symbol files are in non-standard locations
+To see callchains in a more compact form: perf report -g folded
index 39c38cb45b00f8e3e478bfebab6a47a9bf4c3dd7..ddf922f93aa154d04e250bb01a62be85df9100e3 100644 (file)
@@ -1,6 +1,7 @@
 tools/perf
 tools/arch/alpha/include/asm/barrier.h
 tools/arch/arm/include/asm/barrier.h
+tools/arch/arm64/include/asm/barrier.h
 tools/arch/ia64/include/asm/barrier.h
 tools/arch/mips/include/asm/barrier.h
 tools/arch/powerpc/include/asm/barrier.h
@@ -20,14 +21,17 @@ tools/lib/traceevent
 tools/lib/bpf
 tools/lib/api
 tools/lib/bpf
+tools/lib/subcmd
 tools/lib/hweight.c
 tools/lib/rbtree.c
+tools/lib/string.c
 tools/lib/symbol/kallsyms.c
 tools/lib/symbol/kallsyms.h
-tools/lib/util/find_next_bit.c
+tools/lib/find_bit.c
 tools/include/asm/atomic.h
 tools/include/asm/barrier.h
 tools/include/asm/bug.h
+tools/include/asm-generic/atomic-gcc.h
 tools/include/asm-generic/barrier.h
 tools/include/asm-generic/bitops/arch_hweight.h
 tools/include/asm-generic/bitops/atomic.h
@@ -50,6 +54,7 @@ tools/include/linux/log2.h
 tools/include/linux/poison.h
 tools/include/linux/rbtree.h
 tools/include/linux/rbtree_augmented.h
+tools/include/linux/string.h
 tools/include/linux/types.h
 tools/include/linux/err.h
 include/asm-generic/bitops/arch_hweight.h
index 0d19d5447d6c721bba185422ee32b45ce6fff3e9..0a22407e1d7d8abb092ff3d24b6829a27c234bbe 100644 (file)
@@ -145,9 +145,10 @@ BISON   = bison
 STRIP   = strip
 AWK     = awk
 
-LIB_DIR          = $(srctree)/tools/lib/api/
+LIB_DIR                = $(srctree)/tools/lib/api/
 TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
-BPF_DIR = $(srctree)/tools/lib/bpf/
+BPF_DIR                = $(srctree)/tools/lib/bpf/
+SUBCMD_DIR     = $(srctree)/tools/lib/subcmd/
 
 # include config/Makefile by default and rule out
 # non-config cases
@@ -184,15 +185,17 @@ strip-libs = $(filter-out -l%,$(1))
 ifneq ($(OUTPUT),)
   TE_PATH=$(OUTPUT)
   BPF_PATH=$(OUTPUT)
+  SUBCMD_PATH=$(OUTPUT)
 ifneq ($(subdir),)
-  LIB_PATH=$(OUTPUT)/../lib/api/
+  API_PATH=$(OUTPUT)/../lib/api/
 else
-  LIB_PATH=$(OUTPUT)
+  API_PATH=$(OUTPUT)
 endif
 else
   TE_PATH=$(TRACE_EVENT_DIR)
-  LIB_PATH=$(LIB_DIR)
+  API_PATH=$(LIB_DIR)
   BPF_PATH=$(BPF_DIR)
+  SUBCMD_PATH=$(SUBCMD_DIR)
 endif
 
 LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
@@ -201,11 +204,13 @@ export LIBTRACEEVENT
 LIBTRACEEVENT_DYNAMIC_LIST = $(TE_PATH)libtraceevent-dynamic-list
 LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS = -Xlinker --dynamic-list=$(LIBTRACEEVENT_DYNAMIC_LIST)
 
-LIBAPI = $(LIB_PATH)libapi.a
+LIBAPI = $(API_PATH)libapi.a
 export LIBAPI
 
 LIBBPF = $(BPF_PATH)libbpf.a
 
+LIBSUBCMD = $(SUBCMD_PATH)libsubcmd.a
+
 # python extension build directories
 PYTHON_EXTBUILD     := $(OUTPUT)python_ext_build/
 PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
@@ -257,7 +262,7 @@ export PERL_PATH
 
 LIB_FILE=$(OUTPUT)libperf.a
 
-PERFLIBS = $(LIB_FILE) $(LIBAPI) $(LIBTRACEEVENT)
+PERFLIBS = $(LIB_FILE) $(LIBAPI) $(LIBTRACEEVENT) $(LIBSUBCMD)
 ifndef NO_LIBBPF
   PERFLIBS += $(LIBBPF)
 endif
@@ -420,7 +425,7 @@ $(LIBTRACEEVENT)-clean:
        $(call QUIET_CLEAN, libtraceevent)
        $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null
 
-install-traceevent-plugins: $(LIBTRACEEVENT)
+install-traceevent-plugins: libtraceevent_plugins
        $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) install_plugins
 
 $(LIBAPI): fixdep FORCE
@@ -431,12 +436,19 @@ $(LIBAPI)-clean:
        $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null
 
 $(LIBBPF): fixdep FORCE
-       $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) $(OUTPUT)libbpf.a
+       $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) $(OUTPUT)libbpf.a FEATURES_DUMP=$(realpath $(OUTPUT)FEATURE-DUMP)
 
 $(LIBBPF)-clean:
        $(call QUIET_CLEAN, libbpf)
        $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) clean >/dev/null
 
+$(LIBSUBCMD): fixdep FORCE
+       $(Q)$(MAKE) -C $(SUBCMD_DIR) O=$(OUTPUT) $(OUTPUT)libsubcmd.a
+
+$(LIBSUBCMD)-clean:
+       $(call QUIET_CLEAN, libsubcmd)
+       $(Q)$(MAKE) -C $(SUBCMD_DIR) O=$(OUTPUT) clean
+
 help:
        @echo 'Perf make targets:'
        @echo '  doc            - make *all* documentation (see below)'
@@ -476,7 +488,7 @@ INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html
 $(DOC_TARGETS):
        $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all)
 
-TAG_FOLDERS= . ../lib/traceevent ../lib/api ../lib/symbol ../include ../lib/bpf
+TAG_FOLDERS= . ../lib ../include
 TAG_FILES= ../../include/uapi/linux/perf_event.h
 
 TAGS:
@@ -555,6 +567,9 @@ endif
        $(call QUIET_INSTALL, perf_completion-script) \
                $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \
                $(INSTALL) perf-completion.sh '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
+       $(call QUIET_INSTALL, perf-tip) \
+               $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(tip_instdir_SQ)'; \
+               $(INSTALL) Documentation/tips.txt -t '$(DESTDIR_SQ)$(tip_instdir_SQ)'
 
 install-tests: all install-gtk
        $(call QUIET_INSTALL, tests) \
@@ -582,15 +597,16 @@ $(INSTALL_DOC_TARGETS):
 #
 config-clean:
        $(call QUIET_CLEAN, config)
-       $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ clean >/dev/null
+       $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ $(if $(OUTPUT),OUTPUT=$(OUTPUT)feature/,) clean >/dev/null
 
-clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean config-clean
+clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean config-clean
        $(call QUIET_CLEAN, core-objs)  $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS)
-       $(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
+       $(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
        $(Q)$(RM) $(OUTPUT).config-detected
        $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32
        $(call QUIET_CLEAN, core-gen)   $(RM)  *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \
-               $(OUTPUT)util/intel-pt-decoder/inat-tables.c
+               $(OUTPUT)util/intel-pt-decoder/inat-tables.c $(OUTPUT)fixdep \
+               $(OUTPUT)tests/llvm-src-{base,kbuild,prologue}.c
        $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
        $(python-clean)
 
index 7ed00f4b09080fdb5379129d8ed952d43b258f1e..b48de2f5813c60ac037d717a05ee408581e8dec2 100644 (file)
@@ -2,10 +2,10 @@
 #define ARCH_TESTS_H
 
 /* Tests */
-int test__rdpmc(void);
-int test__perf_time_to_tsc(void);
-int test__insn_x86(void);
-int test__intel_cqm_count_nmi_context(void);
+int test__rdpmc(int subtest);
+int test__perf_time_to_tsc(int subtest);
+int test__insn_x86(int subtest);
+int test__intel_cqm_count_nmi_context(int subtest);
 
 #ifdef HAVE_DWARF_UNWIND_SUPPORT
 struct thread;
index b6115dfd28f04197e6293a827ee29a2e4e0c79c6..08d9b2bc185ca039855266e5608794dad7dbfdb0 100644 (file)
@@ -171,7 +171,7 @@ static int test_data_set(struct test_data *dat_set, int x86_64)
  * verbose (-v) option to see all the instructions and whether or not they
  * decoded successfuly.
  */
-int test__insn_x86(void)
+int test__insn_x86(int subtest __maybe_unused)
 {
        int ret = 0;
 
index d28c1b6a3b54d3d6cd89e14b4d1770168fcf3d8b..3e89ba825f6bf3b3f8b15b9110564c63283998b4 100644 (file)
@@ -33,7 +33,7 @@ static pid_t spawn(void)
  * the last read counter value to avoid triggering a WARN_ON_ONCE() in
  * smp_call_function_many() caused by sending IPIs from NMI context.
  */
-int test__intel_cqm_count_nmi_context(void)
+int test__intel_cqm_count_nmi_context(int subtest __maybe_unused)
 {
        struct perf_evlist *evlist = NULL;
        struct perf_evsel *evsel = NULL;
@@ -54,7 +54,7 @@ int test__intel_cqm_count_nmi_context(void)
 
        ret = parse_events(evlist, "intel_cqm/llc_occupancy/", NULL);
        if (ret) {
-               pr_debug("parse_events failed\n");
+               pr_debug("parse_events failed, is \"intel_cqm/llc_occupancy/\" available?\n");
                err = TEST_SKIP;
                goto out;
        }
index 658cd200af74dca1a1f5165626b0cc51ab517087..9d29ee283ac5334bfd6a529c7a9d226f0db782cd 100644 (file)
  * %0 is returned, otherwise %-1 is returned.  If TSC conversion is not
  * supported then then the test passes but " (not supported)" is printed.
  */
-int test__perf_time_to_tsc(void)
+int test__perf_time_to_tsc(int subtest __maybe_unused)
 {
        struct record_opts opts = {
                .mmap_pages          = UINT_MAX,
                .user_freq           = UINT_MAX,
                .user_interval       = ULLONG_MAX,
-               .freq                = 4000,
                .target              = {
                        .uses_mmap   = true,
                },
index e7688214c7cf19fc040170b2590d19d8e011b6e8..7bb0d13c235f70326afc28d726f38f1d95499055 100644 (file)
@@ -149,7 +149,7 @@ out_close:
        return 0;
 }
 
-int test__rdpmc(void)
+int test__rdpmc(int subtest __maybe_unused)
 {
        int status = 0;
        int wret = 0;
index ff63649fa9ac603b32d7e28f3f309918e3c49fdf..465970370f3ed4db72ca525ae5f56f55150d7b12 100644 (file)
@@ -5,6 +5,7 @@ libperf-y += kvm-stat.o
 libperf-y += perf_regs.o
 
 libperf-$(CONFIG_DWARF) += dwarf-regs.o
+libperf-$(CONFIG_BPF_PROLOGUE) += dwarf-regs.o
 
 libperf-$(CONFIG_LIBUNWIND)          += unwind-libunwind.o
 libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
index 9b94ce5209170fcb6105723aea00bf1214fc4032..8d8150f1cf9bcf426b4c29a19170221db680a980 100644 (file)
@@ -327,7 +327,7 @@ static int intel_bts_snapshot_start(struct auxtrace_record *itr)
 
        evlist__for_each(btsr->evlist, evsel) {
                if (evsel->attr.type == btsr->intel_bts_pmu->type)
-                       return perf_evlist__disable_event(btsr->evlist, evsel);
+                       return perf_evsel__disable(evsel);
        }
        return -EINVAL;
 }
@@ -340,7 +340,7 @@ static int intel_bts_snapshot_finish(struct auxtrace_record *itr)
 
        evlist__for_each(btsr->evlist, evsel) {
                if (evsel->attr.type == btsr->intel_bts_pmu->type)
-                       return perf_evlist__enable_event(btsr->evlist, evsel);
+                       return perf_evsel__enable(evsel);
        }
        return -EINVAL;
 }
index b02af064f0f98333b6f90a5d6dd8778e6a7a6bb4..f05daacc9e7810117cfe25415a75990b3aa89f63 100644 (file)
@@ -26,7 +26,7 @@
 #include "../../util/evlist.h"
 #include "../../util/evsel.h"
 #include "../../util/cpumap.h"
-#include "../../util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "../../util/parse-events.h"
 #include "../../util/pmu.h"
 #include "../../util/debug.h"
@@ -725,7 +725,7 @@ static int intel_pt_snapshot_start(struct auxtrace_record *itr)
 
        evlist__for_each(ptr->evlist, evsel) {
                if (evsel->attr.type == ptr->intel_pt_pmu->type)
-                       return perf_evlist__disable_event(ptr->evlist, evsel);
+                       return perf_evsel__disable(evsel);
        }
        return -EINVAL;
 }
@@ -738,7 +738,7 @@ static int intel_pt_snapshot_finish(struct auxtrace_record *itr)
 
        evlist__for_each(ptr->evlist, evsel) {
                if (evsel->attr.type == ptr->intel_pt_pmu->type)
-                       return perf_evlist__enable_event(ptr->evlist, evsel);
+                       return perf_evsel__enable(evsel);
        }
        return -EINVAL;
 }
index fc9bebd2cca0575734f84f9947bf29f7f991c6ab..0999ac536d869c57b0dcb02505148698b9470bd5 100644 (file)
@@ -11,7 +11,7 @@
 #include "../perf.h"
 #include "../util/util.h"
 #include "../util/stat.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "../util/header.h"
 #include "bench.h"
 #include "futex.h"
index bc6a16adbca8a300ff71cb68c9ee705155dcbd4b..6a18ce21f8659baba96dd5c36f3460919906caba 100644 (file)
@@ -5,7 +5,7 @@
 #include "../perf.h"
 #include "../util/util.h"
 #include "../util/stat.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "../util/header.h"
 #include "bench.h"
 #include "futex.h"
index ad0d9b5342fb6ae4713178daf15fdcce6238a2d9..71823868301347a47fdc7d31723dd325426ac3a5 100644 (file)
@@ -11,7 +11,7 @@
 #include "../perf.h"
 #include "../util/util.h"
 #include "../util/stat.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "../util/header.h"
 #include "bench.h"
 #include "futex.h"
index 6d8c9fa2a16c8734b2520ab569db94b46d69e24d..91aaf2a1fa9050dae0a866e6a851777a87c37a0b 100644 (file)
@@ -10,7 +10,7 @@
 #include "../perf.h"
 #include "../util/util.h"
 #include "../util/stat.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "../util/header.h"
 #include "bench.h"
 #include "futex.h"
index e5e41d3bdce724230c16a3df2a199914b9cab29d..f416bd705f661f056da8e1424643922f1999600d 100644 (file)
@@ -11,7 +11,7 @@
 #include "../perf.h"
 #include "../util/util.h"
 #include "../util/stat.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "../util/header.h"
 #include "bench.h"
 #include "futex.h"
index 9419b944220f6fc85f9b9593cce81639e7097cad..a91aa85d80ffc250241d84178da82df658be8f36 100644 (file)
@@ -8,7 +8,7 @@
 
 #include "../perf.h"
 #include "../util/util.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "../util/header.h"
 #include "../util/cloexec.h"
 #include "bench.h"
index 492df2752a2d1057bbde642538f84da93aa9df8b..5049d6357a46953da0e2f9afe8d62c6e6e4238e7 100644 (file)
@@ -7,7 +7,7 @@
 #include "../perf.h"
 #include "../builtin.h"
 #include "../util/util.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "../util/cloexec.h"
 
 #include "bench.h"
index d4ff1b539cfd2727e0488858cf241aa83fe6c037..bfaf9503de8ef4d96a85770afb4f658c11e7d2e2 100644 (file)
@@ -11,7 +11,7 @@
 
 #include "../perf.h"
 #include "../util/util.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "../builtin.h"
 #include "bench.h"
 
index 005cc283790cfb7cf4db014362cb5d56f2a89ca2..1dc2d13cc2722c7c0207edc4fafb1b7f77b7697d 100644 (file)
@@ -10,7 +10,7 @@
  */
 #include "../perf.h"
 #include "../util/util.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "../builtin.h"
 #include "bench.h"
 
index 2bf9b3fd9e61546fb8fd58ff9a43f7c5106e2778..cc5c1267c738da038cfb6b824f79854fab41a629 100644 (file)
@@ -21,7 +21,7 @@
 #include "util/evsel.h"
 #include "util/annotate.h"
 #include "util/event.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/parse-events.h"
 #include "util/thread.h"
 #include "util/sort.h"
@@ -47,7 +47,7 @@ struct perf_annotate {
 };
 
 static int perf_evsel__add_sample(struct perf_evsel *evsel,
-                                 struct perf_sample *sample __maybe_unused,
+                                 struct perf_sample *sample,
                                  struct addr_location *al,
                                  struct perf_annotate *ann)
 {
@@ -72,7 +72,10 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
                return 0;
        }
 
-       he = __hists__add_entry(hists, al, NULL, NULL, NULL, 1, 1, 0, true);
+       sample->period = 1;
+       sample->weight = 1;
+
+       he = __hists__add_entry(hists, al, NULL, NULL, NULL, sample, true);
        if (he == NULL)
                return -ENOMEM;
 
@@ -343,18 +346,19 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
                return ret;
 
        argc = parse_options(argc, argv, options, annotate_usage, 0);
+       if (argc) {
+               /*
+                * Special case: if there's an argument left then assume that
+                * it's a symbol filter:
+                */
+               if (argc > 1)
+                       usage_with_options(annotate_usage, options);
 
-       if (annotate.use_stdio)
-               use_browser = 0;
-       else if (annotate.use_tui)
-               use_browser = 1;
-       else if (annotate.use_gtk)
-               use_browser = 2;
+               annotate.sym_hist_filter = argv[0];
+       }
 
        file.path  = input_name;
 
-       setup_browser(true);
-
        annotate.session = perf_session__new(&file, false, &annotate.tool);
        if (annotate.session == NULL)
                return -1;
@@ -366,19 +370,17 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
        if (ret < 0)
                goto out_delete;
 
-       if (setup_sorting() < 0)
+       if (setup_sorting(NULL) < 0)
                usage_with_options(annotate_usage, options);
 
-       if (argc) {
-               /*
-                * Special case: if there's an argument left then assume that
-                * it's a symbol filter:
-                */
-               if (argc > 1)
-                       usage_with_options(annotate_usage, options);
+       if (annotate.use_stdio)
+               use_browser = 0;
+       else if (annotate.use_tui)
+               use_browser = 1;
+       else if (annotate.use_gtk)
+               use_browser = 2;
 
-               annotate.sym_hist_filter = argv[0];
-       }
+       setup_browser(true);
 
        ret = __cmd_annotate(&annotate);
 
index b17aed36ca16207915ab935ecceea426e49a9ec6..a1cddc6bbf0f178f44ee03b2a3729b85a385dbd4 100644 (file)
@@ -16,7 +16,7 @@
  */
 #include "perf.h"
 #include "util/util.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "builtin.h"
 #include "bench/bench.h"
 
index 7b8450cd33c23ec7884a526fcb4fd3bec6ba6e8c..d93bff7fc0e407d6518a6ce0e2ee0dd4b65bf910 100644 (file)
@@ -16,7 +16,7 @@
 #include "util/cache.h"
 #include "util/debug.h"
 #include "util/header.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/strlist.h"
 #include "util/build-id.h"
 #include "util/session.h"
index 918b4de29de4ea86fc27cd40db49861618869d34..5e914ee79eb3f0eb3a5e38db5f02e7b792b2ce2c 100644 (file)
@@ -12,7 +12,7 @@
 #include "util/build-id.h"
 #include "util/cache.h"
 #include "util/debug.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/session.h"
 #include "util/symbol.h"
 #include "util/data.h"
@@ -110,7 +110,7 @@ int cmd_buildid_list(int argc, const char **argv,
        setup_pager();
 
        if (show_kernel)
-               return sysfs__fprintf_build_id(stdout);
+               return !(sysfs__fprintf_build_id(stdout) > 0);
 
        return perf_session__list_build_ids(force, with_hits);
 }
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
new file mode 100644 (file)
index 0000000..f04e804
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * builtin-config.c
+ *
+ * Copyright (C) 2015, Taeung Song <treeze.taeung@gmail.com>
+ *
+ */
+#include "builtin.h"
+
+#include "perf.h"
+
+#include "util/cache.h"
+#include <subcmd/parse-options.h>
+#include "util/util.h"
+#include "util/debug.h"
+
+static const char * const config_usage[] = {
+       "perf config [options]",
+       NULL
+};
+
+enum actions {
+       ACTION_LIST = 1
+} actions;
+
+static struct option config_options[] = {
+       OPT_SET_UINT('l', "list", &actions,
+                    "show current config variables", ACTION_LIST),
+       OPT_END()
+};
+
+static int show_config(const char *key, const char *value,
+                      void *cb __maybe_unused)
+{
+       if (value)
+               printf("%s=%s\n", key, value);
+       else
+               printf("%s\n", key);
+
+       return 0;
+}
+
+int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
+{
+       int ret = 0;
+
+       argc = parse_options(argc, argv, config_options, config_usage,
+                            PARSE_OPT_STOP_AT_NON_OPTION);
+
+       switch (actions) {
+       case ACTION_LIST:
+               if (argc) {
+                       pr_err("Error: takes no arguments\n");
+                       parse_options_usage(config_usage, config_options, "l", 1);
+               } else {
+                       ret = perf_config(show_config, NULL);
+                       if (ret < 0)
+                               pr_err("Nothing configured, "
+                                      "please check your ~/.perfconfig file\n");
+               }
+               break;
+       default:
+               usage_with_options(config_usage, config_options);
+       }
+
+       return ret;
+}
index d6525bc54d13e337e927b197ab87da55f99492ae..b97bc1518b44a5f7ffb85eeefa7f6ffae95e74f1 100644 (file)
@@ -2,7 +2,7 @@
 #include "builtin.h"
 #include "perf.h"
 #include "debug.h"
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
 #include "data-convert-bt.h"
 
 typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix);
index 0b180a885ba369cc79f3c47e888fa91ed782c09b..36ccc2b8827fdd239b657e79b396ae013c318462 100644 (file)
@@ -311,11 +311,11 @@ static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
 }
 
 static int hists__add_entry(struct hists *hists,
-                           struct addr_location *al, u64 period,
-                           u64 weight, u64 transaction)
+                           struct addr_location *al,
+                           struct perf_sample *sample)
 {
-       if (__hists__add_entry(hists, al, NULL, NULL, NULL, period, weight,
-                              transaction, true) != NULL)
+       if (__hists__add_entry(hists, al, NULL, NULL, NULL,
+                              sample, true) != NULL)
                return 0;
        return -ENOMEM;
 }
@@ -336,8 +336,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
                return -1;
        }
 
-       if (hists__add_entry(hists, &al, sample->period,
-                            sample->weight, sample->transaction)) {
+       if (hists__add_entry(hists, &al, sample)) {
                pr_warning("problem incrementing symbol period, skipping event\n");
                goto out_put;
        }
@@ -1208,7 +1207,7 @@ static int ui_init(void)
                BUG_ON(1);
        }
 
-       list_add(&fmt->sort_list, &perf_hpp__sort_list);
+       perf_hpp__register_sort_field(fmt);
        return 0;
 }
 
@@ -1280,7 +1279,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
 
        sort__mode = SORT_MODE__DIFF;
 
-       if (setup_sorting() < 0)
+       if (setup_sorting(NULL) < 0)
                usage_with_options(diff_usage, options);
 
        setup_pager();
index f4d62510acbbb5603ad246bea89a7dfb95c07f43..8a31f511e1a0d79b9784387fa7b01db42ac3094e 100644 (file)
@@ -12,7 +12,7 @@
 #include "util/evlist.h"
 #include "util/evsel.h"
 #include "util/parse-events.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/session.h"
 #include "util/data.h"
 #include "util/debug.h"
@@ -26,14 +26,22 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
                .mode = PERF_DATA_MODE_READ,
                .force = details->force,
        };
+       bool has_tracepoint = false;
 
        session = perf_session__new(&file, 0, NULL);
        if (session == NULL)
                return -1;
 
-       evlist__for_each(session->evlist, pos)
+       evlist__for_each(session->evlist, pos) {
                perf_evsel__fprintf(pos, details, stdout);
 
+               if (pos->attr.type == PERF_TYPE_TRACEPOINT)
+                       has_tracepoint = true;
+       }
+
+       if (has_tracepoint && !details->trace_fields)
+               printf("# Tip: use 'perf evlist --trace-fields' to show fields for tracepoint events\n");
+
        perf_session__delete(session);
        return 0;
 }
@@ -49,6 +57,7 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused)
        OPT_BOOLEAN('g', "group", &details.event_group,
                    "Show event group information"),
        OPT_BOOLEAN('f', "force", &details.force, "don't complain, do it"),
+       OPT_BOOLEAN(0, "trace-fields", &details.trace_fields, "Show tracepoint fields"),
        OPT_END()
        };
        const char * const evlist_usage[] = {
index a7d588bf3cdd345233042131373666af2f9d7598..96c1a4cfbbbf6b1f639d91d562c55b09da5c7e6f 100644 (file)
@@ -6,11 +6,11 @@
 #include "perf.h"
 #include "util/cache.h"
 #include "builtin.h"
-#include "util/exec_cmd.h"
+#include <subcmd/exec-cmd.h>
 #include "common-cmds.h"
-#include "util/parse-options.h"
-#include "util/run-command.h"
-#include "util/help.h"
+#include <subcmd/parse-options.h>
+#include <subcmd/run-command.h>
+#include <subcmd/help.h>
 #include "util/debug.h"
 
 static struct man_viewer_list {
@@ -407,7 +407,7 @@ static int get_html_page_path(struct strbuf *page_path, const char *page)
 #ifndef open_html
 static void open_html(const char *path)
 {
-       execl_perf_cmd("web--browse", "-c", "help.browser", path, NULL);
+       execl_cmd("web--browse", "-c", "help.browser", path, NULL);
 }
 #endif
 
index 99d127fe9c35e500ca74ea871fd4373fcea15d68..0022e02ed31a7034b9286884ab87c4c131e41fa3 100644 (file)
@@ -18,7 +18,7 @@
 #include "util/data.h"
 #include "util/auxtrace.h"
 
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 
 #include <linux/list.h>
 
index 93ce665f976f65a4a1889ba01441bb1f1cce2786..118010553d0cf0dca9de6f493a5c8e267b0fff48 100644 (file)
@@ -12,7 +12,7 @@
 #include "util/tool.h"
 #include "util/callchain.h"
 
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/trace-event.h"
 #include "util/data.h"
 #include "util/cpumap.h"
index dd94b4ca22131a211729082925bbbf082d19c73e..4418d9214872150648a719dd07fc14a29c913e9b 100644 (file)
@@ -10,7 +10,7 @@
 #include "util/header.h"
 #include "util/session.h"
 #include "util/intlist.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/trace-event.h"
 #include "util/debug.h"
 #include "util/tool.h"
@@ -1351,7 +1351,6 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
        disable_buildid_cache();
 
        use_browser = 0;
-       setup_browser(false);
 
        if (argc) {
                argc = parse_options(argc, argv, live_options,
@@ -1409,8 +1408,6 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
        err = kvm_events_live_report(kvm);
 
 out:
-       exit_browser(0);
-
        if (kvm->session)
                perf_session__delete(kvm->session);
        kvm->session = NULL;
index bf679e2c978bdef9b7943271987e4b7e4e465981..5e22db4684b86a7a226c5d070594f160f2bc9237 100644 (file)
@@ -14,7 +14,7 @@
 #include "util/parse-events.h"
 #include "util/cache.h"
 #include "util/pmu.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 
 int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
 {
index de16aaed516e6016b2a8d887f87727a8179acf19..ce3bfb48b26f0f309b5c90cf49bb4870fbd76a4b 100644 (file)
@@ -9,7 +9,7 @@
 #include "util/thread.h"
 #include "util/header.h"
 
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/trace-event.h"
 
 #include "util/debug.h"
index 80170aace5d4c893b99a842427759c8f5766066e..39017004169665ec4a2ebd59aa0bc43e58412874 100644 (file)
@@ -1,7 +1,7 @@
 #include "builtin.h"
 #include "perf.h"
 
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/trace-event.h"
 #include "util/tool.h"
 #include "util/session.h"
index 132afc97676c1861d7be03bbbd4f5cea99eb9e57..9af859b28b15cc74edbf8041278ec2ee9e47104e 100644 (file)
@@ -37,7 +37,7 @@
 #include "util/strfilter.h"
 #include "util/symbol.h"
 #include "util/debug.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/probe-finder.h"
 #include "util/probe-event.h"
 #include "util/probe-file.h"
@@ -249,6 +249,9 @@ static int opt_show_vars(const struct option *opt,
 
        return ret;
 }
+#else
+# define opt_show_lines NULL
+# define opt_show_vars NULL
 #endif
 static int opt_add_probe_event(const struct option *opt,
                              const char *str, int unset __maybe_unused)
@@ -473,7 +476,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
                opt_add_probe_event),
        OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events"
                    " with existing name"),
-#ifdef HAVE_DWARF_SUPPORT
        OPT_CALLBACK('L', "line", NULL,
                     "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
                     "Show source code lines.", opt_show_lines),
@@ -490,7 +492,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
                   "directory", "path to kernel source"),
        OPT_BOOLEAN('\0', "no-inlines", &probe_conf.no_inlines,
                "Don't search inlined functions"),
-#endif
        OPT__DRY_RUN(&probe_event_dry_run),
        OPT_INTEGER('\0', "max-probes", &probe_conf.max_probes,
                 "Set how many probe points can be found for a probe."),
@@ -521,6 +522,16 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 #ifdef HAVE_DWARF_SUPPORT
        set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE);
        set_option_flag(options, 'V', "vars", PARSE_OPT_EXCLUSIVE);
+#else
+# define set_nobuild(s, l, c) set_option_nobuild(options, s, l, "NO_DWARF=1", c)
+       set_nobuild('L', "line", false);
+       set_nobuild('V', "vars", false);
+       set_nobuild('\0', "externs", false);
+       set_nobuild('\0', "range", false);
+       set_nobuild('k', "vmlinux", true);
+       set_nobuild('s', "source", true);
+       set_nobuild('\0', "no-inlines", true);
+# undef set_nobuild
 #endif
        set_option_flag(options, 'F', "funcs", PARSE_OPT_EXCLUSIVE);
 
index 199fc31e3919c5743ca305f9eef5ef8c8fc86a70..dc4e0adf5c5b5c60cf96cb22120918c575f2b113 100644 (file)
@@ -11,7 +11,7 @@
 
 #include "util/build-id.h"
 #include "util/util.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/parse-events.h"
 
 #include "util/callchain.h"
@@ -452,6 +452,8 @@ static void record__init_features(struct record *rec)
 
        if (!rec->opts.full_auxtrace)
                perf_header__clear_feat(&session->header, HEADER_AUXTRACE);
+
+       perf_header__clear_feat(&session->header, HEADER_STAT);
 }
 
 static volatile int workload_exec_errno;
@@ -813,8 +815,12 @@ int record_parse_callchain_opt(const struct option *opt,
        }
 
        ret = parse_callchain_record_opt(arg, &callchain_param);
-       if (!ret)
+       if (!ret) {
+               /* Enable data address sampling for DWARF unwind. */
+               if (callchain_param.record_mode == CALLCHAIN_DWARF)
+                       record->sample_address = true;
                callchain_debug();
+       }
 
        return ret;
 }
@@ -837,6 +843,19 @@ int record_callchain_opt(const struct option *opt,
 
 static int perf_record_config(const char *var, const char *value, void *cb)
 {
+       struct record *rec = cb;
+
+       if (!strcmp(var, "record.build-id")) {
+               if (!strcmp(value, "cache"))
+                       rec->no_buildid_cache = false;
+               else if (!strcmp(value, "no-cache"))
+                       rec->no_buildid_cache = true;
+               else if (!strcmp(value, "skip"))
+                       rec->no_buildid = true;
+               else
+                       return -1;
+               return 0;
+       }
        if (!strcmp(var, "record.call-graph"))
                var = "call-graph.record-mode"; /* fall-through */
 
@@ -1113,12 +1132,12 @@ struct option __record_options[] = {
                        "per thread proc mmap processing timeout in ms"),
        OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
                    "Record context switch events"),
-#ifdef HAVE_LIBBPF_SUPPORT
        OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path",
                   "clang binary to use for compiling BPF scriptlets"),
        OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options",
                   "options passed to clang when compiling BPF scriptlets"),
-#endif
+       OPT_STRING(0, "vmlinux", &symbol_conf.vmlinux_name,
+                  "file", "vmlinux pathname"),
        OPT_END()
 };
 
@@ -1130,6 +1149,27 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
        struct record *rec = &record;
        char errbuf[BUFSIZ];
 
+#ifndef HAVE_LIBBPF_SUPPORT
+# define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, "NO_LIBBPF=1", c)
+       set_nobuild('\0', "clang-path", true);
+       set_nobuild('\0', "clang-opt", true);
+# undef set_nobuild
+#endif
+
+#ifndef HAVE_BPF_PROLOGUE
+# if !defined (HAVE_DWARF_SUPPORT)
+#  define REASON  "NO_DWARF=1"
+# elif !defined (HAVE_LIBBPF_SUPPORT)
+#  define REASON  "NO_LIBBPF=1"
+# else
+#  define REASON  "this architecture doesn't support BPF prologue"
+# endif
+# define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, REASON, c)
+       set_nobuild('\0', "vmlinux", true);
+# undef set_nobuild
+# undef REASON
+#endif
+
        rec->evlist = perf_evlist__new();
        if (rec->evlist == NULL)
                return -ENOMEM;
index f256fac1e722527a18e585ed51a591c15c574207..d5a42ee12529b97fdcb2b0a74ece8bf2db701550 100644 (file)
@@ -27,7 +27,7 @@
 #include "util/session.h"
 #include "util/tool.h"
 
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/parse-events.h"
 
 #include "util/thread.h"
@@ -45,7 +45,6 @@ struct report {
        struct perf_tool        tool;
        struct perf_session     *session;
        bool                    use_tui, use_gtk, use_stdio;
-       bool                    hide_unresolved;
        bool                    dont_use_callchains;
        bool                    show_full_info;
        bool                    show_threads;
@@ -146,7 +145,7 @@ static int process_sample_event(struct perf_tool *tool,
        struct hist_entry_iter iter = {
                .evsel                  = evsel,
                .sample                 = sample,
-               .hide_unresolved        = rep->hide_unresolved,
+               .hide_unresolved        = symbol_conf.hide_unresolved,
                .add_entry_cb           = hist_iter__report_callback,
        };
        int ret = 0;
@@ -157,7 +156,7 @@ static int process_sample_event(struct perf_tool *tool,
                return -1;
        }
 
-       if (rep->hide_unresolved && al.sym == NULL)
+       if (symbol_conf.hide_unresolved && al.sym == NULL)
                goto out_put;
 
        if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
@@ -434,7 +433,7 @@ static int report__browse_hists(struct report *rep)
        int ret;
        struct perf_session *session = rep->session;
        struct perf_evlist *evlist = session->evlist;
-       const char *help = "For a higher level overview, try: perf report --sort comm,dso";
+       const char *help = perf_tip(TIPDIR);
 
        switch (use_browser) {
        case 1:
@@ -514,20 +513,26 @@ static int __cmd_report(struct report *rep)
        if (rep->cpu_list) {
                ret = perf_session__cpu_bitmap(session, rep->cpu_list,
                                               rep->cpu_bitmap);
-               if (ret)
+               if (ret) {
+                       ui__error("failed to set cpu bitmap\n");
                        return ret;
+               }
        }
 
        if (rep->show_threads)
                perf_read_values_init(&rep->show_threads_values);
 
        ret = report__setup_sample_type(rep);
-       if (ret)
+       if (ret) {
+               /* report__setup_sample_type() already showed error message */
                return ret;
+       }
 
        ret = perf_session__process_events(session);
-       if (ret)
+       if (ret) {
+               ui__error("failed to process sample\n");
                return ret;
+       }
 
        report__warn_kptr_restrict(rep);
 
@@ -625,7 +630,7 @@ parse_percent_limit(const struct option *opt, const char *str,
        return 0;
 }
 
-#define CALLCHAIN_DEFAULT_OPT  "graph,0.5,caller,function"
+#define CALLCHAIN_DEFAULT_OPT  "graph,0.5,caller,function,percent"
 
 const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n"
                                     CALLCHAIN_REPORT_HELP
@@ -708,7 +713,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
        OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
                    "Only display entries with parent-match"),
        OPT_CALLBACK_DEFAULT('g', "call-graph", &report,
-                            "print_type,threshold[,print_limit],order,sort_key[,branch]",
+                            "print_type,threshold[,print_limit],order,sort_key[,branch],value",
                             report_callchain_help, &report_parse_callchain_opt,
                             callchain_default_opt),
        OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
@@ -740,7 +745,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
        OPT_STRING_NOEMPTY('t', "field-separator", &symbol_conf.field_sep, "separator",
                   "separator for columns, no spaces will be added between "
                   "columns '.' is reserved."),
-       OPT_BOOLEAN('U', "hide-unresolved", &report.hide_unresolved,
+       OPT_BOOLEAN('U', "hide-unresolved", &symbol_conf.hide_unresolved,
                    "Only display entries resolved to a symbol"),
        OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
                    "Look for files with symbols relative to this directory"),
@@ -783,6 +788,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
                    "Show callgraph from reference event"),
        OPT_INTEGER(0, "socket-filter", &report.socket_filter,
                    "only show processor socket that match with this filter"),
+       OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace,
+                   "Show raw trace event output (do not use print fmt or plugins)"),
        OPT_END()
        };
        struct perf_data_file file = {
@@ -796,6 +803,16 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
        perf_config(report__config, &report);
 
        argc = parse_options(argc, argv, options, report_usage, 0);
+       if (argc) {
+               /*
+                * Special case: if there's an argument left then assume that
+                * it's a symbol filter:
+                */
+               if (argc > 1)
+                       usage_with_options(report_usage, options);
+
+               report.symbol_filter_str = argv[0];
+       }
 
        if (symbol_conf.vmlinux_name &&
            access(symbol_conf.vmlinux_name, R_OK)) {
@@ -882,7 +899,7 @@ repeat:
                symbol_conf.cumulate_callchain = false;
        }
 
-       if (setup_sorting() < 0) {
+       if (setup_sorting(session->evlist) < 0) {
                if (sort_order)
                        parse_options_usage(report_usage, options, "s", 1);
                if (field_order)
@@ -941,17 +958,6 @@ repeat:
        if (symbol__init(&session->header.env) < 0)
                goto error;
 
-       if (argc) {
-               /*
-                * Special case: if there's an argument left then assume that
-                * it's a symbol filter:
-                */
-               if (argc > 1)
-                       usage_with_options(report_usage, options);
-
-               report.symbol_filter_str = argv[0];
-       }
-
        sort__setup_elide(stdout);
 
        ret = __cmd_report(&report);
index e3d3e32c0a934dc8fd5ce207073f3b80ecf4361a..871b55ae22a4170d285c119cc5f5dddfc90a60e1 100644 (file)
@@ -12,7 +12,7 @@
 #include "util/tool.h"
 #include "util/cloexec.h"
 
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/trace-event.h"
 
 #include "util/debug.h"
index 72b5deb4bd7961bc4fdb86c50689253b23660b0e..c691214d820f0050c39e9d376d69cd5891132a47 100644 (file)
@@ -3,9 +3,9 @@
 #include "perf.h"
 #include "util/cache.h"
 #include "util/debug.h"
-#include "util/exec_cmd.h"
+#include <subcmd/exec-cmd.h>
 #include "util/header.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/perf_regs.h"
 #include "util/session.h"
 #include "util/tool.h"
 #include "util/sort.h"
 #include "util/data.h"
 #include "util/auxtrace.h"
+#include "util/cpumap.h"
+#include "util/thread_map.h"
+#include "util/stat.h"
 #include <linux/bitmap.h>
+#include "asm/bug.h"
 
 static char const              *script_name;
 static char const              *generate_script_lang;
@@ -32,6 +36,7 @@ static bool                   print_flags;
 static bool                    nanosecs;
 static const char              *cpu_list;
 static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
+static struct perf_stat_config stat_config;
 
 unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH;
 
@@ -130,6 +135,18 @@ static struct {
 
                .invalid_fields = PERF_OUTPUT_TRACE,
        },
+
+       [PERF_TYPE_BREAKPOINT] = {
+               .user_set = false,
+
+               .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
+                             PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
+                             PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
+                             PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
+                             PERF_OUTPUT_PERIOD,
+
+               .invalid_fields = PERF_OUTPUT_TRACE,
+       },
 };
 
 static bool output_set_by_user(void)
@@ -204,6 +221,9 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
        struct perf_event_attr *attr = &evsel->attr;
        bool allow_user_set;
 
+       if (perf_header__has_feat(&session->header, HEADER_STAT))
+               return 0;
+
        allow_user_set = perf_header__has_feat(&session->header,
                                               HEADER_AUXTRACE);
 
@@ -588,8 +608,35 @@ static void print_sample_flags(u32 flags)
        printf("  %-4s ", str);
 }
 
-static void process_event(union perf_event *event, struct perf_sample *sample,
-                         struct perf_evsel *evsel, struct addr_location *al)
+struct perf_script {
+       struct perf_tool        tool;
+       struct perf_session     *session;
+       bool                    show_task_events;
+       bool                    show_mmap_events;
+       bool                    show_switch_events;
+       bool                    allocated;
+       struct cpu_map          *cpus;
+       struct thread_map       *threads;
+       int                     name_width;
+};
+
+static int perf_evlist__max_name_len(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel;
+       int max = 0;
+
+       evlist__for_each(evlist, evsel) {
+               int len = strlen(perf_evsel__name(evsel));
+
+               max = MAX(len, max);
+       }
+
+       return max;
+}
+
+static void process_event(struct perf_script *script, union perf_event *event,
+                         struct perf_sample *sample, struct perf_evsel *evsel,
+                         struct addr_location *al)
 {
        struct thread *thread = al->thread;
        struct perf_event_attr *attr = &evsel->attr;
@@ -604,7 +651,12 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
 
        if (PRINT_FIELD(EVNAME)) {
                const char *evname = perf_evsel__name(evsel);
-               printf("%s: ", evname ? evname : "[unknown]");
+
+               if (!script->name_width)
+                       script->name_width = perf_evlist__max_name_len(script->session->evlist);
+
+               printf("%*s: ", script->name_width,
+                      evname ? evname : "[unknown]");
        }
 
        if (print_flags)
@@ -643,65 +695,81 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
        printf("\n");
 }
 
-static int default_start_script(const char *script __maybe_unused,
-                               int argc __maybe_unused,
-                               const char **argv __maybe_unused)
-{
-       return 0;
-}
+static struct scripting_ops    *scripting_ops;
 
-static int default_flush_script(void)
+static void __process_stat(struct perf_evsel *counter, u64 tstamp)
 {
-       return 0;
+       int nthreads = thread_map__nr(counter->threads);
+       int ncpus = perf_evsel__nr_cpus(counter);
+       int cpu, thread;
+       static int header_printed;
+
+       if (counter->system_wide)
+               nthreads = 1;
+
+       if (!header_printed) {
+               printf("%3s %8s %15s %15s %15s %15s %s\n",
+                      "CPU", "THREAD", "VAL", "ENA", "RUN", "TIME", "EVENT");
+               header_printed = 1;
+       }
+
+       for (thread = 0; thread < nthreads; thread++) {
+               for (cpu = 0; cpu < ncpus; cpu++) {
+                       struct perf_counts_values *counts;
+
+                       counts = perf_counts(counter->counts, cpu, thread);
+
+                       printf("%3d %8d %15" PRIu64 " %15" PRIu64 " %15" PRIu64 " %15" PRIu64 " %s\n",
+                               counter->cpus->map[cpu],
+                               thread_map__pid(counter->threads, thread),
+                               counts->val,
+                               counts->ena,
+                               counts->run,
+                               tstamp,
+                               perf_evsel__name(counter));
+               }
+       }
 }
 
-static int default_stop_script(void)
+static void process_stat(struct perf_evsel *counter, u64 tstamp)
 {
-       return 0;
+       if (scripting_ops && scripting_ops->process_stat)
+               scripting_ops->process_stat(&stat_config, counter, tstamp);
+       else
+               __process_stat(counter, tstamp);
 }
 
-static int default_generate_script(struct pevent *pevent __maybe_unused,
-                                  const char *outfile __maybe_unused)
+static void process_stat_interval(u64 tstamp)
 {
-       return 0;
+       if (scripting_ops && scripting_ops->process_stat_interval)
+               scripting_ops->process_stat_interval(tstamp);
 }
 
-static struct scripting_ops default_scripting_ops = {
-       .start_script           = default_start_script,
-       .flush_script           = default_flush_script,
-       .stop_script            = default_stop_script,
-       .process_event          = process_event,
-       .generate_script        = default_generate_script,
-};
-
-static struct scripting_ops    *scripting_ops;
-
 static void setup_scripting(void)
 {
        setup_perl_scripting();
        setup_python_scripting();
-
-       scripting_ops = &default_scripting_ops;
 }
 
 static int flush_scripting(void)
 {
-       return scripting_ops->flush_script();
+       return scripting_ops ? scripting_ops->flush_script() : 0;
 }
 
 static int cleanup_scripting(void)
 {
        pr_debug("\nperf script stopped\n");
 
-       return scripting_ops->stop_script();
+       return scripting_ops ? scripting_ops->stop_script() : 0;
 }
 
-static int process_sample_event(struct perf_tool *tool __maybe_unused,
+static int process_sample_event(struct perf_tool *tool,
                                union perf_event *event,
                                struct perf_sample *sample,
                                struct perf_evsel *evsel,
                                struct machine *machine)
 {
+       struct perf_script *scr = container_of(tool, struct perf_script, tool);
        struct addr_location al;
 
        if (debug_mode) {
@@ -727,20 +795,16 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
        if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
                goto out_put;
 
-       scripting_ops->process_event(event, sample, evsel, &al);
+       if (scripting_ops)
+               scripting_ops->process_event(event, sample, evsel, &al);
+       else
+               process_event(scr, event, sample, evsel, &al);
+
 out_put:
        addr_location__put(&al);
        return 0;
 }
 
-struct perf_script {
-       struct perf_tool        tool;
-       struct perf_session     *session;
-       bool                    show_task_events;
-       bool                    show_mmap_events;
-       bool                    show_switch_events;
-};
-
 static int process_attr(struct perf_tool *tool, union perf_event *event,
                        struct perf_evlist **pevlist)
 {
@@ -1156,6 +1220,8 @@ static int parse_output_fields(const struct option *opt __maybe_unused,
                        type = PERF_TYPE_TRACEPOINT;
                else if (!strcmp(str, "raw"))
                        type = PERF_TYPE_RAW;
+               else if (!strcmp(str, "break"))
+                       type = PERF_TYPE_BREAKPOINT;
                else {
                        fprintf(stderr, "Invalid event type in field string.\n");
                        rc = -EINVAL;
@@ -1421,7 +1487,7 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
        char first_half[BUFSIZ];
        char *script_root;
 
-       snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
+       snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path());
 
        scripts_dir = opendir(scripts_path);
        if (!scripts_dir)
@@ -1542,7 +1608,7 @@ int find_scripts(char **scripts_array, char **scripts_path_array)
        if (!session)
                return -1;
 
-       snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
+       snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path());
 
        scripts_dir = opendir(scripts_path);
        if (!scripts_dir) {
@@ -1600,7 +1666,7 @@ static char *get_script_path(const char *script_root, const char *suffix)
        char lang_path[MAXPATHLEN];
        char *__script_root;
 
-       snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
+       snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path());
 
        scripts_dir = opendir(scripts_path);
        if (!scripts_dir)
@@ -1695,6 +1761,87 @@ static void script__setup_sample_type(struct perf_script *script)
        }
 }
 
+static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
+                                   union perf_event *event,
+                                   struct perf_session *session)
+{
+       struct stat_round_event *round = &event->stat_round;
+       struct perf_evsel *counter;
+
+       evlist__for_each(session->evlist, counter) {
+               perf_stat_process_counter(&stat_config, counter);
+               process_stat(counter, round->time);
+       }
+
+       process_stat_interval(round->time);
+       return 0;
+}
+
+static int process_stat_config_event(struct perf_tool *tool __maybe_unused,
+                                    union perf_event *event,
+                                    struct perf_session *session __maybe_unused)
+{
+       perf_event__read_stat_config(&stat_config, &event->stat_config);
+       return 0;
+}
+
+static int set_maps(struct perf_script *script)
+{
+       struct perf_evlist *evlist = script->session->evlist;
+
+       if (!script->cpus || !script->threads)
+               return 0;
+
+       if (WARN_ONCE(script->allocated, "stats double allocation\n"))
+               return -EINVAL;
+
+       perf_evlist__set_maps(evlist, script->cpus, script->threads);
+
+       if (perf_evlist__alloc_stats(evlist, true))
+               return -ENOMEM;
+
+       script->allocated = true;
+       return 0;
+}
+
+static
+int process_thread_map_event(struct perf_tool *tool,
+                            union perf_event *event,
+                            struct perf_session *session __maybe_unused)
+{
+       struct perf_script *script = container_of(tool, struct perf_script, tool);
+
+       if (script->threads) {
+               pr_warning("Extra thread map event, ignoring.\n");
+               return 0;
+       }
+
+       script->threads = thread_map__new_event(&event->thread_map);
+       if (!script->threads)
+               return -ENOMEM;
+
+       return set_maps(script);
+}
+
+static
+int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
+                         union perf_event *event,
+                         struct perf_session *session __maybe_unused)
+{
+       struct perf_script *script = container_of(tool, struct perf_script, tool);
+
+       if (script->cpus) {
+               pr_warning("Extra cpu map event, ignoring.\n");
+               return 0;
+       }
+
+       script->cpus = cpu_map__new_data(&event->cpu_map.data);
+       if (!script->cpus)
+               return -ENOMEM;
+
+       return set_maps(script);
+}
+
 int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
 {
        bool show_full_info = false;
@@ -1723,6 +1870,11 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
                        .auxtrace_info   = perf_event__process_auxtrace_info,
                        .auxtrace        = perf_event__process_auxtrace,
                        .auxtrace_error  = perf_event__process_auxtrace_error,
+                       .stat            = perf_event__process_stat_event,
+                       .stat_round      = process_stat_round_event,
+                       .stat_config     = process_stat_config_event,
+                       .thread_map      = process_thread_map_event,
+                       .cpu_map         = process_cpu_map_event,
                        .ordered_events  = true,
                        .ordering_requires_timestamps = true,
                },
@@ -1836,7 +1988,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
                scripting_max_stack = itrace_synth_opts.callchain_sz;
 
        /* make sure PERF_EXEC_PATH is set for scripts */
-       perf_set_argv_exec_path(perf_exec_path());
+       set_argv_exec_path(get_argv_exec_path());
 
        if (argc && !script_name && !rec_script_path && !rep_script_path) {
                int live_pipe[2];
@@ -2076,6 +2228,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
        flush_scripting();
 
 out_delete:
+       perf_evlist__free_stats(session->evlist);
        perf_session__delete(session);
 
        if (script_started)
index e77880b5094ded75ac4975d4212f9e35bb9cfa2f..7f568244662b0abecb5a6b402275b63bb17ace9f 100644 (file)
@@ -45,7 +45,7 @@
 #include "builtin.h"
 #include "util/cgroup.h"
 #include "util/util.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/parse-events.h"
 #include "util/pmu.h"
 #include "util/event.h"
@@ -59,6 +59,9 @@
 #include "util/thread.h"
 #include "util/thread_map.h"
 #include "util/counts.h"
+#include "util/session.h"
+#include "util/tool.h"
+#include "asm/bug.h"
 
 #include <stdlib.h>
 #include <sys/prctl.h>
@@ -126,6 +129,21 @@ static bool                        append_file;
 static const char              *output_name;
 static int                     output_fd;
 
+struct perf_stat {
+       bool                     record;
+       struct perf_data_file    file;
+       struct perf_session     *session;
+       u64                      bytes_written;
+       struct perf_tool         tool;
+       bool                     maps_allocated;
+       struct cpu_map          *cpus;
+       struct thread_map       *threads;
+       enum aggr_mode           aggr_mode;
+};
+
+static struct perf_stat                perf_stat;
+#define STAT_RECORD            perf_stat.record
+
 static volatile int done = 0;
 
 static struct perf_stat_config stat_config = {
@@ -161,15 +179,43 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
 
        attr->inherit = !no_inherit;
 
-       if (target__has_cpu(&target))
-               return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
+       /*
+        * Some events get initialized with sample_(period/type) set,
+        * like tracepoints. Clear it up for counting.
+        */
+       attr->sample_period = 0;
+
+       /*
+        * But set sample_type to PERF_SAMPLE_IDENTIFIER, which should be harmless
+        * while avoiding that older tools show confusing messages.
+        *
+        * However for pipe sessions we need to keep it zero,
+        * because script's perf_evsel__check_attr is triggered
+        * by attr->sample_type != 0, and we can't run it on
+        * stat sessions.
+        */
+       if (!(STAT_RECORD && perf_stat.file.is_pipe))
+               attr->sample_type = PERF_SAMPLE_IDENTIFIER;
 
-       if (!target__has_task(&target) && perf_evsel__is_group_leader(evsel)) {
+       /*
+        * Disabling all counters initially, they will be enabled
+        * either manually by us or by kernel via enable_on_exec
+        * set later.
+        */
+       if (perf_evsel__is_group_leader(evsel)) {
                attr->disabled = 1;
-               if (!initial_delay)
+
+               /*
+                * In case of initial_delay we enable tracee
+                * events manually.
+                */
+               if (target__none(&target) && !initial_delay)
                        attr->enable_on_exec = 1;
        }
 
+       if (target__has_cpu(&target))
+               return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
+
        return perf_evsel__open_per_thread(evsel, evsel_list->threads);
 }
 
@@ -185,6 +231,42 @@ static inline int nsec_counter(struct perf_evsel *evsel)
        return 0;
 }
 
+static int process_synthesized_event(struct perf_tool *tool __maybe_unused,
+                                    union perf_event *event,
+                                    struct perf_sample *sample __maybe_unused,
+                                    struct machine *machine __maybe_unused)
+{
+       if (perf_data_file__write(&perf_stat.file, event, event->header.size) < 0) {
+               pr_err("failed to write perf data, error: %m\n");
+               return -1;
+       }
+
+       perf_stat.bytes_written += event->header.size;
+       return 0;
+}
+
+static int write_stat_round_event(u64 tm, u64 type)
+{
+       return perf_event__synthesize_stat_round(NULL, tm, type,
+                                                process_synthesized_event,
+                                                NULL);
+}
+
+#define WRITE_STAT_ROUND_EVENT(time, interval) \
+       write_stat_round_event(time, PERF_STAT_ROUND_TYPE__ ## interval)
+
+#define SID(e, x, y) xyarray__entry(e->sample_id, x, y)
+
+static int
+perf_evsel__write_stat_event(struct perf_evsel *counter, u32 cpu, u32 thread,
+                            struct perf_counts_values *count)
+{
+       struct perf_sample_id *sid = SID(counter, cpu, thread);
+
+       return perf_event__synthesize_stat(NULL, cpu, thread, sid->id, count,
+                                          process_synthesized_event, NULL);
+}
+
 /*
  * Read out the results of a single counter:
  * do not aggregate counts across CPUs in system-wide mode
@@ -208,6 +290,13 @@ static int read_counter(struct perf_evsel *counter)
                        count = perf_counts(counter->counts, cpu, thread);
                        if (perf_evsel__read(counter, cpu, thread, count))
                                return -1;
+
+                       if (STAT_RECORD) {
+                               if (perf_evsel__write_stat_event(counter, cpu, thread, count)) {
+                                       pr_err("failed to write stat event\n");
+                                       return -1;
+                               }
+                       }
                }
        }
 
@@ -241,21 +330,26 @@ static void process_interval(void)
        clock_gettime(CLOCK_MONOTONIC, &ts);
        diff_timespec(&rs, &ts, &ref_time);
 
+       if (STAT_RECORD) {
+               if (WRITE_STAT_ROUND_EVENT(rs.tv_sec * NSECS_PER_SEC + rs.tv_nsec, INTERVAL))
+                       pr_err("failed to write stat round event\n");
+       }
+
        print_counters(&rs, 0, NULL);
 }
 
-static void handle_initial_delay(void)
+static void enable_counters(void)
 {
-       struct perf_evsel *counter;
-
-       if (initial_delay) {
-               const int ncpus = cpu_map__nr(evsel_list->cpus),
-                       nthreads = thread_map__nr(evsel_list->threads);
-
+       if (initial_delay)
                usleep(initial_delay * 1000);
-               evlist__for_each(evsel_list, counter)
-                       perf_evsel__enable(counter, ncpus, nthreads);
-       }
+
+       /*
+        * We need to enable counters only if:
+        * - we don't have tracee (attaching to task or cpu)
+        * - we have initial delay configured
+        */
+       if (!target__none(&target) || initial_delay)
+               perf_evlist__enable(evsel_list);
 }
 
 static volatile int workload_exec_errno;
@@ -271,6 +365,135 @@ static void workload_exec_failed_signal(int signo __maybe_unused, siginfo_t *inf
        workload_exec_errno = info->si_value.sival_int;
 }
 
+static bool has_unit(struct perf_evsel *counter)
+{
+       return counter->unit && *counter->unit;
+}
+
+static bool has_scale(struct perf_evsel *counter)
+{
+       return counter->scale != 1;
+}
+
+static int perf_stat_synthesize_config(bool is_pipe)
+{
+       struct perf_evsel *counter;
+       int err;
+
+       if (is_pipe) {
+               err = perf_event__synthesize_attrs(NULL, perf_stat.session,
+                                                  process_synthesized_event);
+               if (err < 0) {
+                       pr_err("Couldn't synthesize attrs.\n");
+                       return err;
+               }
+       }
+
+       /*
+        * Synthesize other events stuff not carried within
+        * attr event - unit, scale, name
+        */
+       evlist__for_each(evsel_list, counter) {
+               if (!counter->supported)
+                       continue;
+
+               /*
+                * Synthesize unit and scale only if it's defined.
+                */
+               if (has_unit(counter)) {
+                       err = perf_event__synthesize_event_update_unit(NULL, counter, process_synthesized_event);
+                       if (err < 0) {
+                               pr_err("Couldn't synthesize evsel unit.\n");
+                               return err;
+                       }
+               }
+
+               if (has_scale(counter)) {
+                       err = perf_event__synthesize_event_update_scale(NULL, counter, process_synthesized_event);
+                       if (err < 0) {
+                               pr_err("Couldn't synthesize evsel scale.\n");
+                               return err;
+                       }
+               }
+
+               if (counter->own_cpus) {
+                       err = perf_event__synthesize_event_update_cpus(NULL, counter, process_synthesized_event);
+                       if (err < 0) {
+                               pr_err("Couldn't synthesize evsel scale.\n");
+                               return err;
+                       }
+               }
+
+               /*
+                * Name is needed only for pipe output,
+                * perf.data carries event names.
+                */
+               if (is_pipe) {
+                       err = perf_event__synthesize_event_update_name(NULL, counter, process_synthesized_event);
+                       if (err < 0) {
+                               pr_err("Couldn't synthesize evsel name.\n");
+                               return err;
+                       }
+               }
+       }
+
+       err = perf_event__synthesize_thread_map2(NULL, evsel_list->threads,
+                                               process_synthesized_event,
+                                               NULL);
+       if (err < 0) {
+               pr_err("Couldn't synthesize thread map.\n");
+               return err;
+       }
+
+       err = perf_event__synthesize_cpu_map(NULL, evsel_list->cpus,
+                                            process_synthesized_event, NULL);
+       if (err < 0) {
+               pr_err("Couldn't synthesize thread map.\n");
+               return err;
+       }
+
+       err = perf_event__synthesize_stat_config(NULL, &stat_config,
+                                                process_synthesized_event, NULL);
+       if (err < 0) {
+               pr_err("Couldn't synthesize config.\n");
+               return err;
+       }
+
+       return 0;
+}
+
+#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
+
+static int __store_counter_ids(struct perf_evsel *counter,
+                              struct cpu_map *cpus,
+                              struct thread_map *threads)
+{
+       int cpu, thread;
+
+       for (cpu = 0; cpu < cpus->nr; cpu++) {
+               for (thread = 0; thread < threads->nr; thread++) {
+                       int fd = FD(counter, cpu, thread);
+
+                       if (perf_evlist__id_add_fd(evsel_list, counter,
+                                                  cpu, thread, fd) < 0)
+                               return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int store_counter_ids(struct perf_evsel *counter)
+{
+       struct cpu_map *cpus = counter->cpus;
+       struct thread_map *threads = counter->threads;
+
+       if (perf_evsel__alloc_id(counter, cpus->nr, threads->nr))
+               return -ENOMEM;
+
+       return __store_counter_ids(counter, cpus, threads);
+}
+
 static int __run_perf_stat(int argc, const char **argv)
 {
        int interval = stat_config.interval;
@@ -281,6 +504,7 @@ static int __run_perf_stat(int argc, const char **argv)
        size_t l;
        int status = 0;
        const bool forks = (argc > 0);
+       bool is_pipe = STAT_RECORD ? perf_stat.file.is_pipe : false;
 
        if (interval) {
                ts.tv_sec  = interval / 1000;
@@ -291,7 +515,7 @@ static int __run_perf_stat(int argc, const char **argv)
        }
 
        if (forks) {
-               if (perf_evlist__prepare_workload(evsel_list, &target, argv, false,
+               if (perf_evlist__prepare_workload(evsel_list, &target, argv, is_pipe,
                                                  workload_exec_failed_signal) < 0) {
                        perror("failed to prepare workload");
                        return -1;
@@ -335,6 +559,9 @@ static int __run_perf_stat(int argc, const char **argv)
                l = strlen(counter->unit);
                if (l > unit_width)
                        unit_width = l;
+
+               if (STAT_RECORD && store_counter_ids(counter))
+                       return -1;
        }
 
        if (perf_evlist__apply_filters(evsel_list, &counter)) {
@@ -344,6 +571,24 @@ static int __run_perf_stat(int argc, const char **argv)
                return -1;
        }
 
+       if (STAT_RECORD) {
+               int err, fd = perf_data_file__fd(&perf_stat.file);
+
+               if (is_pipe) {
+                       err = perf_header__write_pipe(perf_data_file__fd(&perf_stat.file));
+               } else {
+                       err = perf_session__write_header(perf_stat.session, evsel_list,
+                                                        fd, false);
+               }
+
+               if (err < 0)
+                       return err;
+
+               err = perf_stat_synthesize_config(is_pipe);
+               if (err < 0)
+                       return err;
+       }
+
        /*
         * Enable counters and exec the command:
         */
@@ -352,7 +597,7 @@ static int __run_perf_stat(int argc, const char **argv)
 
        if (forks) {
                perf_evlist__start_workload(evsel_list);
-               handle_initial_delay();
+               enable_counters();
 
                if (interval) {
                        while (!waitpid(child_pid, &status, WNOHANG)) {
@@ -371,7 +616,7 @@ static int __run_perf_stat(int argc, const char **argv)
                if (WIFSIGNALED(status))
                        psignal(WTERMSIG(status), argv[0]);
        } else {
-               handle_initial_delay();
+               enable_counters();
                while (!done) {
                        nanosleep(&ts, NULL);
                        if (interval)
@@ -810,8 +1055,8 @@ static void print_header(int argc, const char **argv)
                else if (target.cpu_list)
                        fprintf(output, "\'CPU(s) %s", target.cpu_list);
                else if (!target__has_task(&target)) {
-                       fprintf(output, "\'%s", argv[0]);
-                       for (i = 1; i < argc; i++)
+                       fprintf(output, "\'%s", argv ? argv[0] : "pipe");
+                       for (i = 1; argv && (i < argc); i++)
                                fprintf(output, " %s", argv[i]);
                } else if (target.pid)
                        fprintf(output, "process id \'%s", target.pid);
@@ -847,6 +1092,10 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
        struct perf_evsel *counter;
        char buf[64], *prefix = NULL;
 
+       /* Do not print anything if we record to the pipe. */
+       if (STAT_RECORD && perf_stat.file.is_pipe)
+               return;
+
        if (interval)
                print_interval(prefix = buf, ts);
        else
@@ -1077,6 +1326,109 @@ static int perf_stat_init_aggr_mode(void)
        return cpus_aggr_map ? 0 : -ENOMEM;
 }
 
+static void perf_stat__exit_aggr_mode(void)
+{
+       cpu_map__put(aggr_map);
+       cpu_map__put(cpus_aggr_map);
+       aggr_map = NULL;
+       cpus_aggr_map = NULL;
+}
+
+static inline int perf_env__get_cpu(struct perf_env *env, struct cpu_map *map, int idx)
+{
+       int cpu;
+
+       if (idx > map->nr)
+               return -1;
+
+       cpu = map->map[idx];
+
+       if (cpu >= env->nr_cpus_online)
+               return -1;
+
+       return cpu;
+}
+
+static int perf_env__get_socket(struct cpu_map *map, int idx, void *data)
+{
+       struct perf_env *env = data;
+       int cpu = perf_env__get_cpu(env, map, idx);
+
+       return cpu == -1 ? -1 : env->cpu[cpu].socket_id;
+}
+
+static int perf_env__get_core(struct cpu_map *map, int idx, void *data)
+{
+       struct perf_env *env = data;
+       int core = -1, cpu = perf_env__get_cpu(env, map, idx);
+
+       if (cpu != -1) {
+               int socket_id = env->cpu[cpu].socket_id;
+
+               /*
+                * Encode socket in upper 16 bits
+                * core_id is relative to socket, and
+                * we need a global id. So we combine
+                * socket + core id.
+                */
+               core = (socket_id << 16) | (env->cpu[cpu].core_id & 0xffff);
+       }
+
+       return core;
+}
+
+static int perf_env__build_socket_map(struct perf_env *env, struct cpu_map *cpus,
+                                     struct cpu_map **sockp)
+{
+       return cpu_map__build_map(cpus, sockp, perf_env__get_socket, env);
+}
+
+static int perf_env__build_core_map(struct perf_env *env, struct cpu_map *cpus,
+                                   struct cpu_map **corep)
+{
+       return cpu_map__build_map(cpus, corep, perf_env__get_core, env);
+}
+
+static int perf_stat__get_socket_file(struct cpu_map *map, int idx)
+{
+       return perf_env__get_socket(map, idx, &perf_stat.session->header.env);
+}
+
+static int perf_stat__get_core_file(struct cpu_map *map, int idx)
+{
+       return perf_env__get_core(map, idx, &perf_stat.session->header.env);
+}
+
+static int perf_stat_init_aggr_mode_file(struct perf_stat *st)
+{
+       struct perf_env *env = &st->session->header.env;
+
+       switch (stat_config.aggr_mode) {
+       case AGGR_SOCKET:
+               if (perf_env__build_socket_map(env, evsel_list->cpus, &aggr_map)) {
+                       perror("cannot build socket map");
+                       return -1;
+               }
+               aggr_get_id = perf_stat__get_socket_file;
+               break;
+       case AGGR_CORE:
+               if (perf_env__build_core_map(env, evsel_list->cpus, &aggr_map)) {
+                       perror("cannot build core map");
+                       return -1;
+               }
+               aggr_get_id = perf_stat__get_core_file;
+               break;
+       case AGGR_NONE:
+       case AGGR_GLOBAL:
+       case AGGR_THREAD:
+       case AGGR_UNSET:
+       default:
+               break;
+       }
+
+       return 0;
+}
+
 /*
  * Add default attributes, if there were no attributes specified or
  * if -d/--detailed, -d -d or -d -d -d is used:
@@ -1236,6 +1588,225 @@ static int add_default_attributes(void)
        return perf_evlist__add_default_attrs(evsel_list, very_very_detailed_attrs);
 }
 
+static const char * const recort_usage[] = {
+       "perf stat record [<options>]",
+       NULL,
+};
+
+static void init_features(struct perf_session *session)
+{
+       int feat;
+
+       for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
+               perf_header__set_feat(&session->header, feat);
+
+       perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
+       perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
+       perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
+       perf_header__clear_feat(&session->header, HEADER_AUXTRACE);
+}
+
+static int __cmd_record(int argc, const char **argv)
+{
+       struct perf_session *session;
+       struct perf_data_file *file = &perf_stat.file;
+
+       argc = parse_options(argc, argv, stat_options, record_usage,
+                            PARSE_OPT_STOP_AT_NON_OPTION);
+
+       if (output_name)
+               file->path = output_name;
+
+       if (run_count != 1 || forever) {
+               pr_err("Cannot use -r option with perf stat record.\n");
+               return -1;
+       }
+
+       session = perf_session__new(file, false, NULL);
+       if (session == NULL) {
+               pr_err("Perf session creation failed.\n");
+               return -1;
+       }
+
+       init_features(session);
+
+       session->evlist   = evsel_list;
+       perf_stat.session = session;
+       perf_stat.record  = true;
+       return argc;
+}
+
+static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
+                                   union perf_event *event,
+                                   struct perf_session *session)
+{
+       struct stat_round_event *round = &event->stat_round;
+       struct perf_evsel *counter;
+       struct timespec tsh, *ts = NULL;
+       const char **argv = session->header.env.cmdline_argv;
+       int argc = session->header.env.nr_cmdline;
+
+       evlist__for_each(evsel_list, counter)
+               perf_stat_process_counter(&stat_config, counter);
+
+       if (round->type == PERF_STAT_ROUND_TYPE__FINAL)
+               update_stats(&walltime_nsecs_stats, round->time);
+
+       if (stat_config.interval && round->time) {
+               tsh.tv_sec  = round->time / NSECS_PER_SEC;
+               tsh.tv_nsec = round->time % NSECS_PER_SEC;
+               ts = &tsh;
+       }
+
+       print_counters(ts, argc, argv);
+       return 0;
+}
+
+static
+int process_stat_config_event(struct perf_tool *tool __maybe_unused,
+                             union perf_event *event,
+                             struct perf_session *session __maybe_unused)
+{
+       struct perf_stat *st = container_of(tool, struct perf_stat, tool);
+
+       perf_event__read_stat_config(&stat_config, &event->stat_config);
+
+       if (cpu_map__empty(st->cpus)) {
+               if (st->aggr_mode != AGGR_UNSET)
+                       pr_warning("warning: processing task data, aggregation mode not set\n");
+               return 0;
+       }
+
+       if (st->aggr_mode != AGGR_UNSET)
+               stat_config.aggr_mode = st->aggr_mode;
+
+       if (perf_stat.file.is_pipe)
+               perf_stat_init_aggr_mode();
+       else
+               perf_stat_init_aggr_mode_file(st);
+
+       return 0;
+}
+
+static int set_maps(struct perf_stat *st)
+{
+       if (!st->cpus || !st->threads)
+               return 0;
+
+       if (WARN_ONCE(st->maps_allocated, "stats double allocation\n"))
+               return -EINVAL;
+
+       perf_evlist__set_maps(evsel_list, st->cpus, st->threads);
+
+       if (perf_evlist__alloc_stats(evsel_list, true))
+               return -ENOMEM;
+
+       st->maps_allocated = true;
+       return 0;
+}
+
+static
+int process_thread_map_event(struct perf_tool *tool __maybe_unused,
+                            union perf_event *event,
+                            struct perf_session *session __maybe_unused)
+{
+       struct perf_stat *st = container_of(tool, struct perf_stat, tool);
+
+       if (st->threads) {
+               pr_warning("Extra thread map event, ignoring.\n");
+               return 0;
+       }
+
+       st->threads = thread_map__new_event(&event->thread_map);
+       if (!st->threads)
+               return -ENOMEM;
+
+       return set_maps(st);
+}
+
+static
+int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
+                         union perf_event *event,
+                         struct perf_session *session __maybe_unused)
+{
+       struct perf_stat *st = container_of(tool, struct perf_stat, tool);
+       struct cpu_map *cpus;
+
+       if (st->cpus) {
+               pr_warning("Extra cpu map event, ignoring.\n");
+               return 0;
+       }
+
+       cpus = cpu_map__new_data(&event->cpu_map.data);
+       if (!cpus)
+               return -ENOMEM;
+
+       st->cpus = cpus;
+       return set_maps(st);
+}
+
+static const char * const report_usage[] = {
+       "perf stat report [<options>]",
+       NULL,
+};
+
+static struct perf_stat perf_stat = {
+       .tool = {
+               .attr           = perf_event__process_attr,
+               .event_update   = perf_event__process_event_update,
+               .thread_map     = process_thread_map_event,
+               .cpu_map        = process_cpu_map_event,
+               .stat_config    = process_stat_config_event,
+               .stat           = perf_event__process_stat_event,
+               .stat_round     = process_stat_round_event,
+       },
+       .aggr_mode = AGGR_UNSET,
+};
+
+static int __cmd_report(int argc, const char **argv)
+{
+       struct perf_session *session;
+       const struct option options[] = {
+       OPT_STRING('i', "input", &input_name, "file", "input file name"),
+       OPT_SET_UINT(0, "per-socket", &perf_stat.aggr_mode,
+                    "aggregate counts per processor socket", AGGR_SOCKET),
+       OPT_SET_UINT(0, "per-core", &perf_stat.aggr_mode,
+                    "aggregate counts per physical processor core", AGGR_CORE),
+       OPT_SET_UINT('A', "no-aggr", &perf_stat.aggr_mode,
+                    "disable CPU count aggregation", AGGR_NONE),
+       OPT_END()
+       };
+       struct stat st;
+       int ret;
+
+       argc = parse_options(argc, argv, options, report_usage, 0);
+
+       if (!input_name || !strlen(input_name)) {
+               if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
+                       input_name = "-";
+               else
+                       input_name = "perf.data";
+       }
+
+       perf_stat.file.path = input_name;
+       perf_stat.file.mode = PERF_DATA_MODE_READ;
+
+       session = perf_session__new(&perf_stat.file, false, &perf_stat.tool);
+       if (session == NULL)
+               return -1;
+
+       perf_stat.session  = session;
+       stat_config.output = stderr;
+       evsel_list         = session->evlist;
+
+       ret = perf_session__process_events(session);
+       if (ret)
+               return ret;
+
+       perf_session__delete(session);
+       return 0;
+}
+
 int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
 {
        const char * const stat_usage[] = {
@@ -1246,6 +1817,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
        const char *mode;
        FILE *output = stderr;
        unsigned int interval;
+       const char * const stat_subcommands[] = { "record", "report" };
 
        setlocale(LC_ALL, "");
 
@@ -1253,12 +1825,30 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
        if (evsel_list == NULL)
                return -ENOMEM;
 
-       argc = parse_options(argc, argv, stat_options, stat_usage,
-               PARSE_OPT_STOP_AT_NON_OPTION);
+       argc = parse_options_subcommand(argc, argv, stat_options, stat_subcommands,
+                                       (const char **) stat_usage,
+                                       PARSE_OPT_STOP_AT_NON_OPTION);
+
+       if (csv_sep) {
+               csv_output = true;
+               if (!strcmp(csv_sep, "\\t"))
+                       csv_sep = "\t";
+       } else
+               csv_sep = DEFAULT_SEPARATOR;
+
+       if (argc && !strncmp(argv[0], "rec", 3)) {
+               argc = __cmd_record(argc, argv);
+               if (argc < 0)
+                       return -1;
+       } else if (argc && !strncmp(argv[0], "rep", 3))
+               return __cmd_report(argc, argv);
 
        interval = stat_config.interval;
 
-       if (output_name && strcmp(output_name, "-"))
+       /*
+        * For record command the -o is already taken care of.
+        */
+       if (!STAT_RECORD && output_name && strcmp(output_name, "-"))
                output = NULL;
 
        if (output_name && output_fd) {
@@ -1296,13 +1886,6 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
 
        stat_config.output = output;
 
-       if (csv_sep) {
-               csv_output = true;
-               if (!strcmp(csv_sep, "\\t"))
-                       csv_sep = "\t";
-       } else
-               csv_sep = DEFAULT_SEPARATOR;
-
        /*
         * let the spreadsheet do the pretty-printing
         */
@@ -1425,6 +2008,42 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
        if (!forever && status != -1 && !interval)
                print_counters(NULL, argc, argv);
 
+       if (STAT_RECORD) {
+               /*
+                * We synthesize the kernel mmap record just so that older tools
+                * don't emit warnings about not being able to resolve symbols
+                * due to /proc/sys/kernel/kptr_restrict settings and instear provide
+                * a saner message about no samples being in the perf.data file.
+                *
+                * This also serves to suppress a warning about f_header.data.size == 0
+                * in header.c at the moment 'perf stat record' gets introduced, which
+                * is not really needed once we start adding the stat specific PERF_RECORD_
+                * records, but the need to suppress the kptr_restrict messages in older
+                * tools remain  -acme
+                */
+               int fd = perf_data_file__fd(&perf_stat.file);
+               int err = perf_event__synthesize_kernel_mmap((void *)&perf_stat,
+                                                            process_synthesized_event,
+                                                            &perf_stat.session->machines.host);
+               if (err) {
+                       pr_warning("Couldn't synthesize the kernel mmap record, harmless, "
+                                  "older tools may produce warnings about this file\n.");
+               }
+
+               if (!interval) {
+                       if (WRITE_STAT_ROUND_EVENT(walltime_nsecs_stats.max, FINAL))
+                               pr_err("failed to write stat round event\n");
+               }
+
+               if (!perf_stat.file.is_pipe) {
+                       perf_stat.session->header.data_size += perf_stat.bytes_written;
+                       perf_session__write_header(perf_stat.session, evsel_list, fd, true);
+               }
+
+               perf_session__delete(perf_stat.session);
+       }
+
+       perf_stat__exit_aggr_mode();
        perf_evlist__free_stats(evsel_list);
 out:
        perf_evlist__delete(evsel_list);
index 30e59620179daef63c272c3119f884a8caefd12f..bd7a7757176ff0461426903411e20339edc57416 100644 (file)
@@ -30,7 +30,7 @@
 
 #include "perf.h"
 #include "util/header.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/parse-events.h"
 #include "util/event.h"
 #include "util/session.h"
index 7e2e72e6d9d16323c3c448986372fa13234d368a..bf01cbb0ef2369f2fc904809b86b70a823bdb604 100644 (file)
@@ -34,7 +34,7 @@
 #include "util/top.h"
 #include "util/util.h"
 #include <linux/rbtree.h>
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/parse-events.h"
 #include "util/cpumap.h"
 #include "util/xyarray.h"
@@ -175,42 +175,40 @@ static void perf_top__record_precise_ip(struct perf_top *top,
                                        int counter, u64 ip)
 {
        struct annotation *notes;
-       struct symbol *sym;
+       struct symbol *sym = he->ms.sym;
        int err = 0;
 
-       if (he == NULL || he->ms.sym == NULL ||
-           ((top->sym_filter_entry == NULL ||
-             top->sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1))
+       if (sym == NULL || (use_browser == 0 &&
+                           (top->sym_filter_entry == NULL ||
+                            top->sym_filter_entry->ms.sym != sym)))
                return;
 
-       sym = he->ms.sym;
        notes = symbol__annotation(sym);
 
        if (pthread_mutex_trylock(&notes->lock))
                return;
 
-       ip = he->ms.map->map_ip(he->ms.map, ip);
-
-       if (ui__has_annotation())
-               err = hist_entry__inc_addr_samples(he, counter, ip);
+       err = hist_entry__inc_addr_samples(he, counter, ip);
 
        pthread_mutex_unlock(&notes->lock);
 
-       /*
-        * This function is now called with he->hists->lock held.
-        * Release it before going to sleep.
-        */
-       pthread_mutex_unlock(&he->hists->lock);
+       if (unlikely(err)) {
+               /*
+                * This function is now called with he->hists->lock held.
+                * Release it before going to sleep.
+                */
+               pthread_mutex_unlock(&he->hists->lock);
+
+               if (err == -ERANGE && !he->ms.map->erange_warned)
+                       ui__warn_map_erange(he->ms.map, sym, ip);
+               else if (err == -ENOMEM) {
+                       pr_err("Not enough memory for annotating '%s' symbol!\n",
+                              sym->name);
+                       sleep(1);
+               }
 
-       if (err == -ERANGE && !he->ms.map->erange_warned)
-               ui__warn_map_erange(he->ms.map, sym, ip);
-       else if (err == -ENOMEM) {
-               pr_err("Not enough memory for annotating '%s' symbol!\n",
-                      sym->name);
-               sleep(1);
+               pthread_mutex_lock(&he->hists->lock);
        }
-
-       pthread_mutex_lock(&he->hists->lock);
 }
 
 static void perf_top__show_details(struct perf_top *top)
@@ -687,14 +685,8 @@ static int hist_iter__top_callback(struct hist_entry_iter *iter,
        struct hist_entry *he = iter->he;
        struct perf_evsel *evsel = iter->evsel;
 
-       if (sort__has_sym && single) {
-               u64 ip = al->addr;
-
-               if (al->map)
-                       ip = al->map->unmap_ip(al->map, ip);
-
-               perf_top__record_precise_ip(top, he, evsel->idx, ip);
-       }
+       if (sort__has_sym && single)
+               perf_top__record_precise_ip(top, he, evsel->idx, al->addr);
 
        hist__account_cycles(iter->sample->branch_stack, al, iter->sample,
                     !(top->record_opts.branch_stack & PERF_SAMPLE_BRANCH_ANY));
@@ -964,7 +956,7 @@ static int __cmd_top(struct perf_top *top)
        if (ret)
                goto out_delete;
 
-       if (perf_session__register_idle_thread(top->session) == NULL)
+       if (perf_session__register_idle_thread(top->session) < 0)
                goto out_delete;
 
        machine__synthesize_threads(&top->session->machines.host, &opts->target,
@@ -1218,6 +1210,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
        OPT_CALLBACK('j', "branch-filter", &opts->branch_stack,
                     "branch filter mask", "branch stack filter modes",
                     parse_branch_stack),
+       OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace,
+                   "Show raw trace event output (do not use print fmt or plugins)"),
        OPT_END()
        };
        const char * const top_usage[] = {
@@ -1239,11 +1233,17 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
        if (argc)
                usage_with_options(top_usage, options);
 
+       if (!top.evlist->nr_entries &&
+           perf_evlist__add_default(top.evlist) < 0) {
+               pr_err("Not enough memory for event selector list\n");
+               goto out_delete_evlist;
+       }
+
        sort__mode = SORT_MODE__TOP;
        /* display thread wants entries to be collapsed in a different tree */
        sort__need_collapse = 1;
 
-       if (setup_sorting() < 0) {
+       if (setup_sorting(top.evlist) < 0) {
                if (sort_order)
                        parse_options_usage(top_usage, options, "s", 1);
                if (field_order)
@@ -1279,12 +1279,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
        if (target__none(target))
                target->system_wide = true;
 
-       if (perf_evlist__create_maps(top.evlist, target) < 0)
-               usage_with_options(top_usage, options);
-
-       if (!top.evlist->nr_entries &&
-           perf_evlist__add_default(top.evlist) < 0) {
-               ui__error("Not enough memory for event selector list\n");
+       if (perf_evlist__create_maps(top.evlist, target) < 0) {
+               ui__error("Couldn't create thread/CPU maps: %s\n",
+                         errno == ENOENT ? "No such process" : strerror_r(errno, errbuf, sizeof(errbuf)));
                goto out_delete_evlist;
        }
 
index c783d8fd3a80fb4ae29ab2cb81d3a7d8b54a0123..20916dd77aac24847bffbaa5d1c0fb56580d6e39 100644 (file)
 #include "util/color.h"
 #include "util/debug.h"
 #include "util/evlist.h"
-#include "util/exec_cmd.h"
+#include <subcmd/exec-cmd.h>
 #include "util/machine.h"
 #include "util/session.h"
 #include "util/thread.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/strlist.h"
 #include "util/intlist.h"
 #include "util/thread_map.h"
diff --git a/tools/perf/builtin-version.c b/tools/perf/builtin-version.c
new file mode 100644 (file)
index 0000000..9b10cda
--- /dev/null
@@ -0,0 +1,10 @@
+#include "util/util.h"
+#include "builtin.h"
+#include "perf.h"
+
+int cmd_version(int argc __maybe_unused, const char **argv __maybe_unused,
+               const char *prefix __maybe_unused)
+{
+       printf("perf version %s\n", perf_version_string);
+       return 0;
+}
index 3688ad29085fa55739cceabad42e34f1413e879f..3f871b54e2619b45c449b2887f15a5be388b81c9 100644 (file)
@@ -17,6 +17,7 @@ extern int cmd_annotate(int argc, const char **argv, const char *prefix);
 extern int cmd_bench(int argc, const char **argv, const char *prefix);
 extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix);
 extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);
+extern int cmd_config(int argc, const char **argv, const char *prefix);
 extern int cmd_diff(int argc, const char **argv, const char *prefix);
 extern int cmd_evlist(int argc, const char **argv, const char *prefix);
 extern int cmd_help(int argc, const char **argv, const char *prefix);
index 00fcaf8a5b8d60535d00981ff67a47094ece0604..ab5cbaa170d0d882510e58d1d4e57e44c8843b3f 100644 (file)
@@ -9,6 +9,7 @@ perf-buildid-cache              mainporcelain common
 perf-buildid-list              mainporcelain common
 perf-data                      mainporcelain common
 perf-diff                      mainporcelain common
+perf-config                    mainporcelain common
 perf-evlist                    mainporcelain common
 perf-inject                    mainporcelain common
 perf-kmem                      mainporcelain common
@@ -25,4 +26,4 @@ perf-stat                     mainporcelain common
 perf-test                      mainporcelain common
 perf-timechart                 mainporcelain common
 perf-top                       mainporcelain common
-perf-trace                     mainporcelain common
+perf-trace                     mainporcelain audit
index de89ec57436171ef74e5aa48135db8c2e9b4c0a0..254d06e39bea8ceb5199a1237dc6b006e513a1a4 100644 (file)
@@ -135,8 +135,6 @@ endif
 
 ifeq ($(DEBUG),0)
   CFLAGS += -O6
-else
-  CFLAGS += $(call cc-option,-Og,-O0)
 endif
 
 ifdef PARSER_DEBUG
@@ -318,6 +316,18 @@ ifndef NO_LIBELF
       CFLAGS += -DHAVE_LIBBPF_SUPPORT
       $(call detected,CONFIG_LIBBPF)
     endif
+
+    ifndef NO_DWARF
+      ifdef PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
+        CFLAGS += -DHAVE_BPF_PROLOGUE
+        $(call detected,CONFIG_BPF_PROLOGUE)
+      else
+        msg := $(warning BPF prologue is not supported by architecture $(ARCH), missing regs_query_register_offset());
+      endif
+    else
+      msg := $(warning DWARF support is off, BPF prologue is disabled);
+    endif
+
   endif # NO_LIBBPF
 endif # NO_LIBELF
 
@@ -681,6 +691,7 @@ sharedir = $(prefix)/share
 template_dir = share/perf-core/templates
 STRACE_GROUPS_DIR = share/perf-core/strace/groups
 htmldir = share/doc/perf-doc
+tipdir = share/doc/perf-tip
 ifeq ($(prefix),/usr)
 sysconfdir = /etc
 ETC_PERFCONFIG = $(sysconfdir)/perfconfig
@@ -707,6 +718,7 @@ infodir_SQ = $(subst ','\'',$(infodir))
 perfexecdir_SQ = $(subst ','\'',$(perfexecdir))
 template_dir_SQ = $(subst ','\'',$(template_dir))
 htmldir_SQ = $(subst ','\'',$(htmldir))
+tipdir_SQ = $(subst ','\'',$(tipdir))
 prefix_SQ = $(subst ','\'',$(prefix))
 sysconfdir_SQ = $(subst ','\'',$(sysconfdir))
 libdir_SQ = $(subst ','\'',$(libdir))
@@ -714,12 +726,15 @@ libdir_SQ = $(subst ','\'',$(libdir))
 ifneq ($(filter /%,$(firstword $(perfexecdir))),)
 perfexec_instdir = $(perfexecdir)
 STRACE_GROUPS_INSTDIR = $(STRACE_GROUPS_DIR)
+tip_instdir = $(tipdir)
 else
 perfexec_instdir = $(prefix)/$(perfexecdir)
 STRACE_GROUPS_INSTDIR = $(prefix)/$(STRACE_GROUPS_DIR)
+tip_instdir = $(prefix)/$(tipdir)
 endif
 perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
 STRACE_GROUPS_INSTDIR_SQ = $(subst ','\'',$(STRACE_GROUPS_INSTDIR))
+tip_instdir_SQ = $(subst ','\'',$(tip_instdir))
 
 # If we install to $(HOME) we keep the traceevent default:
 # $(HOME)/.traceevent/plugins
@@ -741,6 +756,10 @@ ifeq ($(VF),1)
   $(call print_var,sysconfdir)
   $(call print_var,LIBUNWIND_DIR)
   $(call print_var,LIBDW_DIR)
+
+  ifeq ($(dwarf-post-unwind),1)
+    $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text))
+  endif
   $(info )
 endif
 
@@ -756,6 +775,7 @@ $(call detected_var,ETC_PERFCONFIG_SQ)
 $(call detected_var,STRACE_GROUPS_DIR_SQ)
 $(call detected_var,prefix_SQ)
 $(call detected_var,perfexecdir_SQ)
+$(call detected_var,tipdir_SQ)
 $(call detected_var,LIBDIR)
 $(call detected_var,GTK_CFLAGS)
 $(call detected_var,PERL_EMBED_CCOPTS)
index 0ebef09c0842f89e16df8404931f884d7796c1ca..c16ce833079c0a307642f2ae0e75f9c0d577c4d8 100644 (file)
@@ -177,22 +177,3 @@ $(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2)))
 endef
 _ge_attempt = $(if $(get-executable),$(get-executable),$(call _gea_err,$(2)))
 _gea_err  = $(if $(1),$(error Please set '$(1)' appropriately))
-
-# try-run
-# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
-# Exit code chooses option. "$$TMP" is can be used as temporary file and
-# is automatically cleaned up.
-try-run = $(shell set -e;              \
-       TMP="$(TMPOUT).$$$$.tmp";       \
-       TMPO="$(TMPOUT).$$$$.o";        \
-       if ($(1)) >/dev/null 2>&1;      \
-       then echo "$(2)";               \
-       else echo "$(3)";               \
-       fi;                             \
-       rm -f "$$TMP" "$$TMPO")
-
-# cc-option
-# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
-
-cc-option = $(call try-run,\
-       $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2))
index 3d4c7c09adeae9afeeccf69161882b2fc65f9e41..a929618b8eb616f90c9bb8e26bad5416a0fdbc19 100644 (file)
@@ -9,16 +9,18 @@
 #include "builtin.h"
 
 #include "util/env.h"
-#include "util/exec_cmd.h"
+#include <subcmd/exec-cmd.h>
 #include "util/cache.h"
 #include "util/quote.h"
-#include "util/run-command.h"
+#include <subcmd/run-command.h>
 #include "util/parse-events.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/bpf-loader.h"
 #include "util/debug.h"
 #include <api/fs/tracing_path.h>
 #include <pthread.h>
+#include <stdlib.h>
+#include <time.h>
 
 const char perf_usage_string[] =
        "perf [--version] [--help] [OPTIONS] COMMAND [ARGS]";
@@ -39,6 +41,7 @@ struct cmd_struct {
 static struct cmd_struct commands[] = {
        { "buildid-cache", cmd_buildid_cache, 0 },
        { "buildid-list", cmd_buildid_list, 0 },
+       { "config",     cmd_config,     0 },
        { "diff",       cmd_diff,       0 },
        { "evlist",     cmd_evlist,     0 },
        { "help",       cmd_help,       0 },
@@ -118,7 +121,7 @@ static void commit_pager_choice(void)
 {
        switch (use_pager) {
        case 0:
-               setenv("PERF_PAGER", "cat", 1);
+               setenv(PERF_PAGER_ENVIRONMENT, "cat", 1);
                break;
        case 1:
                /* setup_pager(); */
@@ -182,9 +185,9 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
                if (!prefixcmp(cmd, CMD_EXEC_PATH)) {
                        cmd += strlen(CMD_EXEC_PATH);
                        if (*cmd == '=')
-                               perf_set_argv_exec_path(cmd + 1);
+                               set_argv_exec_path(cmd + 1);
                        else {
-                               puts(perf_exec_path());
+                               puts(get_argv_exec_path());
                                exit(0);
                        }
                } else if (!strcmp(cmd, "--html-path")) {
@@ -383,6 +386,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
                use_pager = 1;
        commit_pager_choice();
 
+       perf_env__set_cmdline(&perf_env, argc, argv);
        status = p->fn(argc, argv, prefix);
        exit_browser(status);
        perf_env__exit(&perf_env);
@@ -528,14 +532,20 @@ int main(int argc, const char **argv)
        const char *cmd;
        char sbuf[STRERR_BUFSIZE];
 
+       /* libsubcmd init */
+       exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT);
+       pager_init(PERF_PAGER_ENVIRONMENT);
+
        /* The page_size is placed in util object. */
        page_size = sysconf(_SC_PAGE_SIZE);
        cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
 
-       cmd = perf_extract_argv0_path(argv[0]);
+       cmd = extract_argv0_path(argv[0]);
        if (!cmd)
                cmd = "perf-help";
 
+       srandom(time(NULL));
+
        /* get debugfs/tracefs mount point from /proc/mounts */
        tracing_path_mount();
 
diff --git a/tools/perf/scripts/python/stat-cpi.py b/tools/perf/scripts/python/stat-cpi.py
new file mode 100644 (file)
index 0000000..8b60f34
--- /dev/null
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+
+data    = {}
+times   = []
+threads = []
+cpus    = []
+
+def get_key(time, event, cpu, thread):
+    return "%d-%s-%d-%d" % (time, event, cpu, thread)
+
+def store_key(time, cpu, thread):
+    if (time not in times):
+        times.append(time)
+
+    if (cpu not in cpus):
+        cpus.append(cpu)
+
+    if (thread not in threads):
+        threads.append(thread)
+
+def store(time, event, cpu, thread, val, ena, run):
+    #print "event %s cpu %d, thread %d, time %d, val %d, ena %d, run %d" % \
+    #      (event, cpu, thread, time, val, ena, run)
+
+    store_key(time, cpu, thread)
+    key = get_key(time, event, cpu, thread)
+    data[key] = [ val, ena, run]
+
+def get(time, event, cpu, thread):
+    key = get_key(time, event, cpu, thread)
+    return data[key][0]
+
+def stat__cycles_k(cpu, thread, time, val, ena, run):
+    store(time, "cycles", cpu, thread, val, ena, run);
+
+def stat__instructions_k(cpu, thread, time, val, ena, run):
+    store(time, "instructions", cpu, thread, val, ena, run);
+
+def stat__cycles_u(cpu, thread, time, val, ena, run):
+    store(time, "cycles", cpu, thread, val, ena, run);
+
+def stat__instructions_u(cpu, thread, time, val, ena, run):
+    store(time, "instructions", cpu, thread, val, ena, run);
+
+def stat__cycles(cpu, thread, time, val, ena, run):
+    store(time, "cycles", cpu, thread, val, ena, run);
+
+def stat__instructions(cpu, thread, time, val, ena, run):
+    store(time, "instructions", cpu, thread, val, ena, run);
+
+def stat__interval(time):
+    for cpu in cpus:
+        for thread in threads:
+            cyc = get(time, "cycles", cpu, thread)
+            ins = get(time, "instructions", cpu, thread)
+            cpi = 0
+
+            if ins != 0:
+                cpi = cyc/float(ins)
+
+            print "%15f: cpu %d, thread %d -> cpi %f (%d/%d)" % (time/(float(1000000000)), cpu, thread, cpi, cyc, ins)
+
+def trace_end():
+    pass
+# XXX trace_end callback could be used as an alternative place
+#     to compute same values as in the script above:
+#
+#    for time in times:
+#        for cpu in cpus:
+#            for thread in threads:
+#                cyc = get(time, "cycles", cpu, thread)
+#                ins = get(time, "instructions", cpu, thread)
+#
+#                if ins != 0:
+#                    cpi = cyc/float(ins)
+#
+#                print "time %.9f, cpu %d, thread %d -> cpi %f" % (time/(float(1000000000)), cpu, thread, cpi)
index 489fc9ffbcb0908fd218cb5dfc603ae985270ce2..bf016c439fbd10a3cada60253c98d60ce441aa98 100644 (file)
@@ -1,2 +1,3 @@
 llvm-src-base.c
 llvm-src-kbuild.c
+llvm-src-prologue.c
index f41ebf8849feb1d5fe20e2601de952c85e3bac8c..614899b88b377e07f9615d618ba7045f66051bea 100644 (file)
@@ -31,24 +31,34 @@ perf-y += sample-parsing.o
 perf-y += parse-no-sample-id-all.o
 perf-y += kmod-path.o
 perf-y += thread-map.o
-perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o
+perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o llvm-src-prologue.o
 perf-y += bpf.o
 perf-y += topology.o
+perf-y += cpumap.o
+perf-y += stat.o
+perf-y += event_update.o
 
-$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c
+$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build
        $(call rule_mkdir)
        $(Q)echo '#include <tests/llvm.h>' > $@
        $(Q)echo 'const char test_llvm__bpf_base_prog[] =' >> $@
        $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
        $(Q)echo ';' >> $@
 
-$(OUTPUT)tests/llvm-src-kbuild.c: tests/bpf-script-test-kbuild.c
+$(OUTPUT)tests/llvm-src-kbuild.c: tests/bpf-script-test-kbuild.c tests/Build
        $(call rule_mkdir)
        $(Q)echo '#include <tests/llvm.h>' > $@
        $(Q)echo 'const char test_llvm__bpf_test_kbuild_prog[] =' >> $@
        $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
        $(Q)echo ';' >> $@
 
+$(OUTPUT)tests/llvm-src-prologue.c: tests/bpf-script-test-prologue.c tests/Build
+       $(call rule_mkdir)
+       $(Q)echo '#include <tests/llvm.h>' > $@
+       $(Q)echo 'const char test_llvm__bpf_test_prologue_prog[] =' >> $@
+       $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
+       $(Q)echo ';' >> $@
+
 ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64))
 perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
 endif
index 638875a0960a1e8d8b786a4b7c73dab463050857..28d1605b033896aa4b87844eeffa6d9dc1646e6b 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/kernel.h>
 #include "../perf.h"
 #include "util.h"
-#include "exec_cmd.h"
+#include <subcmd/exec-cmd.h>
 #include "tests.h"
 
 #define ENV "PERF_TEST_ATTR"
@@ -153,7 +153,7 @@ static int run_dir(const char *d, const char *perf)
        return system(cmd);
 }
 
-int test__attr(void)
+int test__attr(int subtest __maybe_unused)
 {
        struct stat st;
        char path_perf[PATH_MAX];
@@ -164,7 +164,7 @@ int test__attr(void)
                return run_dir("./tests", "./perf");
 
        /* Then installed path. */
-       snprintf(path_dir,  PATH_MAX, "%s/tests", perf_exec_path());
+       snprintf(path_dir,  PATH_MAX, "%s/tests", get_argv_exec_path());
        snprintf(path_perf, PATH_MAX, "%s/perf", BINDIR);
 
        if (!lstat(path_dir, &st) &&
index a02b035fd5aa84ba8e473d0902cccb39806a82b5..fb80c9eb6a95b67947b23adaeca69b5e57bac704 100644 (file)
@@ -111,7 +111,7 @@ static long long bp_count(int fd)
        return count;
 }
 
-int test__bp_signal(void)
+int test__bp_signal(int subtest __maybe_unused)
 {
        struct sigaction sa;
        long long count1, count2;
index e76537724491850342753c0b5ddead454555b899..89f92fa67cc4c48f6804ecde82532765e6e27932 100644 (file)
@@ -58,7 +58,7 @@ static long long bp_count(int fd)
 #define EXECUTIONS 10000
 #define THRESHOLD  100
 
-int test__bp_signal_overflow(void)
+int test__bp_signal_overflow(int subtest __maybe_unused)
 {
        struct perf_event_attr pe;
        struct sigaction sa;
diff --git a/tools/perf/tests/bpf-script-test-prologue.c b/tools/perf/tests/bpf-script-test-prologue.c
new file mode 100644 (file)
index 0000000..7230e62
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * bpf-script-test-prologue.c
+ * Test BPF prologue
+ */
+#ifndef LINUX_VERSION_CODE
+# error Need LINUX_VERSION_CODE
+# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig'
+#endif
+#define SEC(NAME) __attribute__((section(NAME), used))
+
+#include <uapi/linux/fs.h>
+
+#define FMODE_READ             0x1
+#define FMODE_WRITE            0x2
+
+static void (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
+       (void *) 6;
+
+SEC("func=null_lseek file->f_mode offset orig")
+int bpf_func__null_lseek(void *ctx, int err, unsigned long f_mode,
+                        unsigned long offset, unsigned long orig)
+{
+       if (err)
+               return 0;
+       if (f_mode & FMODE_WRITE)
+               return 0;
+       if (offset & 1)
+               return 0;
+       if (orig == SEEK_CUR)
+               return 0;
+       return 1;
+}
+
+char _license[] SEC("license") = "GPL";
+int _version SEC("version") = LINUX_VERSION_CODE;
index ec16f7812c8b59e325a9e7516e359f50de7a44b3..33689a0cf821e5b9608e54b981e3280ee580890c 100644 (file)
@@ -19,6 +19,29 @@ static int epoll_pwait_loop(void)
        return 0;
 }
 
+#ifdef HAVE_BPF_PROLOGUE
+
+static int llseek_loop(void)
+{
+       int fds[2], i;
+
+       fds[0] = open("/dev/null", O_RDONLY);
+       fds[1] = open("/dev/null", O_RDWR);
+
+       if (fds[0] < 0 || fds[1] < 0)
+               return -1;
+
+       for (i = 0; i < NR_ITERS; i++) {
+               lseek(fds[i % 2], i, (i / 2) % 2 ? SEEK_CUR : SEEK_SET);
+               lseek(fds[(i + 1) % 2], i, (i / 2) % 2 ? SEEK_CUR : SEEK_SET);
+       }
+       close(fds[0]);
+       close(fds[1]);
+       return 0;
+}
+
+#endif
+
 static struct {
        enum test_llvm__testcase prog_id;
        const char *desc;
@@ -37,6 +60,17 @@ static struct {
                &epoll_pwait_loop,
                (NR_ITERS + 1) / 2,
        },
+#ifdef HAVE_BPF_PROLOGUE
+       {
+               LLVM_TESTCASE_BPF_PROLOGUE,
+               "Test BPF prologue generation",
+               "[bpf_prologue_test]",
+               "fix kbuild first",
+               "check your vmlinux setting?",
+               &llseek_loop,
+               (NR_ITERS + 1) / 4,
+       },
+#endif
 };
 
 static int do_test(struct bpf_object *obj, int (*func)(void),
@@ -68,8 +102,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void),
        err = parse_events_load_bpf_obj(&parse_evlist, &parse_evlist.list, obj);
        if (err || list_empty(&parse_evlist.list)) {
                pr_debug("Failed to add events selected by BPF\n");
-               if (!err)
-                       return TEST_FAIL;
+               return TEST_FAIL;
        }
 
        snprintf(pid, sizeof(pid), "%d", getpid());
@@ -123,8 +156,10 @@ static int do_test(struct bpf_object *obj, int (*func)(void),
                }
        }
 
-       if (count != expect)
+       if (count != expect) {
                pr_debug("BPF filter result incorrect\n");
+               goto out_delete_evlist;
+       }
 
        ret = TEST_OK;
 
@@ -146,7 +181,7 @@ prepare_bpf(void *obj_buf, size_t obj_buf_sz, const char *name)
        return obj;
 }
 
-static int __test__bpf(int index)
+static int __test__bpf(int idx)
 {
        int ret;
        void *obj_buf;
@@ -154,54 +189,72 @@ static int __test__bpf(int index)
        struct bpf_object *obj;
 
        ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
-                                      bpf_testcase_table[index].prog_id,
+                                      bpf_testcase_table[idx].prog_id,
                                       true);
        if (ret != TEST_OK || !obj_buf || !obj_buf_sz) {
                pr_debug("Unable to get BPF object, %s\n",
-                        bpf_testcase_table[index].msg_compile_fail);
-               if (index == 0)
+                        bpf_testcase_table[idx].msg_compile_fail);
+               if (idx == 0)
                        return TEST_SKIP;
                else
                        return TEST_FAIL;
        }
 
        obj = prepare_bpf(obj_buf, obj_buf_sz,
-                         bpf_testcase_table[index].name);
+                         bpf_testcase_table[idx].name);
        if (!obj) {
                ret = TEST_FAIL;
                goto out;
        }
 
        ret = do_test(obj,
-                     bpf_testcase_table[index].target_func,
-                     bpf_testcase_table[index].expect_result);
+                     bpf_testcase_table[idx].target_func,
+                     bpf_testcase_table[idx].expect_result);
 out:
        bpf__clear();
        return ret;
 }
 
-int test__bpf(void)
+int test__bpf_subtest_get_nr(void)
+{
+       return (int)ARRAY_SIZE(bpf_testcase_table);
+}
+
+const char *test__bpf_subtest_get_desc(int i)
+{
+       if (i < 0 || i >= (int)ARRAY_SIZE(bpf_testcase_table))
+               return NULL;
+       return bpf_testcase_table[i].desc;
+}
+
+int test__bpf(int i)
 {
-       unsigned int i;
        int err;
 
+       if (i < 0 || i >= (int)ARRAY_SIZE(bpf_testcase_table))
+               return TEST_FAIL;
+
        if (geteuid() != 0) {
                pr_debug("Only root can run BPF test\n");
                return TEST_SKIP;
        }
 
-       for (i = 0; i < ARRAY_SIZE(bpf_testcase_table); i++) {
-               err = __test__bpf(i);
+       err = __test__bpf(i);
+       return err;
+}
 
-               if (err != TEST_OK)
-                       return err;
-       }
+#else
+int test__bpf_subtest_get_nr(void)
+{
+       return 0;
+}
 
-       return TEST_OK;
+const char *test__bpf_subtest_get_desc(int i __maybe_unused)
+{
+       return NULL;
 }
 
-#else
-int test__bpf(void)
+int test__bpf(int i __maybe_unused)
 {
        pr_debug("Skip BPF test because BPF support is not compiled\n");
        return TEST_SKIP;
index 80c442eab767d0c333408c8daecbc32d3a120d0e..f2b1dcac45d3065d90ef6fb01bdd57694577d809 100644 (file)
@@ -11,7 +11,7 @@
 #include "tests.h"
 #include "debug.h"
 #include "color.h"
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
 #include "symbol.h"
 
 struct test __weak arch_tests[] = {
@@ -160,6 +160,11 @@ static struct test generic_tests[] = {
        {
                .desc = "Test LLVM searching and compiling",
                .func = test__llvm,
+               .subtest = {
+                       .skip_if_fail   = true,
+                       .get_nr         = test__llvm_subtest_get_nr,
+                       .get_desc       = test__llvm_subtest_get_desc,
+               },
        },
        {
                .desc = "Test topology in session",
@@ -168,6 +173,35 @@ static struct test generic_tests[] = {
        {
                .desc = "Test BPF filter",
                .func = test__bpf,
+               .subtest = {
+                       .skip_if_fail   = true,
+                       .get_nr         = test__bpf_subtest_get_nr,
+                       .get_desc       = test__bpf_subtest_get_desc,
+               },
+       },
+       {
+               .desc = "Test thread map synthesize",
+               .func = test__thread_map_synthesize,
+       },
+       {
+               .desc = "Test cpu map synthesize",
+               .func = test__cpu_map_synthesize,
+       },
+       {
+               .desc = "Test stat config synthesize",
+               .func = test__synthesize_stat_config,
+       },
+       {
+               .desc = "Test stat synthesize",
+               .func = test__synthesize_stat,
+       },
+       {
+               .desc = "Test stat round synthesize",
+               .func = test__synthesize_stat_round,
+       },
+       {
+               .desc = "Test attr update synthesize",
+               .func = test__event_update,
        },
        {
                .func = NULL,
@@ -203,7 +237,7 @@ static bool perf_test__matches(struct test *test, int curr, int argc, const char
        return false;
 }
 
-static int run_test(struct test *test)
+static int run_test(struct test *test, int subtest)
 {
        int status, err = -1, child = fork();
        char sbuf[STRERR_BUFSIZE];
@@ -216,7 +250,22 @@ static int run_test(struct test *test)
 
        if (!child) {
                pr_debug("test child forked, pid %d\n", getpid());
-               err = test->func();
+               if (!verbose) {
+                       int nullfd = open("/dev/null", O_WRONLY);
+                       if (nullfd >= 0) {
+                               close(STDERR_FILENO);
+                               close(STDOUT_FILENO);
+
+                               dup2(nullfd, STDOUT_FILENO);
+                               dup2(STDOUT_FILENO, STDERR_FILENO);
+                               close(nullfd);
+                       }
+               } else {
+                       signal(SIGSEGV, sighandler_dump_stack);
+                       signal(SIGFPE, sighandler_dump_stack);
+               }
+
+               err = test->func(subtest);
                exit(err);
        }
 
@@ -237,6 +286,40 @@ static int run_test(struct test *test)
        for (j = 0; j < ARRAY_SIZE(tests); j++) \
                for (t = &tests[j][0]; t->func; t++)
 
+static int test_and_print(struct test *t, bool force_skip, int subtest)
+{
+       int err;
+
+       if (!force_skip) {
+               pr_debug("\n--- start ---\n");
+               err = run_test(t, subtest);
+               pr_debug("---- end ----\n");
+       } else {
+               pr_debug("\n--- force skipped ---\n");
+               err = TEST_SKIP;
+       }
+
+       if (!t->subtest.get_nr)
+               pr_debug("%s:", t->desc);
+       else
+               pr_debug("%s subtest %d:", t->desc, subtest);
+
+       switch (err) {
+       case TEST_OK:
+               pr_info(" Ok\n");
+               break;
+       case TEST_SKIP:
+               color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n");
+               break;
+       case TEST_FAIL:
+       default:
+               color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
+               break;
+       }
+
+       return err;
+}
+
 static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
 {
        struct test *t;
@@ -264,21 +347,43 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
                        continue;
                }
 
-               pr_debug("\n--- start ---\n");
-               err = run_test(t);
-               pr_debug("---- end ----\n%s:", t->desc);
-
-               switch (err) {
-               case TEST_OK:
-                       pr_info(" Ok\n");
-                       break;
-               case TEST_SKIP:
-                       color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n");
-                       break;
-               case TEST_FAIL:
-               default:
-                       color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
-                       break;
+               if (!t->subtest.get_nr) {
+                       test_and_print(t, false, -1);
+               } else {
+                       int subn = t->subtest.get_nr();
+                       /*
+                        * minus 2 to align with normal testcases.
+                        * For subtest we print additional '.x' in number.
+                        * for example:
+                        *
+                        * 35: Test LLVM searching and compiling                        :
+                        * 35.1: Basic BPF llvm compiling test                          : Ok
+                        */
+                       int subw = width > 2 ? width - 2 : width;
+                       bool skip = false;
+                       int subi;
+
+                       if (subn <= 0) {
+                               color_fprintf(stderr, PERF_COLOR_YELLOW,
+                                             " Skip (not compiled in)\n");
+                               continue;
+                       }
+                       pr_info("\n");
+
+                       for (subi = 0; subi < subn; subi++) {
+                               int len = strlen(t->subtest.get_desc(subi));
+
+                               if (subw < len)
+                                       subw = len;
+                       }
+
+                       for (subi = 0; subi < subn; subi++) {
+                               pr_info("%2d.%1d: %-*s:", i, subi + 1, subw,
+                                       t->subtest.get_desc(subi));
+                               err = test_and_print(t, skip, subi);
+                               if (err != TEST_OK && t->subtest.skip_if_fail)
+                                       skip = true;
+                       }
                }
        }
 
index a767a6400c5ced49b16b9b4be7a3ea638799998d..313a48c6b2bc8e111e113e79c4a72fdc2d720ac5 100644 (file)
@@ -433,7 +433,6 @@ enum {
 
 static int do_test_code_reading(bool try_kcore)
 {
-       struct machines machines;
        struct machine *machine;
        struct thread *thread;
        struct record_opts opts = {
@@ -459,8 +458,7 @@ static int do_test_code_reading(bool try_kcore)
 
        pid = getpid();
 
-       machines__init(&machines);
-       machine = &machines.host;
+       machine = machine__new_host();
 
        ret = machine__create_kernel_maps(machine);
        if (ret < 0) {
@@ -549,6 +547,13 @@ static int do_test_code_reading(bool try_kcore)
                if (ret < 0) {
                        if (!excl_kernel) {
                                excl_kernel = true;
+                               /*
+                                * Both cpus and threads are now owned by evlist
+                                * and will be freed by following perf_evlist__set_maps
+                                * call. Getting refference to keep them alive.
+                                */
+                               cpu_map__get(cpus);
+                               thread_map__get(threads);
                                perf_evlist__set_maps(evlist, NULL, NULL);
                                perf_evlist__delete(evlist);
                                evlist = NULL;
@@ -594,14 +599,13 @@ out_err:
                cpu_map__put(cpus);
                thread_map__put(threads);
        }
-       machines__destroy_kernel_maps(&machines);
        machine__delete_threads(machine);
-       machines__exit(&machines);
+       machine__delete(machine);
 
        return err;
 }
 
-int test__code_reading(void)
+int test__code_reading(int subtest __maybe_unused)
 {
        int ret;
 
diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c
new file mode 100644 (file)
index 0000000..4cb6418
--- /dev/null
@@ -0,0 +1,88 @@
+#include "tests.h"
+#include "cpumap.h"
+
+static int process_event_mask(struct perf_tool *tool __maybe_unused,
+                        union perf_event *event,
+                        struct perf_sample *sample __maybe_unused,
+                        struct machine *machine __maybe_unused)
+{
+       struct cpu_map_event *map_event = &event->cpu_map;
+       struct cpu_map_mask *mask;
+       struct cpu_map_data *data;
+       struct cpu_map *map;
+       int i;
+
+       data = &map_event->data;
+
+       TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__MASK);
+
+       mask = (struct cpu_map_mask *)data->data;
+
+       TEST_ASSERT_VAL("wrong nr",   mask->nr == 1);
+
+       for (i = 0; i < 20; i++) {
+               TEST_ASSERT_VAL("wrong cpu", test_bit(i, mask->mask));
+       }
+
+       map = cpu_map__new_data(data);
+       TEST_ASSERT_VAL("wrong nr",  map->nr == 20);
+
+       for (i = 0; i < 20; i++) {
+               TEST_ASSERT_VAL("wrong cpu", map->map[i] == i);
+       }
+
+       cpu_map__put(map);
+       return 0;
+}
+
+static int process_event_cpus(struct perf_tool *tool __maybe_unused,
+                        union perf_event *event,
+                        struct perf_sample *sample __maybe_unused,
+                        struct machine *machine __maybe_unused)
+{
+       struct cpu_map_event *map_event = &event->cpu_map;
+       struct cpu_map_entries *cpus;
+       struct cpu_map_data *data;
+       struct cpu_map *map;
+
+       data = &map_event->data;
+
+       TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__CPUS);
+
+       cpus = (struct cpu_map_entries *)data->data;
+
+       TEST_ASSERT_VAL("wrong nr",   cpus->nr == 2);
+       TEST_ASSERT_VAL("wrong cpu",  cpus->cpu[0] == 1);
+       TEST_ASSERT_VAL("wrong cpu",  cpus->cpu[1] == 256);
+
+       map = cpu_map__new_data(data);
+       TEST_ASSERT_VAL("wrong nr",  map->nr == 2);
+       TEST_ASSERT_VAL("wrong cpu", map->map[0] == 1);
+       TEST_ASSERT_VAL("wrong cpu", map->map[1] == 256);
+       TEST_ASSERT_VAL("wrong refcnt", atomic_read(&map->refcnt) == 1);
+       cpu_map__put(map);
+       return 0;
+}
+
+
+int test__cpu_map_synthesize(int subtest __maybe_unused)
+{
+       struct cpu_map *cpus;
+
+       /* This one is better stores in mask. */
+       cpus = cpu_map__new("0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19");
+
+       TEST_ASSERT_VAL("failed to synthesize map",
+               !perf_event__synthesize_cpu_map(NULL, cpus, process_event_mask, NULL));
+
+       cpu_map__put(cpus);
+
+       /* This one is better stores in cpu values. */
+       cpus = cpu_map__new("1,256");
+
+       TEST_ASSERT_VAL("failed to synthesize map",
+               !perf_event__synthesize_cpu_map(NULL, cpus, process_event_cpus, NULL));
+
+       cpu_map__put(cpus);
+       return 0;
+}
index a218aeaf56a002396bf0d0db9ef0e457a7445c9f..dc673ff7c43756503ca095184f44bd2daa78b50e 100644 (file)
@@ -110,7 +110,7 @@ static int dso__data_fd(struct dso *dso, struct machine *machine)
        return fd;
 }
 
-int test__dso_data(void)
+int test__dso_data(int subtest __maybe_unused)
 {
        struct machine machine;
        struct dso *dso;
@@ -245,7 +245,7 @@ static int set_fd_limit(int n)
        return setrlimit(RLIMIT_NOFILE, &rlim);
 }
 
-int test__dso_data_cache(void)
+int test__dso_data_cache(int subtest __maybe_unused)
 {
        struct machine machine;
        long nr_end, nr = open_files_cnt();
@@ -302,7 +302,7 @@ int test__dso_data_cache(void)
        return 0;
 }
 
-int test__dso_data_reopen(void)
+int test__dso_data_reopen(int subtest __maybe_unused)
 {
        struct machine machine;
        long nr_end, nr = open_files_cnt();
index 07221793a3acec65d083f68548d4bf5e287b4628..1c5c0221cea2862fe7421c83e0cb16e987a8f320 100644 (file)
@@ -51,6 +51,12 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
                "krava_1",
                "test__dwarf_unwind"
        };
+       /*
+        * The funcs[MAX_STACK] array index, based on the
+        * callchain order setup.
+        */
+       int idx = callchain_param.order == ORDER_CALLER ?
+                 MAX_STACK - *cnt - 1 : *cnt;
 
        if (*cnt >= MAX_STACK) {
                pr_debug("failed: crossed the max stack value %d\n", MAX_STACK);
@@ -63,8 +69,10 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
                return -1;
        }
 
-       pr_debug("got: %s 0x%" PRIx64 "\n", symbol, entry->ip);
-       return strcmp((const char *) symbol, funcs[(*cnt)++]);
+       (*cnt)++;
+       pr_debug("got: %s 0x%" PRIx64 ", expecting %s\n",
+                symbol, entry->ip, funcs[idx]);
+       return strcmp((const char *) symbol, funcs[idx]);
 }
 
 __attribute__ ((noinline))
@@ -105,8 +113,16 @@ static int compare(void *p1, void *p2)
        /* Any possible value should be 'thread' */
        struct thread *thread = *(struct thread **)p1;
 
-       if (global_unwind_retval == -INT_MAX)
+       if (global_unwind_retval == -INT_MAX) {
+               /* Call unwinder twice for both callchain orders. */
+               callchain_param.order = ORDER_CALLER;
+
                global_unwind_retval = unwind_thread(thread);
+               if (!global_unwind_retval) {
+                       callchain_param.order = ORDER_CALLEE;
+                       global_unwind_retval = unwind_thread(thread);
+               }
+       }
 
        return p1 - p2;
 }
@@ -142,21 +158,23 @@ static int krava_1(struct thread *thread)
        return krava_2(thread);
 }
 
-int test__dwarf_unwind(void)
+int test__dwarf_unwind(int subtest __maybe_unused)
 {
-       struct machines machines;
        struct machine *machine;
        struct thread *thread;
        int err = -1;
 
-       machines__init(&machines);
-
-       machine = machines__find(&machines, HOST_KERNEL_ID);
+       machine = machine__new_host();
        if (!machine) {
                pr_err("Could not get machine\n");
                return -1;
        }
 
+       if (machine__create_kernel_maps(machine)) {
+               pr_err("Failed to create kernel maps\n");
+               return -1;
+       }
+
        callchain_param.record_mode = CALLCHAIN_DWARF;
 
        if (init_live_machine(machine)) {
@@ -178,7 +196,6 @@ int test__dwarf_unwind(void)
 
  out:
        machine__delete_threads(machine);
-       machine__exit(machine);
-       machines__exit(&machines);
+       machine__delete(machine);
        return err;
 }
diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c
new file mode 100644 (file)
index 0000000..012eab5
--- /dev/null
@@ -0,0 +1,117 @@
+#include <linux/compiler.h>
+#include "evlist.h"
+#include "evsel.h"
+#include "machine.h"
+#include "tests.h"
+#include "debug.h"
+
+static int process_event_unit(struct perf_tool *tool __maybe_unused,
+                             union perf_event *event,
+                             struct perf_sample *sample __maybe_unused,
+                             struct machine *machine __maybe_unused)
+{
+       struct event_update_event *ev = (struct event_update_event *) event;
+
+       TEST_ASSERT_VAL("wrong id", ev->id == 123);
+       TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__UNIT);
+       TEST_ASSERT_VAL("wrong unit", !strcmp(ev->data, "KRAVA"));
+       return 0;
+}
+
+static int process_event_scale(struct perf_tool *tool __maybe_unused,
+                              union perf_event *event,
+                              struct perf_sample *sample __maybe_unused,
+                              struct machine *machine __maybe_unused)
+{
+       struct event_update_event *ev = (struct event_update_event *) event;
+       struct event_update_event_scale *ev_data;
+
+       ev_data = (struct event_update_event_scale *) ev->data;
+
+       TEST_ASSERT_VAL("wrong id", ev->id == 123);
+       TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__SCALE);
+       TEST_ASSERT_VAL("wrong scale", ev_data->scale = 0.123);
+       return 0;
+}
+
+struct event_name {
+       struct perf_tool tool;
+       const char *name;
+};
+
+static int process_event_name(struct perf_tool *tool,
+                             union perf_event *event,
+                             struct perf_sample *sample __maybe_unused,
+                             struct machine *machine __maybe_unused)
+{
+       struct event_name *tmp = container_of(tool, struct event_name, tool);
+       struct event_update_event *ev = (struct event_update_event*) event;
+
+       TEST_ASSERT_VAL("wrong id", ev->id == 123);
+       TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__NAME);
+       TEST_ASSERT_VAL("wrong name", !strcmp(ev->data, tmp->name));
+       return 0;
+}
+
+static int process_event_cpus(struct perf_tool *tool __maybe_unused,
+                             union perf_event *event,
+                             struct perf_sample *sample __maybe_unused,
+                             struct machine *machine __maybe_unused)
+{
+       struct event_update_event *ev = (struct event_update_event*) event;
+       struct event_update_event_cpus *ev_data;
+       struct cpu_map *map;
+
+       ev_data = (struct event_update_event_cpus*) ev->data;
+
+       map = cpu_map__new_data(&ev_data->cpus);
+
+       TEST_ASSERT_VAL("wrong id", ev->id == 123);
+       TEST_ASSERT_VAL("wrong type", ev->type == PERF_EVENT_UPDATE__CPUS);
+       TEST_ASSERT_VAL("wrong cpus", map->nr == 3);
+       TEST_ASSERT_VAL("wrong cpus", map->map[0] == 1);
+       TEST_ASSERT_VAL("wrong cpus", map->map[1] == 2);
+       TEST_ASSERT_VAL("wrong cpus", map->map[2] == 3);
+       cpu_map__put(map);
+       return 0;
+}
+
+int test__event_update(int subtest __maybe_unused)
+{
+       struct perf_evlist *evlist;
+       struct perf_evsel *evsel;
+       struct event_name tmp;
+
+       evlist = perf_evlist__new_default();
+       TEST_ASSERT_VAL("failed to get evlist", evlist);
+
+       evsel = perf_evlist__first(evlist);
+
+       TEST_ASSERT_VAL("failed to allos ids",
+                       !perf_evsel__alloc_id(evsel, 1, 1));
+
+       perf_evlist__id_add(evlist, evsel, 0, 0, 123);
+
+       evsel->unit = strdup("KRAVA");
+
+       TEST_ASSERT_VAL("failed to synthesize attr update unit",
+                       !perf_event__synthesize_event_update_unit(NULL, evsel, process_event_unit));
+
+       evsel->scale = 0.123;
+
+       TEST_ASSERT_VAL("failed to synthesize attr update scale",
+                       !perf_event__synthesize_event_update_scale(NULL, evsel, process_event_scale));
+
+       tmp.name = perf_evsel__name(evsel);
+
+       TEST_ASSERT_VAL("failed to synthesize attr update name",
+                       !perf_event__synthesize_event_update_name(&tmp.tool, evsel, process_event_name));
+
+       evsel->own_cpus = cpu_map__new("1,2,3");
+
+       TEST_ASSERT_VAL("failed to synthesize attr update cpus",
+                       !perf_event__synthesize_event_update_cpus(&tmp.tool, evsel, process_event_cpus));
+
+       cpu_map__put(evsel->own_cpus);
+       return 0;
+}
index 3fa715987a5ec2693e2bcdb31a33e3f20616c136..2de4a4f2c3ed3df38e85e69f19dc68fc14f66f3d 100644 (file)
@@ -95,7 +95,7 @@ out_delete_evlist:
 #define perf_evsel__name_array_test(names) \
        __perf_evsel__name_array_test(names, ARRAY_SIZE(names))
 
-int test__perf_evsel__roundtrip_name_test(void)
+int test__perf_evsel__roundtrip_name_test(int subtest __maybe_unused)
 {
        int err = 0, ret = 0;
 
@@ -103,7 +103,8 @@ int test__perf_evsel__roundtrip_name_test(void)
        if (err)
                ret = err;
 
-       err = perf_evsel__name_array_test(perf_evsel__sw_names);
+       err = __perf_evsel__name_array_test(perf_evsel__sw_names,
+                                           PERF_COUNT_SW_DUMMY + 1);
        if (err)
                ret = err;
 
index 790e413d9a1f39c1945bb4519a4391ded30560e9..1984b3bbfe15d2bc6f407e1e272d3f1a95046916 100644 (file)
@@ -32,7 +32,7 @@ static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
        return ret;
 }
 
-int test__perf_evsel__tp_sched_test(void)
+int test__perf_evsel__tp_sched_test(int subtest __maybe_unused)
 {
        struct perf_evsel *evsel = perf_evsel__newtp("sched", "sched_switch");
        int ret = 0;
index d24b837951d4c4e33dd879def62d8cc407bf4df8..c809463edbe51b96891f30bba13226c8f3f9ad99 100644 (file)
@@ -25,7 +25,7 @@ static int fdarray__fprintf_prefix(struct fdarray *fda, const char *prefix, FILE
        return printed + fdarray__fprintf(fda, fp);
 }
 
-int test__fdarray__filter(void)
+int test__fdarray__filter(int subtest __maybe_unused)
 {
        int nr_fds, expected_fd[2], fd, err = TEST_FAIL;
        struct fdarray *fda = fdarray__new(5, 5);
@@ -103,7 +103,7 @@ out:
        return err;
 }
 
-int test__fdarray__add(void)
+int test__fdarray__add(int subtest __maybe_unused)
 {
        int err = TEST_FAIL;
        struct fdarray *fda = fdarray__new(2, 2);
index ce80b274b097332d02b5502fb0c5b88fc6d6016a..bcfd081ee1d2210acd722f1706660ee549ba10e6 100644 (file)
@@ -87,6 +87,11 @@ struct machine *setup_fake_machine(struct machines *machines)
                return NULL;
        }
 
+       if (machine__create_kernel_maps(machine)) {
+               pr_debug("Cannot create kernel maps\n");
+               return NULL;
+       }
+
        for (i = 0; i < ARRAY_SIZE(fake_threads); i++) {
                struct thread *thread;
 
@@ -150,7 +155,6 @@ struct machine *setup_fake_machine(struct machines *machines)
 out:
        pr_debug("Not enough memory for machine setup\n");
        machine__delete_threads(machine);
-       machine__delete(machine);
        return NULL;
 }
 
index 7ed737019de7f621226e698939a718b1af1594d6..e360892120618a46eea78dd5b1c59f6e87cfc9ca 100644 (file)
@@ -281,7 +281,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine)
        symbol_conf.cumulate_callchain = false;
        perf_evsel__reset_sample_bit(evsel, CALLCHAIN);
 
-       setup_sorting();
+       setup_sorting(NULL);
        callchain_register_param(&callchain_param);
 
        err = add_hist_entries(hists, machine);
@@ -428,7 +428,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine)
        symbol_conf.cumulate_callchain = false;
        perf_evsel__set_sample_bit(evsel, CALLCHAIN);
 
-       setup_sorting();
+       setup_sorting(NULL);
        callchain_register_param(&callchain_param);
 
        err = add_hist_entries(hists, machine);
@@ -486,7 +486,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
        symbol_conf.cumulate_callchain = true;
        perf_evsel__reset_sample_bit(evsel, CALLCHAIN);
 
-       setup_sorting();
+       setup_sorting(NULL);
        callchain_register_param(&callchain_param);
 
        err = add_hist_entries(hists, machine);
@@ -670,7 +670,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
        symbol_conf.cumulate_callchain = true;
        perf_evsel__set_sample_bit(evsel, CALLCHAIN);
 
-       setup_sorting();
+       setup_sorting(NULL);
        callchain_register_param(&callchain_param);
 
        err = add_hist_entries(hists, machine);
@@ -686,7 +686,7 @@ out:
        return err;
 }
 
-int test__hists_cumulate(void)
+int test__hists_cumulate(int subtest __maybe_unused)
 {
        int err = TEST_FAIL;
        struct machines machines;
index 818acf875dd0bb4afc7e4e60873125c4b4448a5c..2a784befd9ce56df84f0c3362c3ec7fcc05475c8 100644 (file)
@@ -104,7 +104,7 @@ out:
        return TEST_FAIL;
 }
 
-int test__hists_filter(void)
+int test__hists_filter(int subtest __maybe_unused)
 {
        int err = TEST_FAIL;
        struct machines machines;
@@ -122,7 +122,7 @@ int test__hists_filter(void)
                goto out;
 
        /* default sort order (comm,dso,sym) will be used */
-       if (setup_sorting() < 0)
+       if (setup_sorting(NULL) < 0)
                goto out;
 
        machines__init(&machines);
index 8c102b0114249708e4ae2059c81732ab23793c4b..c764d69ac6ef37e4e59e6335f9013de9f3baaef5 100644 (file)
@@ -64,7 +64,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
        struct perf_evsel *evsel;
        struct addr_location al;
        struct hist_entry *he;
-       struct perf_sample sample = { .period = 1, };
+       struct perf_sample sample = { .period = 1, .weight = 1, };
        size_t i = 0, k;
 
        /*
@@ -90,7 +90,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
                                goto out;
 
                        he = __hists__add_entry(hists, &al, NULL,
-                                               NULL, NULL, 1, 1, 0, true);
+                                               NULL, NULL, &sample, true);
                        if (he == NULL) {
                                addr_location__put(&al);
                                goto out;
@@ -116,7 +116,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
                                goto out;
 
                        he = __hists__add_entry(hists, &al, NULL,
-                                               NULL, NULL, 1, 1, 0, true);
+                                               NULL, NULL, &sample, true);
                        if (he == NULL) {
                                addr_location__put(&al);
                                goto out;
@@ -274,7 +274,7 @@ static int validate_link(struct hists *leader, struct hists *other)
        return __validate_link(leader, 0) || __validate_link(other, 1);
 }
 
-int test__hists_link(void)
+int test__hists_link(int subtest __maybe_unused)
 {
        int err = -1;
        struct hists *hists, *first_hists;
@@ -294,7 +294,7 @@ int test__hists_link(void)
                goto out;
 
        /* default sort order (comm,dso,sym) will be used */
-       if (setup_sorting() < 0)
+       if (setup_sorting(NULL) < 0)
                goto out;
 
        machines__init(&machines);
index adbebc852cc8b58886a2618f973815f9284b7b3b..ebe6cd485b5d8c4deeada43b89061f8905f4f554 100644 (file)
@@ -134,7 +134,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine)
        field_order = NULL;
        sort_order = NULL; /* equivalent to sort_order = "comm,dso,sym" */
 
-       setup_sorting();
+       setup_sorting(NULL);
 
        /*
         * expected output:
@@ -236,7 +236,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine)
        field_order = "overhead,cpu";
        sort_order = "pid";
 
-       setup_sorting();
+       setup_sorting(NULL);
 
        /*
         * expected output:
@@ -292,7 +292,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
        field_order = "comm,overhead,dso";
        sort_order = NULL;
 
-       setup_sorting();
+       setup_sorting(NULL);
 
        /*
         * expected output:
@@ -366,7 +366,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
        field_order = "dso,sym,comm,overhead,dso";
        sort_order = "sym";
 
-       setup_sorting();
+       setup_sorting(NULL);
 
        /*
         * expected output:
@@ -468,7 +468,7 @@ static int test5(struct perf_evsel *evsel, struct machine *machine)
        field_order = "cpu,pid,comm,dso,sym";
        sort_order = "dso,pid";
 
-       setup_sorting();
+       setup_sorting(NULL);
 
        /*
         * expected output:
@@ -576,7 +576,7 @@ out:
        return err;
 }
 
-int test__hists_output(void)
+int test__hists_output(int subtest __maybe_unused)
 {
        int err = TEST_FAIL;
        struct machines machines;
index a2e2269aa093a902f4810304d4af7e2fb8767b5c..ddb78fae064a50ca1d43476b29c7b5ff7ee2e7b3 100644 (file)
@@ -49,13 +49,12 @@ static int find_comm(struct perf_evlist *evlist, const char *comm)
  * when an event is disabled but a dummy software event is not disabled.  If the
  * test passes %0 is returned, otherwise %-1 is returned.
  */
-int test__keep_tracking(void)
+int test__keep_tracking(int subtest __maybe_unused)
 {
        struct record_opts opts = {
                .mmap_pages          = UINT_MAX,
                .user_freq           = UINT_MAX,
                .user_interval       = ULLONG_MAX,
-               .freq                = 4000,
                .target              = {
                        .uses_mmap   = true,
                },
@@ -124,7 +123,7 @@ int test__keep_tracking(void)
 
        evsel = perf_evlist__last(evlist);
 
-       CHECK__(perf_evlist__disable_event(evlist, evsel));
+       CHECK__(perf_evsel__disable(evsel));
 
        comm = "Test COMM 2";
        CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0));
index 08c433b4bf4f30c8f69307ba3fd5b0ec21802e2f..d2af78193153cb559ea58002fcb7aba4d03abdd5 100644 (file)
@@ -49,7 +49,7 @@ static int test_is_kernel_module(const char *path, int cpumode, bool expect)
 #define M(path, c, e) \
        TEST_ASSERT_VAL("failed", !test_is_kernel_module(path, c, e))
 
-int test__kmod_path__parse(void)
+int test__kmod_path__parse(int subtest __maybe_unused)
 {
        /* path                alloc_name  alloc_ext   kmod  comp   name     ext */
        T("/xxxx/xxxx/x-x.ko", true      , true      , true, false, "[x_x]", NULL);
index bc4cf507cde50b7018bac107e152ba9f23ab007d..06f45c1d42561df030e35d55078d70d910e79998 100644 (file)
@@ -44,13 +44,17 @@ static struct {
                .source = test_llvm__bpf_test_kbuild_prog,
                .desc = "Test kbuild searching",
        },
+       [LLVM_TESTCASE_BPF_PROLOGUE] = {
+               .source = test_llvm__bpf_test_prologue_prog,
+               .desc = "Compile source for BPF prologue generation test",
+       },
 };
 
 
 int
 test_llvm__fetch_bpf_obj(void **p_obj_buf,
                         size_t *p_obj_buf_sz,
-                        enum test_llvm__testcase index,
+                        enum test_llvm__testcase idx,
                         bool force)
 {
        const char *source;
@@ -59,11 +63,11 @@ test_llvm__fetch_bpf_obj(void **p_obj_buf,
        char *tmpl_new = NULL, *clang_opt_new = NULL;
        int err, old_verbose, ret = TEST_FAIL;
 
-       if (index >= __LLVM_TESTCASE_MAX)
+       if (idx >= __LLVM_TESTCASE_MAX)
                return TEST_FAIL;
 
-       source = bpf_source_table[index].source;
-       desc = bpf_source_table[index].desc;
+       source = bpf_source_table[idx].source;
+       desc = bpf_source_table[idx].desc;
 
        perf_config(perf_config_cb, NULL);
 
@@ -127,44 +131,39 @@ out:
        return ret;
 }
 
-int test__llvm(void)
+int test__llvm(int subtest)
 {
-       enum test_llvm__testcase i;
+       int ret;
+       void *obj_buf = NULL;
+       size_t obj_buf_sz = 0;
 
-       for (i = 0; i < __LLVM_TESTCASE_MAX; i++) {
-               int ret;
-               void *obj_buf = NULL;
-               size_t obj_buf_sz = 0;
+       if ((subtest < 0) || (subtest >= __LLVM_TESTCASE_MAX))
+               return TEST_FAIL;
 
-               ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
-                                              i, false);
+       ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
+                                      subtest, false);
 
-               if (ret == TEST_OK) {
-                       ret = test__bpf_parsing(obj_buf, obj_buf_sz);
-                       if (ret != TEST_OK)
-                               pr_debug("Failed to parse test case '%s'\n",
-                                        bpf_source_table[i].desc);
-               }
-               free(obj_buf);
-
-               switch (ret) {
-               case TEST_SKIP:
-                       return TEST_SKIP;
-               case TEST_OK:
-                       break;
-               default:
-                       /*
-                        * Test 0 is the basic LLVM test. If test 0
-                        * fail, the basic LLVM support not functional
-                        * so the whole test should fail. If other test
-                        * case fail, it can be fixed by adjusting
-                        * config so don't report error.
-                        */
-                       if (i == 0)
-                               return TEST_FAIL;
-                       else
-                               return TEST_SKIP;
+       if (ret == TEST_OK) {
+               ret = test__bpf_parsing(obj_buf, obj_buf_sz);
+               if (ret != TEST_OK) {
+                       pr_debug("Failed to parse test case '%s'\n",
+                                bpf_source_table[subtest].desc);
                }
        }
-       return TEST_OK;
+       free(obj_buf);
+
+       return ret;
+}
+
+int test__llvm_subtest_get_nr(void)
+{
+       return __LLVM_TESTCASE_MAX;
+}
+
+const char *test__llvm_subtest_get_desc(int subtest)
+{
+       if ((subtest < 0) || (subtest >= __LLVM_TESTCASE_MAX))
+               return NULL;
+
+       return bpf_source_table[subtest].desc;
 }
index d91d8f44efeee2642a1dea7813b81a4299b7e067..5150b4d6ef50afe357f5f86300f4d39d28bec658 100644 (file)
@@ -6,10 +6,12 @@
 
 extern const char test_llvm__bpf_base_prog[];
 extern const char test_llvm__bpf_test_kbuild_prog[];
+extern const char test_llvm__bpf_test_prologue_prog[];
 
 enum test_llvm__testcase {
        LLVM_TESTCASE_BASE,
        LLVM_TESTCASE_KBUILD,
+       LLVM_TESTCASE_BPF_PROLOGUE,
        __LLVM_TESTCASE_MAX,
 };
 
index 8ea3dffc5065fbc532ebfe5a170d64f33f18ed3d..c1fbb8e884c0fcf2bcc84beec0bc13bd8c76ed34 100644 (file)
@@ -259,7 +259,8 @@ $(run_O):
 tarpkg:
        @cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \
        echo "- $@: $$cmd" && echo $$cmd > $@ && \
-       ( eval $$cmd ) >> $@ 2>&1
+       ( eval $$cmd ) >> $@ 2>&1 && \
+       rm -f $@
 
 make_kernelsrc:
        @echo "- make -C <kernelsrc> tools/perf"
index 4495493c943111aa6c76fd492d7ca6ee88b74e37..359e98fcd94cd1be00dcc085fa18d058c8fb1986 100644 (file)
@@ -16,7 +16,7 @@
  * Then it checks if the number of syscalls reported as perf events by
  * the kernel corresponds to the number of syscalls made.
  */
-int test__basic_mmap(void)
+int test__basic_mmap(int subtest __maybe_unused)
 {
        int err = -1;
        union perf_event *event;
index 145050e2e5446166f900f8d9405859b15bfcfff3..0c5ce44f723fcbfd9c43b6c15377c27d2d503038 100644 (file)
@@ -149,7 +149,6 @@ static int synth_process(struct machine *machine)
 
 static int mmap_events(synth_cb synth)
 {
-       struct machines machines;
        struct machine *machine;
        int err, i;
 
@@ -162,8 +161,7 @@ static int mmap_events(synth_cb synth)
         */
        TEST_ASSERT_VAL("failed to create threads", !threads_create());
 
-       machines__init(&machines);
-       machine = &machines.host;
+       machine = machine__new_host();
 
        dump_trace = verbose > 1 ? 1 : 0;
 
@@ -203,7 +201,7 @@ static int mmap_events(synth_cb synth)
        }
 
        machine__delete_threads(machine);
-       machines__exit(&machines);
+       machine__delete(machine);
        return err;
 }
 
@@ -221,7 +219,7 @@ static int mmap_events(synth_cb synth)
  *
  * by using all thread objects.
  */
-int test__mmap_thread_lookup(void)
+int test__mmap_thread_lookup(int subtest __maybe_unused)
 {
        /* perf_event__synthesize_threads synthesize */
        TEST_ASSERT_VAL("failed with sythesizing all",
index 2006485a2859ba450ddbe6da6c005ff58b5b47d8..53c2273e88592b56ac6b3ca977c43b7ae31e5655 100644 (file)
@@ -7,7 +7,7 @@
 #include "debug.h"
 #include "stat.h"
 
-int test__openat_syscall_event_on_all_cpus(void)
+int test__openat_syscall_event_on_all_cpus(int subtest __maybe_unused)
 {
        int err = -1, fd, cpu;
        struct cpu_map *cpus;
index 5e811cd8f1c3e14567ef38e9da9595f502946c5d..eb99a105f31ce60b6d16123c92524e2f436eb71b 100644 (file)
@@ -6,7 +6,7 @@
 #include "tests.h"
 #include "debug.h"
 
-int test__syscall_openat_tp_fields(void)
+int test__syscall_openat_tp_fields(int subtest __maybe_unused)
 {
        struct record_opts opts = {
                .target = {
index 033b54797b8a021fe5f5c7ed25459a23d9cb5b6c..1184f9ba649927826f3e96cbeb734404e08ae9be 100644 (file)
@@ -5,7 +5,7 @@
 #include "debug.h"
 #include "tests.h"
 
-int test__openat_syscall_event(void)
+int test__openat_syscall_event(int subtest __maybe_unused)
 {
        int err = -1, fd;
        struct perf_evsel *evsel;
index 636d7b42d8447f93917ce64b0aff528fd3fceed6..abe8849d1d7030bda2ae65f770424e3c9ad84330 100644 (file)
@@ -1765,7 +1765,7 @@ static void debug_warn(const char *warn, va_list params)
        fprintf(stderr, " Warning: %s\n", msg);
 }
 
-int test__parse_events(void)
+int test__parse_events(int subtest __maybe_unused)
 {
        int ret1, ret2 = 0;
 
index 2c63ea6585413c691beb0b2a6ebf52de292eca52..294c76b01b417d004fd20c047b624fe04cf61f65 100644 (file)
@@ -67,7 +67,7 @@ struct test_attr_event {
  *
  * Return: %0 on success, %-1 if the test fails.
  */
-int test__parse_no_sample_id_all(void)
+int test__parse_no_sample_id_all(int subtest __maybe_unused)
 {
        int err;
 
index 7a228a2a070bb2280d69320116b2985b5be05b21..1cc78cefe3990906d8195c43c4d6971e630ddc42 100644 (file)
@@ -32,7 +32,7 @@ realloc:
        return cpu;
 }
 
-int test__PERF_RECORD(void)
+int test__PERF_RECORD(int subtest __maybe_unused)
 {
        struct record_opts opts = {
                .target = {
@@ -40,12 +40,11 @@ int test__PERF_RECORD(void)
                        .uses_mmap = true,
                },
                .no_buffering = true,
-               .freq         = 10,
                .mmap_pages   = 256,
        };
        cpu_set_t cpu_mask;
        size_t cpu_mask_size = sizeof(cpu_mask);
-       struct perf_evlist *evlist = perf_evlist__new_default();
+       struct perf_evlist *evlist = perf_evlist__new_dummy();
        struct perf_evsel *evsel;
        struct perf_sample sample;
        const char *cmd = "sleep";
@@ -61,6 +60,9 @@ int test__PERF_RECORD(void)
        int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, };
        char sbuf[STRERR_BUFSIZE];
 
+       if (evlist == NULL) /* Fallback for kernels lacking PERF_COUNT_SW_DUMMY */
+               evlist = perf_evlist__new_default();
+
        if (evlist == NULL || argv == NULL) {
                pr_debug("Not enough memory to create evlist\n");
                goto out;
index faa04e9d5d5fc751a1ac8082522fb045f108a060..1e2ba26029301ffd85e1a1803eea8b8f40f134e6 100644 (file)
@@ -133,7 +133,7 @@ static struct list_head *test_terms_list(void)
        return &terms;
 }
 
-int test__pmu(void)
+int test__pmu(int subtest __maybe_unused)
 {
        char *format = test_format_dir_get();
        LIST_HEAD(formats);
index 7760277c6defa3470a7097c987bcc2de3a2fd13e..7a52834ee0d0e848802b104719ee7726e3b97aae 100644 (file)
@@ -4,11 +4,12 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <linux/compiler.h>
 #include "tests.h"
 
 extern int verbose;
 
-int test__python_use(void)
+int test__python_use(int subtest __maybe_unused)
 {
        char *cmd;
        int ret;
index 30c02181e78b228449fa5263f7b0b4c9e33a54d8..5f23710b9fee62855de88f11f39e6054d12c9a27 100644 (file)
@@ -290,7 +290,7 @@ out_free:
  * checks sample format bits separately and together.  If the test passes %0 is
  * returned, otherwise %-1 is returned.
  */
-int test__sample_parsing(void)
+int test__sample_parsing(int subtest __maybe_unused)
 {
        const u64 rf[] = {4, 5, 6, 7, 12, 13, 14, 15};
        u64 sample_type;
diff --git a/tools/perf/tests/stat.c b/tools/perf/tests/stat.c
new file mode 100644 (file)
index 0000000..6a20ff2
--- /dev/null
@@ -0,0 +1,111 @@
+#include <linux/compiler.h>
+#include "event.h"
+#include "tests.h"
+#include "stat.h"
+#include "counts.h"
+#include "debug.h"
+
+static bool has_term(struct stat_config_event *config,
+                    u64 tag, u64 val)
+{
+       unsigned i;
+
+       for (i = 0; i < config->nr; i++) {
+               if ((config->data[i].tag == tag) &&
+                   (config->data[i].val == val))
+                       return true;
+       }
+
+       return false;
+}
+
+static int process_stat_config_event(struct perf_tool *tool __maybe_unused,
+                                    union perf_event *event,
+                                    struct perf_sample *sample __maybe_unused,
+                                    struct machine *machine __maybe_unused)
+{
+       struct stat_config_event *config = &event->stat_config;
+       struct perf_stat_config stat_config;
+
+#define HAS(term, val) \
+       has_term(config, PERF_STAT_CONFIG_TERM__##term, val)
+
+       TEST_ASSERT_VAL("wrong nr",        config->nr == PERF_STAT_CONFIG_TERM__MAX);
+       TEST_ASSERT_VAL("wrong aggr_mode", HAS(AGGR_MODE, AGGR_CORE));
+       TEST_ASSERT_VAL("wrong scale",     HAS(SCALE, 1));
+       TEST_ASSERT_VAL("wrong interval",  HAS(INTERVAL, 1));
+
+#undef HAS
+
+       perf_event__read_stat_config(&stat_config, config);
+
+       TEST_ASSERT_VAL("wrong aggr_mode", stat_config.aggr_mode == AGGR_CORE);
+       TEST_ASSERT_VAL("wrong scale",     stat_config.scale == 1);
+       TEST_ASSERT_VAL("wrong interval",  stat_config.interval == 1);
+       return 0;
+}
+
+int test__synthesize_stat_config(int subtest __maybe_unused)
+{
+       struct perf_stat_config stat_config = {
+               .aggr_mode      = AGGR_CORE,
+               .scale          = 1,
+               .interval       = 1,
+       };
+
+       TEST_ASSERT_VAL("failed to synthesize stat_config",
+               !perf_event__synthesize_stat_config(NULL, &stat_config, process_stat_config_event, NULL));
+
+       return 0;
+}
+
+static int process_stat_event(struct perf_tool *tool __maybe_unused,
+                             union perf_event *event,
+                             struct perf_sample *sample __maybe_unused,
+                             struct machine *machine __maybe_unused)
+{
+       struct stat_event *st = &event->stat;
+
+       TEST_ASSERT_VAL("wrong cpu",    st->cpu    == 1);
+       TEST_ASSERT_VAL("wrong thread", st->thread == 2);
+       TEST_ASSERT_VAL("wrong id",     st->id     == 3);
+       TEST_ASSERT_VAL("wrong val",    st->val    == 100);
+       TEST_ASSERT_VAL("wrong run",    st->ena    == 200);
+       TEST_ASSERT_VAL("wrong ena",    st->run    == 300);
+       return 0;
+}
+
+int test__synthesize_stat(int subtest __maybe_unused)
+{
+       struct perf_counts_values count;
+
+       count.val = 100;
+       count.ena = 200;
+       count.run = 300;
+
+       TEST_ASSERT_VAL("failed to synthesize stat_config",
+               !perf_event__synthesize_stat(NULL, 1, 2, 3, &count, process_stat_event, NULL));
+
+       return 0;
+}
+
+static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
+                                   union perf_event *event,
+                                   struct perf_sample *sample __maybe_unused,
+                                   struct machine *machine __maybe_unused)
+{
+       struct stat_round_event *stat_round = &event->stat_round;
+
+       TEST_ASSERT_VAL("wrong time", stat_round->time == 0xdeadbeef);
+       TEST_ASSERT_VAL("wrong type", stat_round->type == PERF_STAT_ROUND_TYPE__INTERVAL);
+       return 0;
+}
+
+int test__synthesize_stat_round(int subtest __maybe_unused)
+{
+       TEST_ASSERT_VAL("failed to synthesize stat_config",
+               !perf_event__synthesize_stat_round(NULL, 0xdeadbeef, PERF_STAT_ROUND_TYPE__INTERVAL,
+                                                  process_stat_round_event, NULL));
+
+       return 0;
+}
index 5b83f56a3b6f25928337d3954d2924322d3154ef..36e8ce1550e30f3769cf0c32c60439d8aa750f7a 100644 (file)
@@ -122,7 +122,7 @@ out_delete_evlist:
        return err;
 }
 
-int test__sw_clock_freq(void)
+int test__sw_clock_freq(int subtest __maybe_unused)
 {
        int ret;
 
index a02af503100c9c51c1f961c9e089546ccdcfd000..ebd80168d51e853a29e0f34d93e4dad1812b417b 100644 (file)
@@ -305,7 +305,7 @@ out_free_nodes:
  * evsel->system_wide and evsel->tracking flags (respectively) with other events
  * sometimes enabled or disabled.
  */
-int test__switch_tracking(void)
+int test__switch_tracking(int subtest __maybe_unused)
 {
        const char *sched_switch = "sched:sched_switch";
        struct switch_tracking switch_tracking = { .tids = NULL, };
@@ -455,7 +455,7 @@ int test__switch_tracking(void)
 
        perf_evlist__enable(evlist);
 
-       err = perf_evlist__disable_event(evlist, cpu_clocks_evsel);
+       err = perf_evsel__disable(cpu_clocks_evsel);
        if (err) {
                pr_debug("perf_evlist__disable_event failed!\n");
                goto out_err;
@@ -474,7 +474,7 @@ int test__switch_tracking(void)
                goto out_err;
        }
 
-       err = perf_evlist__disable_event(evlist, cycles_evsel);
+       err = perf_evsel__disable(cycles_evsel);
        if (err) {
                pr_debug("perf_evlist__disable_event failed!\n");
                goto out_err;
@@ -500,7 +500,7 @@ int test__switch_tracking(void)
                goto out_err;
        }
 
-       err = perf_evlist__enable_event(evlist, cycles_evsel);
+       err = perf_evsel__enable(cycles_evsel);
        if (err) {
                pr_debug("perf_evlist__disable_event failed!\n");
                goto out_err;
index add16385f13e5bbb750cec83da3f1fe0d28889af..2dfff7ac8ef31eae49b01b62c024ff4ddcf246dc 100644 (file)
@@ -31,7 +31,7 @@ static void workload_exec_failed_signal(int signo __maybe_unused,
  * if the number of exit event reported by the kernel is 1 or not
  * in order to check the kernel returns correct number of event.
  */
-int test__task_exit(void)
+int test__task_exit(int subtest __maybe_unused)
 {
        int err = -1;
        union perf_event *event;
index 3c8734a3abbc5ba24c9feb90c3cbdf3c5c1dfc7e..82b2b5e6ba7c7613ca58f9a46cda688b36444915 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef TESTS_H
 #define TESTS_H
 
+#include <stdbool.h>
+
 #define TEST_ASSERT_VAL(text, cond)                                     \
 do {                                                                    \
        if (!(cond)) {                                                   \
@@ -26,48 +28,63 @@ enum {
 
 struct test {
        const char *desc;
-       int (*func)(void);
+       int (*func)(int subtest);
+       struct {
+               bool skip_if_fail;
+               int (*get_nr)(void);
+               const char *(*get_desc)(int subtest);
+       } subtest;
 };
 
 /* Tests */
-int test__vmlinux_matches_kallsyms(void);
-int test__openat_syscall_event(void);
-int test__openat_syscall_event_on_all_cpus(void);
-int test__basic_mmap(void);
-int test__PERF_RECORD(void);
-int test__perf_evsel__roundtrip_name_test(void);
-int test__perf_evsel__tp_sched_test(void);
-int test__syscall_openat_tp_fields(void);
-int test__pmu(void);
-int test__attr(void);
-int test__dso_data(void);
-int test__dso_data_cache(void);
-int test__dso_data_reopen(void);
-int test__parse_events(void);
-int test__hists_link(void);
-int test__python_use(void);
-int test__bp_signal(void);
-int test__bp_signal_overflow(void);
-int test__task_exit(void);
-int test__sw_clock_freq(void);
-int test__code_reading(void);
-int test__sample_parsing(void);
-int test__keep_tracking(void);
-int test__parse_no_sample_id_all(void);
-int test__dwarf_unwind(void);
-int test__hists_filter(void);
-int test__mmap_thread_lookup(void);
-int test__thread_mg_share(void);
-int test__hists_output(void);
-int test__hists_cumulate(void);
-int test__switch_tracking(void);
-int test__fdarray__filter(void);
-int test__fdarray__add(void);
-int test__kmod_path__parse(void);
-int test__thread_map(void);
-int test__llvm(void);
-int test__bpf(void);
-int test_session_topology(void);
+int test__vmlinux_matches_kallsyms(int subtest);
+int test__openat_syscall_event(int subtest);
+int test__openat_syscall_event_on_all_cpus(int subtest);
+int test__basic_mmap(int subtest);
+int test__PERF_RECORD(int subtest);
+int test__perf_evsel__roundtrip_name_test(int subtest);
+int test__perf_evsel__tp_sched_test(int subtest);
+int test__syscall_openat_tp_fields(int subtest);
+int test__pmu(int subtest);
+int test__attr(int subtest);
+int test__dso_data(int subtest);
+int test__dso_data_cache(int subtest);
+int test__dso_data_reopen(int subtest);
+int test__parse_events(int subtest);
+int test__hists_link(int subtest);
+int test__python_use(int subtest);
+int test__bp_signal(int subtest);
+int test__bp_signal_overflow(int subtest);
+int test__task_exit(int subtest);
+int test__sw_clock_freq(int subtest);
+int test__code_reading(int subtest);
+int test__sample_parsing(int subtest);
+int test__keep_tracking(int subtest);
+int test__parse_no_sample_id_all(int subtest);
+int test__dwarf_unwind(int subtest);
+int test__hists_filter(int subtest);
+int test__mmap_thread_lookup(int subtest);
+int test__thread_mg_share(int subtest);
+int test__hists_output(int subtest);
+int test__hists_cumulate(int subtest);
+int test__switch_tracking(int subtest);
+int test__fdarray__filter(int subtest);
+int test__fdarray__add(int subtest);
+int test__kmod_path__parse(int subtest);
+int test__thread_map(int subtest);
+int test__llvm(int subtest);
+const char *test__llvm_subtest_get_desc(int subtest);
+int test__llvm_subtest_get_nr(void);
+int test__bpf(int subtest);
+const char *test__bpf_subtest_get_desc(int subtest);
+int test__bpf_subtest_get_nr(void);
+int test_session_topology(int subtest);
+int test__thread_map_synthesize(int subtest);
+int test__cpu_map_synthesize(int subtest);
+int test__synthesize_stat_config(int subtest);
+int test__synthesize_stat(int subtest);
+int test__synthesize_stat_round(int subtest);
+int test__event_update(int subtest);
 
 #if defined(__arm__) || defined(__aarch64__)
 #ifdef HAVE_DWARF_UNWIND_SUPPORT
index 138a0e3431fafd7ae0b6441fa24b7845f7b51ea0..fccde848fe9c0d0d67f1d6081b7e09ed7fc05610 100644 (file)
@@ -4,7 +4,7 @@
 #include "thread_map.h"
 #include "debug.h"
 
-int test__thread_map(void)
+int test__thread_map(int subtest __maybe_unused)
 {
        struct thread_map *map;
 
@@ -40,3 +40,46 @@ int test__thread_map(void)
        thread_map__put(map);
        return 0;
 }
+
+static int process_event(struct perf_tool *tool __maybe_unused,
+                        union perf_event *event,
+                        struct perf_sample *sample __maybe_unused,
+                        struct machine *machine __maybe_unused)
+{
+       struct thread_map_event *map = &event->thread_map;
+       struct thread_map *threads;
+
+       TEST_ASSERT_VAL("wrong nr",   map->nr == 1);
+       TEST_ASSERT_VAL("wrong pid",  map->entries[0].pid == (u64) getpid());
+       TEST_ASSERT_VAL("wrong comm", !strcmp(map->entries[0].comm, "perf"));
+
+       threads = thread_map__new_event(&event->thread_map);
+       TEST_ASSERT_VAL("failed to alloc map", threads);
+
+       TEST_ASSERT_VAL("wrong nr", threads->nr == 1);
+       TEST_ASSERT_VAL("wrong pid",
+                       thread_map__pid(threads, 0) == getpid());
+       TEST_ASSERT_VAL("wrong comm",
+                       thread_map__comm(threads, 0) &&
+                       !strcmp(thread_map__comm(threads, 0), "perf"));
+       TEST_ASSERT_VAL("wrong refcnt",
+                       atomic_read(&threads->refcnt) == 1);
+       thread_map__put(threads);
+       return 0;
+}
+
+int test__thread_map_synthesize(int subtest __maybe_unused)
+{
+       struct thread_map *threads;
+
+       /* test map on current pid */
+       threads = thread_map__new_by_pid(getpid());
+       TEST_ASSERT_VAL("failed to alloc map", threads);
+
+       thread_map__read_comms(threads);
+
+       TEST_ASSERT_VAL("failed to synthesize map",
+               !perf_event__synthesize_thread_map2(NULL, threads, process_event, NULL));
+
+       return 0;
+}
index 01fabb19d74607bb9157f0dbddfd160d21c8cebf..188b63140fc841f8c3111d20439b78d7f73133db 100644 (file)
@@ -4,7 +4,7 @@
 #include "map.h"
 #include "debug.h"
 
-int test__thread_mg_share(void)
+int test__thread_mg_share(int subtest __maybe_unused)
 {
        struct machines machines;
        struct machine *machine;
index f5bb096c3bd9704d2996468d0da490b4226b5c51..98fe69ac553c8462f4fe1dcbf610ff67e3c54948 100644 (file)
@@ -84,7 +84,7 @@ static int check_cpu_topology(char *path, struct cpu_map *map)
        return 0;
 }
 
-int test_session_topology(void)
+int test_session_topology(int subtest __maybe_unused)
 {
        char path[PATH_MAX];
        struct cpu_map *map;
index d677e018e50426a8b2c2b417a63b8dfbe36949b7..f0bfc9e8fd9f617d69c0b3cb36fe6c210ebbd6d5 100644 (file)
@@ -18,7 +18,7 @@ static int vmlinux_matches_kallsyms_filter(struct map *map __maybe_unused,
 
 #define UM(x) kallsyms_map->unmap_ip(kallsyms_map, (x))
 
-int test__vmlinux_matches_kallsyms(void)
+int test__vmlinux_matches_kallsyms(int subtest __maybe_unused)
 {
        int err = -1;
        struct rb_node *nd;
index e9703c0829f104bf9d7819d04831306cfd31dbe8..d37202121689a017b0790d552e088d695716c527 100644 (file)
@@ -528,7 +528,7 @@ static struct ui_browser_colorset {
                .colorset = HE_COLORSET_SELECTED,
                .name     = "selected",
                .fg       = "black",
-               .bg       = "lightgray",
+               .bg       = "yellow",
        },
        {
                .colorset = HE_COLORSET_CODE,
index fa9eb92c9e24a477e45623c1017a2791fc68dd07..901d481e6cea589a3e29675a5124b05434a94eb7 100644 (file)
@@ -178,12 +178,51 @@ static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
        return n;
 }
 
+static int callchain_node__count_flat_rows(struct callchain_node *node)
+{
+       struct callchain_list *chain;
+       char folded_sign = 0;
+       int n = 0;
+
+       list_for_each_entry(chain, &node->parent_val, list) {
+               if (!folded_sign) {
+                       /* only check first chain list entry */
+                       folded_sign = callchain_list__folded(chain);
+                       if (folded_sign == '+')
+                               return 1;
+               }
+               n++;
+       }
+
+       list_for_each_entry(chain, &node->val, list) {
+               if (!folded_sign) {
+                       /* node->parent_val list might be empty */
+                       folded_sign = callchain_list__folded(chain);
+                       if (folded_sign == '+')
+                               return 1;
+               }
+               n++;
+       }
+
+       return n;
+}
+
+static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
+{
+       return 1;
+}
+
 static int callchain_node__count_rows(struct callchain_node *node)
 {
        struct callchain_list *chain;
        bool unfolded = false;
        int n = 0;
 
+       if (callchain_param.mode == CHAIN_FLAT)
+               return callchain_node__count_flat_rows(node);
+       else if (callchain_param.mode == CHAIN_FOLDED)
+               return callchain_node__count_folded_rows(node);
+
        list_for_each_entry(chain, &node->val, list) {
                ++n;
                unfolded = chain->unfolded;
@@ -263,7 +302,7 @@ static void callchain_node__init_have_children(struct callchain_node *node,
        chain = list_entry(node->val.next, struct callchain_list, list);
        chain->has_children = has_sibling;
 
-       if (!list_empty(&node->val)) {
+       if (node->val.next != node->val.prev) {
                chain = list_entry(node->val.prev, struct callchain_list, list);
                chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
        }
@@ -279,6 +318,9 @@ static void callchain__init_have_children(struct rb_root *root)
        for (nd = rb_first(root); nd; nd = rb_next(nd)) {
                struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
                callchain_node__init_have_children(node, has_sibling);
+               if (callchain_param.mode == CHAIN_FLAT ||
+                   callchain_param.mode == CHAIN_FOLDED)
+                       callchain_node__make_parent_list(node);
        }
 }
 
@@ -298,6 +340,9 @@ static bool hist_browser__toggle_fold(struct hist_browser *browser)
        struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
        bool has_children;
 
+       if (!he || !ms)
+               return false;
+
        if (ms == &he->ms)
                has_children = hist_entry__toggle_fold(he);
        else
@@ -574,6 +619,231 @@ static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_u
 
 #define LEVEL_OFFSET_STEP 3
 
+static int hist_browser__show_callchain_list(struct hist_browser *browser,
+                                            struct callchain_node *node,
+                                            struct callchain_list *chain,
+                                            unsigned short row, u64 total,
+                                            bool need_percent, int offset,
+                                            print_callchain_entry_fn print,
+                                            struct callchain_print_arg *arg)
+{
+       char bf[1024], *alloc_str;
+       const char *str;
+
+       if (arg->row_offset != 0) {
+               arg->row_offset--;
+               return 0;
+       }
+
+       alloc_str = NULL;
+       str = callchain_list__sym_name(chain, bf, sizeof(bf),
+                                      browser->show_dso);
+
+       if (need_percent) {
+               char buf[64];
+
+               callchain_node__scnprintf_value(node, buf, sizeof(buf),
+                                               total);
+
+               if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
+                       str = "Not enough memory!";
+               else
+                       str = alloc_str;
+       }
+
+       print(browser, chain, str, offset, row, arg);
+
+       free(alloc_str);
+       return 1;
+}
+
+static int hist_browser__show_callchain_flat(struct hist_browser *browser,
+                                            struct rb_root *root,
+                                            unsigned short row, u64 total,
+                                            print_callchain_entry_fn print,
+                                            struct callchain_print_arg *arg,
+                                            check_output_full_fn is_output_full)
+{
+       struct rb_node *node;
+       int first_row = row, offset = LEVEL_OFFSET_STEP;
+       bool need_percent;
+
+       node = rb_first(root);
+       need_percent = node && rb_next(node);
+
+       while (node) {
+               struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
+               struct rb_node *next = rb_next(node);
+               struct callchain_list *chain;
+               char folded_sign = ' ';
+               int first = true;
+               int extra_offset = 0;
+
+               list_for_each_entry(chain, &child->parent_val, list) {
+                       bool was_first = first;
+
+                       if (first)
+                               first = false;
+                       else if (need_percent)
+                               extra_offset = LEVEL_OFFSET_STEP;
+
+                       folded_sign = callchain_list__folded(chain);
+
+                       row += hist_browser__show_callchain_list(browser, child,
+                                                       chain, row, total,
+                                                       was_first && need_percent,
+                                                       offset + extra_offset,
+                                                       print, arg);
+
+                       if (is_output_full(browser, row))
+                               goto out;
+
+                       if (folded_sign == '+')
+                               goto next;
+               }
+
+               list_for_each_entry(chain, &child->val, list) {
+                       bool was_first = first;
+
+                       if (first)
+                               first = false;
+                       else if (need_percent)
+                               extra_offset = LEVEL_OFFSET_STEP;
+
+                       folded_sign = callchain_list__folded(chain);
+
+                       row += hist_browser__show_callchain_list(browser, child,
+                                                       chain, row, total,
+                                                       was_first && need_percent,
+                                                       offset + extra_offset,
+                                                       print, arg);
+
+                       if (is_output_full(browser, row))
+                               goto out;
+
+                       if (folded_sign == '+')
+                               break;
+               }
+
+next:
+               if (is_output_full(browser, row))
+                       break;
+               node = next;
+       }
+out:
+       return row - first_row;
+}
+
+static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
+                                               struct callchain_list *chain,
+                                               char *value_str, char *old_str)
+{
+       char bf[1024];
+       const char *str;
+       char *new;
+
+       str = callchain_list__sym_name(chain, bf, sizeof(bf),
+                                      browser->show_dso);
+       if (old_str) {
+               if (asprintf(&new, "%s%s%s", old_str,
+                            symbol_conf.field_sep ?: ";", str) < 0)
+                       new = NULL;
+       } else {
+               if (value_str) {
+                       if (asprintf(&new, "%s %s", value_str, str) < 0)
+                               new = NULL;
+               } else {
+                       if (asprintf(&new, "%s", str) < 0)
+                               new = NULL;
+               }
+       }
+       return new;
+}
+
+static int hist_browser__show_callchain_folded(struct hist_browser *browser,
+                                              struct rb_root *root,
+                                              unsigned short row, u64 total,
+                                              print_callchain_entry_fn print,
+                                              struct callchain_print_arg *arg,
+                                              check_output_full_fn is_output_full)
+{
+       struct rb_node *node;
+       int first_row = row, offset = LEVEL_OFFSET_STEP;
+       bool need_percent;
+
+       node = rb_first(root);
+       need_percent = node && rb_next(node);
+
+       while (node) {
+               struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
+               struct rb_node *next = rb_next(node);
+               struct callchain_list *chain, *first_chain = NULL;
+               int first = true;
+               char *value_str = NULL, *value_str_alloc = NULL;
+               char *chain_str = NULL, *chain_str_alloc = NULL;
+
+               if (arg->row_offset != 0) {
+                       arg->row_offset--;
+                       goto next;
+               }
+
+               if (need_percent) {
+                       char buf[64];
+
+                       callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
+                       if (asprintf(&value_str, "%s", buf) < 0) {
+                               value_str = (char *)"<...>";
+                               goto do_print;
+                       }
+                       value_str_alloc = value_str;
+               }
+
+               list_for_each_entry(chain, &child->parent_val, list) {
+                       chain_str = hist_browser__folded_callchain_str(browser,
+                                               chain, value_str, chain_str);
+                       if (first) {
+                               first = false;
+                               first_chain = chain;
+                       }
+
+                       if (chain_str == NULL) {
+                               chain_str = (char *)"Not enough memory!";
+                               goto do_print;
+                       }
+
+                       chain_str_alloc = chain_str;
+               }
+
+               list_for_each_entry(chain, &child->val, list) {
+                       chain_str = hist_browser__folded_callchain_str(browser,
+                                               chain, value_str, chain_str);
+                       if (first) {
+                               first = false;
+                               first_chain = chain;
+                       }
+
+                       if (chain_str == NULL) {
+                               chain_str = (char *)"Not enough memory!";
+                               goto do_print;
+                       }
+
+                       chain_str_alloc = chain_str;
+               }
+
+do_print:
+               print(browser, first_chain, chain_str, offset, row++, arg);
+               free(value_str_alloc);
+               free(chain_str_alloc);
+
+next:
+               if (is_output_full(browser, row))
+                       break;
+               node = next;
+       }
+
+       return row - first_row;
+}
+
 static int hist_browser__show_callchain(struct hist_browser *browser,
                                        struct rb_root *root, int level,
                                        unsigned short row, u64 total,
@@ -592,15 +862,12 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
        while (node) {
                struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
                struct rb_node *next = rb_next(node);
-               u64 cumul = callchain_cumul_hits(child);
                struct callchain_list *chain;
                char folded_sign = ' ';
                int first = true;
                int extra_offset = 0;
 
                list_for_each_entry(chain, &child->val, list) {
-                       char bf[1024], *alloc_str;
-                       const char *str;
                        bool was_first = first;
 
                        if (first)
@@ -609,31 +876,16 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
                                extra_offset = LEVEL_OFFSET_STEP;
 
                        folded_sign = callchain_list__folded(chain);
-                       if (arg->row_offset != 0) {
-                               arg->row_offset--;
-                               goto do_next;
-                       }
-
-                       alloc_str = NULL;
-                       str = callchain_list__sym_name(chain, bf, sizeof(bf),
-                                                      browser->show_dso);
-
-                       if (was_first && need_percent) {
-                               double percent = cumul * 100.0 / total;
 
-                               if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
-                                       str = "Not enough memory!";
-                               else
-                                       str = alloc_str;
-                       }
-
-                       print(browser, chain, str, offset + extra_offset, row, arg);
+                       row += hist_browser__show_callchain_list(browser, child,
+                                                       chain, row, total,
+                                                       was_first && need_percent,
+                                                       offset + extra_offset,
+                                                       print, arg);
 
-                       free(alloc_str);
-
-                       if (is_output_full(browser, ++row))
+                       if (is_output_full(browser, row))
                                goto out;
-do_next:
+
                        if (folded_sign == '+')
                                break;
                }
@@ -789,7 +1041,8 @@ static int hist_browser__show_entry(struct hist_browser *browser,
                hist_browser__gotorc(browser, row, 0);
 
                perf_hpp__for_each_format(fmt) {
-                       if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll)
+                       if (perf_hpp__should_skip(fmt, entry->hists) ||
+                           column++ < browser->b.horiz_scroll)
                                continue;
 
                        if (current_entry && browser->b.navkeypressed) {
@@ -844,10 +1097,22 @@ static int hist_browser__show_entry(struct hist_browser *browser,
                                total = entry->stat.period;
                }
 
-               printed += hist_browser__show_callchain(browser,
+               if (callchain_param.mode == CHAIN_FLAT) {
+                       printed += hist_browser__show_callchain_flat(browser,
+                                       &entry->sorted_chain, row, total,
+                                       hist_browser__show_callchain_entry, &arg,
+                                       hist_browser__check_output_full);
+               } else if (callchain_param.mode == CHAIN_FOLDED) {
+                       printed += hist_browser__show_callchain_folded(browser,
+                                       &entry->sorted_chain, row, total,
+                                       hist_browser__show_callchain_entry, &arg,
+                                       hist_browser__check_output_full);
+               } else {
+                       printed += hist_browser__show_callchain(browser,
                                        &entry->sorted_chain, 1, row, total,
                                        hist_browser__show_callchain_entry, &arg,
                                        hist_browser__check_output_full);
+               }
 
                if (arg.is_current_entry)
                        browser->he_selection = entry;
@@ -880,7 +1145,7 @@ static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *
        }
 
        perf_hpp__for_each_format(fmt) {
-               if (perf_hpp__should_skip(fmt)  || column++ < browser->b.horiz_scroll)
+               if (perf_hpp__should_skip(fmt, hists)  || column++ < browser->b.horiz_scroll)
                        continue;
 
                ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
@@ -928,6 +1193,8 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
        }
 
        ui_browser__hists_init_top(browser);
+       hb->he_selection = NULL;
+       hb->selection = NULL;
 
        for (nd = browser->top; nd; nd = rb_next(nd)) {
                struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
@@ -1033,6 +1300,9 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
         * and stop when we printed enough lines to fill the screen.
         */
 do_offset:
+       if (!nd)
+               return;
+
        if (offset > 0) {
                do {
                        h = rb_entry(nd, struct hist_entry, rb_node);
@@ -1145,7 +1415,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
                printed += fprintf(fp, "%c ", folded_sign);
 
        perf_hpp__for_each_format(fmt) {
-               if (perf_hpp__should_skip(fmt))
+               if (perf_hpp__should_skip(fmt, he->hists))
                        continue;
 
                if (!first) {
@@ -1794,10 +2064,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
        SLang_reset_tty();
        SLang_init_tty(0, 0, 0);
 
-       if (min_pcnt) {
+       if (min_pcnt)
                browser->min_pcnt = min_pcnt;
-               hist_browser__update_nr_entries(browser);
-       }
+       hist_browser__update_nr_entries(browser);
 
        browser->pstack = pstack__new(3);
        if (browser->pstack == NULL)
index 4b3585eed1e84be6feb0243f4f9f0cbd7e1ef592..0f8dcfdfb10f3856abefc7f252631e8937bacf6b 100644 (file)
@@ -89,8 +89,8 @@ void perf_gtk__init_hpp(void)
                                perf_gtk__hpp_color_overhead_acc;
 }
 
-static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
-                                   GtkTreeIter *parent, int col, u64 total)
+static void perf_gtk__add_callchain_flat(struct rb_root *root, GtkTreeStore *store,
+                                        GtkTreeIter *parent, int col, u64 total)
 {
        struct rb_node *nd;
        bool has_single_node = (rb_first(root) == rb_last(root));
@@ -100,13 +100,132 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
                struct callchain_list *chain;
                GtkTreeIter iter, new_parent;
                bool need_new_parent;
-               double percent;
-               u64 hits, child_total;
 
                node = rb_entry(nd, struct callchain_node, rb_node);
 
-               hits = callchain_cumul_hits(node);
-               percent = 100.0 * hits / total;
+               new_parent = *parent;
+               need_new_parent = !has_single_node;
+
+               callchain_node__make_parent_list(node);
+
+               list_for_each_entry(chain, &node->parent_val, list) {
+                       char buf[128];
+
+                       gtk_tree_store_append(store, &iter, &new_parent);
+
+                       callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
+                       gtk_tree_store_set(store, &iter, 0, buf, -1);
+
+                       callchain_list__sym_name(chain, buf, sizeof(buf), false);
+                       gtk_tree_store_set(store, &iter, col, buf, -1);
+
+                       if (need_new_parent) {
+                               /*
+                                * Only show the top-most symbol in a callchain
+                                * if it's not the only callchain.
+                                */
+                               new_parent = iter;
+                               need_new_parent = false;
+                       }
+               }
+
+               list_for_each_entry(chain, &node->val, list) {
+                       char buf[128];
+
+                       gtk_tree_store_append(store, &iter, &new_parent);
+
+                       callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
+                       gtk_tree_store_set(store, &iter, 0, buf, -1);
+
+                       callchain_list__sym_name(chain, buf, sizeof(buf), false);
+                       gtk_tree_store_set(store, &iter, col, buf, -1);
+
+                       if (need_new_parent) {
+                               /*
+                                * Only show the top-most symbol in a callchain
+                                * if it's not the only callchain.
+                                */
+                               new_parent = iter;
+                               need_new_parent = false;
+                       }
+               }
+       }
+}
+
+static void perf_gtk__add_callchain_folded(struct rb_root *root, GtkTreeStore *store,
+                                          GtkTreeIter *parent, int col, u64 total)
+{
+       struct rb_node *nd;
+
+       for (nd = rb_first(root); nd; nd = rb_next(nd)) {
+               struct callchain_node *node;
+               struct callchain_list *chain;
+               GtkTreeIter iter;
+               char buf[64];
+               char *str, *str_alloc = NULL;
+               bool first = true;
+
+               node = rb_entry(nd, struct callchain_node, rb_node);
+
+               callchain_node__make_parent_list(node);
+
+               list_for_each_entry(chain, &node->parent_val, list) {
+                       char name[1024];
+
+                       callchain_list__sym_name(chain, name, sizeof(name), false);
+
+                       if (asprintf(&str, "%s%s%s",
+                                    first ? "" : str_alloc,
+                                    first ? "" : symbol_conf.field_sep ?: "; ",
+                                    name) < 0)
+                               return;
+
+                       first = false;
+                       free(str_alloc);
+                       str_alloc = str;
+               }
+
+               list_for_each_entry(chain, &node->val, list) {
+                       char name[1024];
+
+                       callchain_list__sym_name(chain, name, sizeof(name), false);
+
+                       if (asprintf(&str, "%s%s%s",
+                                    first ? "" : str_alloc,
+                                    first ? "" : symbol_conf.field_sep ?: "; ",
+                                    name) < 0)
+                               return;
+
+                       first = false;
+                       free(str_alloc);
+                       str_alloc = str;
+               }
+
+               gtk_tree_store_append(store, &iter, parent);
+
+               callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
+               gtk_tree_store_set(store, &iter, 0, buf, -1);
+
+               gtk_tree_store_set(store, &iter, col, str, -1);
+
+               free(str_alloc);
+       }
+}
+
+static void perf_gtk__add_callchain_graph(struct rb_root *root, GtkTreeStore *store,
+                                         GtkTreeIter *parent, int col, u64 total)
+{
+       struct rb_node *nd;
+       bool has_single_node = (rb_first(root) == rb_last(root));
+
+       for (nd = rb_first(root); nd; nd = rb_next(nd)) {
+               struct callchain_node *node;
+               struct callchain_list *chain;
+               GtkTreeIter iter, new_parent;
+               bool need_new_parent;
+               u64 child_total;
+
+               node = rb_entry(nd, struct callchain_node, rb_node);
 
                new_parent = *parent;
                need_new_parent = !has_single_node && (node->val_nr > 1);
@@ -116,7 +235,7 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
 
                        gtk_tree_store_append(store, &iter, &new_parent);
 
-                       scnprintf(buf, sizeof(buf), "%5.2f%%", percent);
+                       callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
                        gtk_tree_store_set(store, &iter, 0, buf, -1);
 
                        callchain_list__sym_name(chain, buf, sizeof(buf), false);
@@ -138,11 +257,22 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
                        child_total = total;
 
                /* Now 'iter' contains info of the last callchain_list */
-               perf_gtk__add_callchain(&node->rb_root, store, &iter, col,
-                                       child_total);
+               perf_gtk__add_callchain_graph(&node->rb_root, store, &iter, col,
+                                             child_total);
        }
 }
 
+static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
+                                   GtkTreeIter *parent, int col, u64 total)
+{
+       if (callchain_param.mode == CHAIN_FLAT)
+               perf_gtk__add_callchain_flat(root, store, parent, col, total);
+       else if (callchain_param.mode == CHAIN_FOLDED)
+               perf_gtk__add_callchain_folded(root, store, parent, col, total);
+       else
+               perf_gtk__add_callchain_graph(root, store, parent, col, total);
+}
+
 static void on_row_activated(GtkTreeView *view, GtkTreePath *path,
                             GtkTreeViewColumn *col __maybe_unused,
                             gpointer user_data __maybe_unused)
@@ -188,7 +318,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
        col_idx = 0;
 
        perf_hpp__for_each_format(fmt) {
-               if (perf_hpp__should_skip(fmt))
+               if (perf_hpp__should_skip(fmt, hists))
                        continue;
 
                /*
@@ -238,7 +368,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
                col_idx = 0;
 
                perf_hpp__for_each_format(fmt) {
-                       if (perf_hpp__should_skip(fmt))
+                       if (perf_hpp__should_skip(fmt, h->hists))
                                continue;
 
                        if (fmt->color)
index 5029ba2b55af0cb20daaeec875d1f493dc807e62..bf2a66e254eac35c63a0dd44e83628f34e4dc2f9 100644 (file)
@@ -443,7 +443,6 @@ LIST_HEAD(perf_hpp__sort_list);
 
 void perf_hpp__init(void)
 {
-       struct list_head *list;
        int i;
 
        for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
@@ -484,17 +483,6 @@ void perf_hpp__init(void)
 
        if (symbol_conf.show_total_period)
                hpp_dimension__add_output(PERF_HPP__PERIOD);
-
-       /* prepend overhead field for backward compatiblity.  */
-       list = &perf_hpp__format[PERF_HPP__OVERHEAD].sort_list;
-       if (list_empty(list))
-               list_add(list, &perf_hpp__sort_list);
-
-       if (symbol_conf.cumulate_callchain) {
-               list = &perf_hpp__format[PERF_HPP__OVERHEAD_ACC].sort_list;
-               if (list_empty(list))
-                       list_add(list, &perf_hpp__sort_list);
-       }
 }
 
 void perf_hpp__column_register(struct perf_hpp_fmt *format)
@@ -619,7 +607,7 @@ unsigned int hists__sort_list_width(struct hists *hists)
        struct perf_hpp dummy_hpp;
 
        perf_hpp__for_each_format(fmt) {
-               if (perf_hpp__should_skip(fmt))
+               if (perf_hpp__should_skip(fmt, hists))
                        continue;
 
                if (first)
index dfcbc90146ef0227bcdd19faca44c5890c823e26..387110d50b002557d99e723605407c3db990d71a 100644 (file)
@@ -34,10 +34,10 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
        return ret;
 }
 
-static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
+static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node,
+                                    struct callchain_list *chain,
                                     int depth, int depth_mask, int period,
-                                    u64 total_samples, u64 hits,
-                                    int left_margin)
+                                    u64 total_samples, int left_margin)
 {
        int i;
        size_t ret = 0;
@@ -50,10 +50,9 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
                else
                        ret += fprintf(fp, " ");
                if (!period && i == depth - 1) {
-                       double percent;
-
-                       percent = hits * 100.0 / total_samples;
-                       ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
+                       ret += fprintf(fp, "--");
+                       ret += callchain_node__fprintf_value(node, fp, total_samples);
+                       ret += fprintf(fp, "--");
                } else
                        ret += fprintf(fp, "%s", "          ");
        }
@@ -82,13 +81,14 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
                                         int depth_mask, int left_margin)
 {
        struct rb_node *node, *next;
-       struct callchain_node *child;
+       struct callchain_node *child = NULL;
        struct callchain_list *chain;
        int new_depth_mask = depth_mask;
        u64 remaining;
        size_t ret = 0;
        int i;
        uint entries_printed = 0;
+       int cumul_count = 0;
 
        remaining = total_samples;
 
@@ -100,6 +100,7 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
                child = rb_entry(node, struct callchain_node, rb_node);
                cumul = callchain_cumul_hits(child);
                remaining -= cumul;
+               cumul_count += callchain_cumul_counts(child);
 
                /*
                 * The depth mask manages the output of pipes that show
@@ -120,10 +121,9 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
                                                   left_margin);
                i = 0;
                list_for_each_entry(chain, &child->val, list) {
-                       ret += ipchain__fprintf_graph(fp, chain, depth,
+                       ret += ipchain__fprintf_graph(fp, child, chain, depth,
                                                      new_depth_mask, i++,
                                                      total_samples,
-                                                     cumul,
                                                      left_margin);
                }
 
@@ -143,14 +143,23 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
 
        if (callchain_param.mode == CHAIN_GRAPH_REL &&
                remaining && remaining != total_samples) {
+               struct callchain_node rem_node = {
+                       .hit = remaining,
+               };
 
                if (!rem_sq_bracket)
                        return ret;
 
+               if (callchain_param.value == CCVAL_COUNT && child && child->parent) {
+                       rem_node.count = child->parent->children_count - cumul_count;
+                       if (rem_node.count <= 0)
+                               return ret;
+               }
+
                new_depth_mask &= ~(1 << (depth - 1));
-               ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
+               ret += ipchain__fprintf_graph(fp, &rem_node, &rem_hits, depth,
                                              new_depth_mask, 0, total_samples,
-                                             remaining, left_margin);
+                                             left_margin);
        }
 
        return ret;
@@ -243,12 +252,11 @@ static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree,
        struct rb_node *rb_node = rb_first(tree);
 
        while (rb_node) {
-               double percent;
-
                chain = rb_entry(rb_node, struct callchain_node, rb_node);
-               percent = chain->hit * 100.0 / total_samples;
 
-               ret = percent_color_fprintf(fp, "           %6.2f%%\n", percent);
+               ret += fprintf(fp, "           ");
+               ret += callchain_node__fprintf_value(chain, fp, total_samples);
+               ret += fprintf(fp, "\n");
                ret += __callchain__fprintf_flat(fp, chain, total_samples);
                ret += fprintf(fp, "\n");
                if (++entries_printed == callchain_param.print_limit)
@@ -260,6 +268,57 @@ static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree,
        return ret;
 }
 
+static size_t __callchain__fprintf_folded(FILE *fp, struct callchain_node *node)
+{
+       const char *sep = symbol_conf.field_sep ?: ";";
+       struct callchain_list *chain;
+       size_t ret = 0;
+       char bf[1024];
+       bool first;
+
+       if (!node)
+               return 0;
+
+       ret += __callchain__fprintf_folded(fp, node->parent);
+
+       first = (ret == 0);
+       list_for_each_entry(chain, &node->val, list) {
+               if (chain->ip >= PERF_CONTEXT_MAX)
+                       continue;
+               ret += fprintf(fp, "%s%s", first ? "" : sep,
+                              callchain_list__sym_name(chain,
+                                               bf, sizeof(bf), false));
+               first = false;
+       }
+
+       return ret;
+}
+
+static size_t callchain__fprintf_folded(FILE *fp, struct rb_root *tree,
+                                       u64 total_samples)
+{
+       size_t ret = 0;
+       u32 entries_printed = 0;
+       struct callchain_node *chain;
+       struct rb_node *rb_node = rb_first(tree);
+
+       while (rb_node) {
+
+               chain = rb_entry(rb_node, struct callchain_node, rb_node);
+
+               ret += callchain_node__fprintf_value(chain, fp, total_samples);
+               ret += fprintf(fp, " ");
+               ret += __callchain__fprintf_folded(fp, chain);
+               ret += fprintf(fp, "\n");
+               if (++entries_printed == callchain_param.print_limit)
+                       break;
+
+               rb_node = rb_next(rb_node);
+       }
+
+       return ret;
+}
+
 static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
                                            u64 total_samples, int left_margin,
                                            FILE *fp)
@@ -278,6 +337,9 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
        case CHAIN_FLAT:
                return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
                break;
+       case CHAIN_FOLDED:
+               return callchain__fprintf_folded(fp, &he->sorted_chain, total_samples);
+               break;
        case CHAIN_NONE:
                break;
        default:
@@ -323,7 +385,7 @@ static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
                return 0;
 
        perf_hpp__for_each_format(fmt) {
-               if (perf_hpp__should_skip(fmt))
+               if (perf_hpp__should_skip(fmt, he->hists))
                        continue;
 
                /*
@@ -402,7 +464,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
        fprintf(fp, "# ");
 
        perf_hpp__for_each_format(fmt) {
-               if (perf_hpp__should_skip(fmt))
+               if (perf_hpp__should_skip(fmt, hists))
                        continue;
 
                if (!first)
@@ -428,7 +490,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
        perf_hpp__for_each_format(fmt) {
                unsigned int i;
 
-               if (perf_hpp__should_skip(fmt))
+               if (perf_hpp__should_skip(fmt, hists))
                        continue;
 
                if (!first)
index 591b3fe3ed49acd8b31f701a78b3302a84786546..5eec53a3f4ac7dbedb54776f746705acfa4fa2b4 100644 (file)
@@ -6,24 +6,20 @@ libperf-y += config.o
 libperf-y += ctype.o
 libperf-y += db-export.o
 libperf-y += env.o
-libperf-y += environment.o
 libperf-y += event.o
 libperf-y += evlist.o
 libperf-y += evsel.o
-libperf-y += exec_cmd.o
-libperf-y += find_next_bit.o
-libperf-y += help.o
+libperf-y += find_bit.o
 libperf-y += kallsyms.o
 libperf-y += levenshtein.o
 libperf-y += llvm-utils.o
-libperf-y += parse-options.o
 libperf-y += parse-events.o
 libperf-y += perf_regs.o
 libperf-y += path.o
 libperf-y += rbtree.o
+libperf-y += libstring.o
 libperf-y += bitmap.o
 libperf-y += hweight.o
-libperf-y += run-command.o
 libperf-y += quote.o
 libperf-y += strbuf.o
 libperf-y += string.o
@@ -32,11 +28,9 @@ libperf-y += strfilter.o
 libperf-y += top.o
 libperf-y += usage.o
 libperf-y += wrapper.o
-libperf-y += sigchain.o
 libperf-y += dso.o
 libperf-y += symbol.o
 libperf-y += color.o
-libperf-y += pager.o
 libperf-y += header.o
 libperf-y += callchain.o
 libperf-y += values.o
@@ -86,8 +80,11 @@ libperf-$(CONFIG_AUXTRACE) += intel-pt.o
 libperf-$(CONFIG_AUXTRACE) += intel-bts.o
 libperf-y += parse-branch-options.o
 libperf-y += parse-regs-options.o
+libperf-y += term.o
+libperf-y += help-unknown-cmd.o
 
 libperf-$(CONFIG_LIBBPF) += bpf-loader.o
+libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o
 libperf-$(CONFIG_LIBELF) += symbol-elf.o
 libperf-$(CONFIG_LIBELF) += probe-file.o
 libperf-$(CONFIG_LIBELF) += probe-event.o
@@ -110,7 +107,6 @@ libperf-$(CONFIG_ZLIB) += zlib.o
 libperf-$(CONFIG_LZMA) += lzma.o
 
 CFLAGS_config.o   += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
-CFLAGS_exec_cmd.o += -DPERF_EXEC_PATH="BUILD_STR($(perfexecdir_SQ))" -DPREFIX="BUILD_STR($(prefix_SQ))"
 
 $(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
        $(call rule_mkdir)
@@ -136,8 +132,10 @@ CFLAGS_pmu-bison.o          += -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w
 $(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
 $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
 
-CFLAGS_find_next_bit.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
+CFLAGS_bitmap.o        += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
+CFLAGS_find_bit.o      += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
 CFLAGS_rbtree.o        += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
+CFLAGS_libstring.o     += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
 CFLAGS_hweight.o       += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
 CFLAGS_parse-events.o  += -Wno-redundant-decls
 
@@ -145,7 +143,11 @@ $(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c FORCE
        $(call rule_mkdir)
        $(call if_changed_dep,cc_o_c)
 
-$(OUTPUT)util/find_next_bit.o: ../lib/util/find_next_bit.c FORCE
+$(OUTPUT)util/bitmap.o: ../lib/bitmap.c FORCE
+       $(call rule_mkdir)
+       $(call if_changed_dep,cc_o_c)
+
+$(OUTPUT)util/find_bit.o: ../lib/find_bit.c FORCE
        $(call rule_mkdir)
        $(call if_changed_dep,cc_o_c)
 
@@ -153,6 +155,10 @@ $(OUTPUT)util/rbtree.o: ../lib/rbtree.c FORCE
        $(call rule_mkdir)
        $(call if_changed_dep,cc_o_c)
 
+$(OUTPUT)util/libstring.o: ../lib/string.c FORCE
+       $(call rule_mkdir)
+       $(call if_changed_dep,cc_o_c)
+
 $(OUTPUT)util/hweight.o: ../lib/hweight.c FORCE
        $(call rule_mkdir)
        $(call if_changed_dep,cc_o_c)
index 1dd1949b0e7995e43f0fa216fee0db583803ed5c..b795b6994144cc983d09d9c2422ab37888c2e44e 100644 (file)
@@ -65,6 +65,11 @@ static int call__parse(struct ins_operands *ops)
 
        name++;
 
+#ifdef __arm__
+       if (strchr(name, '+'))
+               return -1;
+#endif
+
        tok = strchr(name, '>');
        if (tok == NULL)
                return -1;
@@ -246,7 +251,11 @@ static int mov__parse(struct ins_operands *ops)
                return -1;
 
        target = ++s;
+#ifdef __arm__
+       comment = strchr(s, ';');
+#else
        comment = strchr(s, '#');
+#endif
 
        if (comment != NULL)
                s = comment - 1;
@@ -354,6 +363,20 @@ static struct ins instructions[] = {
        { .name = "addq",  .ops  = &mov_ops, },
        { .name = "addw",  .ops  = &mov_ops, },
        { .name = "and",   .ops  = &mov_ops, },
+#ifdef __arm__
+       { .name = "b",     .ops  = &jump_ops, }, // might also be a call
+       { .name = "bcc",   .ops  = &jump_ops, },
+       { .name = "bcs",   .ops  = &jump_ops, },
+       { .name = "beq",   .ops  = &jump_ops, },
+       { .name = "bge",   .ops  = &jump_ops, },
+       { .name = "bgt",   .ops  = &jump_ops, },
+       { .name = "bhi",   .ops  = &jump_ops, },
+       { .name = "bl",    .ops  = &call_ops, },
+       { .name = "blt",   .ops  = &jump_ops, },
+       { .name = "bls",   .ops  = &jump_ops, },
+       { .name = "blx",   .ops  = &call_ops, },
+       { .name = "bne",   .ops  = &jump_ops, },
+#endif
        { .name = "bts",   .ops  = &mov_ops, },
        { .name = "call",  .ops  = &call_ops, },
        { .name = "callq", .ops  = &call_ops, },
index 7f10430af39c3ac9e47f4da1aca93e37a8f9cf87..360fda01f3b0d17369254d03fe16daf24f30c698 100644 (file)
@@ -45,7 +45,7 @@
 #include "event.h"
 #include "session.h"
 #include "debug.h"
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
 
 #include "intel-pt.h"
 #include "intel-bts.h"
diff --git a/tools/perf/util/bitmap.c b/tools/perf/util/bitmap.c
deleted file mode 100644 (file)
index 0a1adc1..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * From lib/bitmap.c
- * Helper functions for bitmap.h.
- *
- * This source code is licensed under the GNU General Public License,
- * Version 2.  See the file COPYING for more details.
- */
-#include <linux/bitmap.h>
-
-int __bitmap_weight(const unsigned long *bitmap, int bits)
-{
-       int k, w = 0, lim = bits/BITS_PER_LONG;
-
-       for (k = 0; k < lim; k++)
-               w += hweight_long(bitmap[k]);
-
-       if (bits % BITS_PER_LONG)
-               w += hweight_long(bitmap[k] & BITMAP_LAST_WORD_MASK(bits));
-
-       return w;
-}
-
-void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
-                const unsigned long *bitmap2, int bits)
-{
-       int k;
-       int nr = BITS_TO_LONGS(bits);
-
-       for (k = 0; k < nr; k++)
-               dst[k] = bitmap1[k] | bitmap2[k];
-}
index 4c50411371db31208c361115331695571fe545b7..540a7efa657ea8668eeddf1b476bbcb3c0490bbc 100644 (file)
@@ -5,11 +5,15 @@
  * Copyright (C) 2015 Huawei Inc.
  */
 
+#include <linux/bpf.h>
 #include <bpf/libbpf.h>
 #include <linux/err.h>
+#include <linux/string.h>
 #include "perf.h"
 #include "debug.h"
 #include "bpf-loader.h"
+#include "bpf-prologue.h"
+#include "llvm-utils.h"
 #include "probe-event.h"
 #include "probe-finder.h" // for MAX_PROBES
 #include "llvm-utils.h"
@@ -32,6 +36,10 @@ DEFINE_PRINT_FN(debug, 1)
 
 struct bpf_prog_priv {
        struct perf_probe_event pev;
+       bool need_prologue;
+       struct bpf_insn *insns_buf;
+       int nr_types;
+       int *type_mapping;
 };
 
 static bool libbpf_initialized;
@@ -106,9 +114,177 @@ bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused,
        struct bpf_prog_priv *priv = _priv;
 
        cleanup_perf_probe_events(&priv->pev, 1);
+       zfree(&priv->insns_buf);
+       zfree(&priv->type_mapping);
        free(priv);
 }
 
+static int
+prog_config__exec(const char *value, struct perf_probe_event *pev)
+{
+       pev->uprobes = true;
+       pev->target = strdup(value);
+       if (!pev->target)
+               return -ENOMEM;
+       return 0;
+}
+
+static int
+prog_config__module(const char *value, struct perf_probe_event *pev)
+{
+       pev->uprobes = false;
+       pev->target = strdup(value);
+       if (!pev->target)
+               return -ENOMEM;
+       return 0;
+}
+
+static int
+prog_config__bool(const char *value, bool *pbool, bool invert)
+{
+       int err;
+       bool bool_value;
+
+       if (!pbool)
+               return -EINVAL;
+
+       err = strtobool(value, &bool_value);
+       if (err)
+               return err;
+
+       *pbool = invert ? !bool_value : bool_value;
+       return 0;
+}
+
+static int
+prog_config__inlines(const char *value,
+                    struct perf_probe_event *pev __maybe_unused)
+{
+       return prog_config__bool(value, &probe_conf.no_inlines, true);
+}
+
+static int
+prog_config__force(const char *value,
+                  struct perf_probe_event *pev __maybe_unused)
+{
+       return prog_config__bool(value, &probe_conf.force_add, false);
+}
+
+static struct {
+       const char *key;
+       const char *usage;
+       const char *desc;
+       int (*func)(const char *, struct perf_probe_event *);
+} bpf_prog_config_terms[] = {
+       {
+               .key    = "exec",
+               .usage  = "exec=<full path of file>",
+               .desc   = "Set uprobe target",
+               .func   = prog_config__exec,
+       },
+       {
+               .key    = "module",
+               .usage  = "module=<module name>    ",
+               .desc   = "Set kprobe module",
+               .func   = prog_config__module,
+       },
+       {
+               .key    = "inlines",
+               .usage  = "inlines=[yes|no]        ",
+               .desc   = "Probe at inline symbol",
+               .func   = prog_config__inlines,
+       },
+       {
+               .key    = "force",
+               .usage  = "force=[yes|no]          ",
+               .desc   = "Forcibly add events with existing name",
+               .func   = prog_config__force,
+       },
+};
+
+static int
+do_prog_config(const char *key, const char *value,
+              struct perf_probe_event *pev)
+{
+       unsigned int i;
+
+       pr_debug("config bpf program: %s=%s\n", key, value);
+       for (i = 0; i < ARRAY_SIZE(bpf_prog_config_terms); i++)
+               if (strcmp(key, bpf_prog_config_terms[i].key) == 0)
+                       return bpf_prog_config_terms[i].func(value, pev);
+
+       pr_debug("BPF: ERROR: invalid program config option: %s=%s\n",
+                key, value);
+
+       pr_debug("\nHint: Valid options are:\n");
+       for (i = 0; i < ARRAY_SIZE(bpf_prog_config_terms); i++)
+               pr_debug("\t%s:\t%s\n", bpf_prog_config_terms[i].usage,
+                        bpf_prog_config_terms[i].desc);
+       pr_debug("\n");
+
+       return -BPF_LOADER_ERRNO__PROGCONF_TERM;
+}
+
+static const char *
+parse_prog_config_kvpair(const char *config_str, struct perf_probe_event *pev)
+{
+       char *text = strdup(config_str);
+       char *sep, *line;
+       const char *main_str = NULL;
+       int err = 0;
+
+       if (!text) {
+               pr_debug("No enough memory: dup config_str failed\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       line = text;
+       while ((sep = strchr(line, ';'))) {
+               char *equ;
+
+               *sep = '\0';
+               equ = strchr(line, '=');
+               if (!equ) {
+                       pr_warning("WARNING: invalid config in BPF object: %s\n",
+                                  line);
+                       pr_warning("\tShould be 'key=value'.\n");
+                       goto nextline;
+               }
+               *equ = '\0';
+
+               err = do_prog_config(line, equ + 1, pev);
+               if (err)
+                       break;
+nextline:
+               line = sep + 1;
+       }
+
+       if (!err)
+               main_str = config_str + (line - text);
+       free(text);
+
+       return err ? ERR_PTR(err) : main_str;
+}
+
+static int
+parse_prog_config(const char *config_str, struct perf_probe_event *pev)
+{
+       int err;
+       const char *main_str = parse_prog_config_kvpair(config_str, pev);
+
+       if (IS_ERR(main_str))
+               return PTR_ERR(main_str);
+
+       err = parse_perf_probe_command(main_str, pev);
+       if (err < 0) {
+               pr_debug("bpf: '%s' is not a valid config string\n",
+                        config_str);
+               /* parse failed, don't need clear pev. */
+               return -BPF_LOADER_ERRNO__CONFIG;
+       }
+       return 0;
+}
+
 static int
 config_bpf_program(struct bpf_program *prog)
 {
@@ -117,6 +293,10 @@ config_bpf_program(struct bpf_program *prog)
        const char *config_str;
        int err;
 
+       /* Initialize per-program probing setting */
+       probe_conf.no_inlines = false;
+       probe_conf.force_add = false;
+
        config_str = bpf_program__title(prog, false);
        if (IS_ERR(config_str)) {
                pr_debug("bpf: unable to get title for program\n");
@@ -131,13 +311,9 @@ config_bpf_program(struct bpf_program *prog)
        pev = &priv->pev;
 
        pr_debug("bpf: config program '%s'\n", config_str);
-       err = parse_perf_probe_command(config_str, pev);
-       if (err < 0) {
-               pr_debug("bpf: '%s' is not a valid config string\n",
-                        config_str);
-               err = -BPF_LOADER_ERRNO__CONFIG;
+       err = parse_prog_config(config_str, pev);
+       if (err)
                goto errout;
-       }
 
        if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) {
                pr_debug("bpf: '%s': group for event is set and not '%s'.\n",
@@ -197,6 +373,220 @@ static int bpf__prepare_probe(void)
        return err;
 }
 
+static int
+preproc_gen_prologue(struct bpf_program *prog, int n,
+                    struct bpf_insn *orig_insns, int orig_insns_cnt,
+                    struct bpf_prog_prep_result *res)
+{
+       struct probe_trace_event *tev;
+       struct perf_probe_event *pev;
+       struct bpf_prog_priv *priv;
+       struct bpf_insn *buf;
+       size_t prologue_cnt = 0;
+       int i, err;
+
+       err = bpf_program__get_private(prog, (void **)&priv);
+       if (err || !priv)
+               goto errout;
+
+       pev = &priv->pev;
+
+       if (n < 0 || n >= priv->nr_types)
+               goto errout;
+
+       /* Find a tev belongs to that type */
+       for (i = 0; i < pev->ntevs; i++) {
+               if (priv->type_mapping[i] == n)
+                       break;
+       }
+
+       if (i >= pev->ntevs) {
+               pr_debug("Internal error: prologue type %d not found\n", n);
+               return -BPF_LOADER_ERRNO__PROLOGUE;
+       }
+
+       tev = &pev->tevs[i];
+
+       buf = priv->insns_buf;
+       err = bpf__gen_prologue(tev->args, tev->nargs,
+                               buf, &prologue_cnt,
+                               BPF_MAXINSNS - orig_insns_cnt);
+       if (err) {
+               const char *title;
+
+               title = bpf_program__title(prog, false);
+               if (!title)
+                       title = "[unknown]";
+
+               pr_debug("Failed to generate prologue for program %s\n",
+                        title);
+               return err;
+       }
+
+       memcpy(&buf[prologue_cnt], orig_insns,
+              sizeof(struct bpf_insn) * orig_insns_cnt);
+
+       res->new_insn_ptr = buf;
+       res->new_insn_cnt = prologue_cnt + orig_insns_cnt;
+       res->pfd = NULL;
+       return 0;
+
+errout:
+       pr_debug("Internal error in preproc_gen_prologue\n");
+       return -BPF_LOADER_ERRNO__PROLOGUE;
+}
+
+/*
+ * compare_tev_args is reflexive, transitive and antisymmetric.
+ * I can proof it but this margin is too narrow to contain.
+ */
+static int compare_tev_args(const void *ptev1, const void *ptev2)
+{
+       int i, ret;
+       const struct probe_trace_event *tev1 =
+               *(const struct probe_trace_event **)ptev1;
+       const struct probe_trace_event *tev2 =
+               *(const struct probe_trace_event **)ptev2;
+
+       ret = tev2->nargs - tev1->nargs;
+       if (ret)
+               return ret;
+
+       for (i = 0; i < tev1->nargs; i++) {
+               struct probe_trace_arg *arg1, *arg2;
+               struct probe_trace_arg_ref *ref1, *ref2;
+
+               arg1 = &tev1->args[i];
+               arg2 = &tev2->args[i];
+
+               ret = strcmp(arg1->value, arg2->value);
+               if (ret)
+                       return ret;
+
+               ref1 = arg1->ref;
+               ref2 = arg2->ref;
+
+               while (ref1 && ref2) {
+                       ret = ref2->offset - ref1->offset;
+                       if (ret)
+                               return ret;
+
+                       ref1 = ref1->next;
+                       ref2 = ref2->next;
+               }
+
+               if (ref1 || ref2)
+                       return ref2 ? 1 : -1;
+       }
+
+       return 0;
+}
+
+/*
+ * Assign a type number to each tevs in a pev.
+ * mapping is an array with same slots as tevs in that pev.
+ * nr_types will be set to number of types.
+ */
+static int map_prologue(struct perf_probe_event *pev, int *mapping,
+                       int *nr_types)
+{
+       int i, type = 0;
+       struct probe_trace_event **ptevs;
+
+       size_t array_sz = sizeof(*ptevs) * pev->ntevs;
+
+       ptevs = malloc(array_sz);
+       if (!ptevs) {
+               pr_debug("No ehough memory: alloc ptevs failed\n");
+               return -ENOMEM;
+       }
+
+       pr_debug("In map_prologue, ntevs=%d\n", pev->ntevs);
+       for (i = 0; i < pev->ntevs; i++)
+               ptevs[i] = &pev->tevs[i];
+
+       qsort(ptevs, pev->ntevs, sizeof(*ptevs),
+             compare_tev_args);
+
+       for (i = 0; i < pev->ntevs; i++) {
+               int n;
+
+               n = ptevs[i] - pev->tevs;
+               if (i == 0) {
+                       mapping[n] = type;
+                       pr_debug("mapping[%d]=%d\n", n, type);
+                       continue;
+               }
+
+               if (compare_tev_args(ptevs + i, ptevs + i - 1) == 0)
+                       mapping[n] = type;
+               else
+                       mapping[n] = ++type;
+
+               pr_debug("mapping[%d]=%d\n", n, mapping[n]);
+       }
+       free(ptevs);
+       *nr_types = type + 1;
+
+       return 0;
+}
+
+static int hook_load_preprocessor(struct bpf_program *prog)
+{
+       struct perf_probe_event *pev;
+       struct bpf_prog_priv *priv;
+       bool need_prologue = false;
+       int err, i;
+
+       err = bpf_program__get_private(prog, (void **)&priv);
+       if (err || !priv) {
+               pr_debug("Internal error when hook preprocessor\n");
+               return -BPF_LOADER_ERRNO__INTERNAL;
+       }
+
+       pev = &priv->pev;
+       for (i = 0; i < pev->ntevs; i++) {
+               struct probe_trace_event *tev = &pev->tevs[i];
+
+               if (tev->nargs > 0) {
+                       need_prologue = true;
+                       break;
+               }
+       }
+
+       /*
+        * Since all tevs don't have argument, we don't need generate
+        * prologue.
+        */
+       if (!need_prologue) {
+               priv->need_prologue = false;
+               return 0;
+       }
+
+       priv->need_prologue = true;
+       priv->insns_buf = malloc(sizeof(struct bpf_insn) * BPF_MAXINSNS);
+       if (!priv->insns_buf) {
+               pr_debug("No enough memory: alloc insns_buf failed\n");
+               return -ENOMEM;
+       }
+
+       priv->type_mapping = malloc(sizeof(int) * pev->ntevs);
+       if (!priv->type_mapping) {
+               pr_debug("No enough memory: alloc type_mapping failed\n");
+               return -ENOMEM;
+       }
+       memset(priv->type_mapping, -1,
+              sizeof(int) * pev->ntevs);
+
+       err = map_prologue(pev, priv->type_mapping, &priv->nr_types);
+       if (err)
+               return err;
+
+       err = bpf_program__set_prep(prog, priv->nr_types,
+                                   preproc_gen_prologue);
+       return err;
+}
+
 int bpf__probe(struct bpf_object *obj)
 {
        int err = 0;
@@ -231,6 +621,18 @@ int bpf__probe(struct bpf_object *obj)
                        pr_debug("bpf_probe: failed to apply perf probe events");
                        goto out;
                }
+
+               /*
+                * After probing, let's consider prologue, which
+                * adds program fetcher to BPF programs.
+                *
+                * hook_load_preprocessorr() hooks pre-processor
+                * to bpf_program, let it generate prologue
+                * dynamically during loading.
+                */
+               err = hook_load_preprocessor(prog);
+               if (err)
+                       goto out;
        }
 out:
        return err < 0 ? err : 0;
@@ -314,7 +716,14 @@ int bpf__foreach_tev(struct bpf_object *obj,
                for (i = 0; i < pev->ntevs; i++) {
                        tev = &pev->tevs[i];
 
-                       fd = bpf_program__fd(prog);
+                       if (priv->need_prologue) {
+                               int type = priv->type_mapping[i];
+
+                               fd = bpf_program__nth_fd(prog, type);
+                       } else {
+                               fd = bpf_program__fd(prog);
+                       }
+
                        if (fd < 0) {
                                pr_debug("bpf: failed to get file descriptor\n");
                                return fd;
@@ -340,6 +749,10 @@ static const char *bpf_loader_strerror_table[NR_ERRNO] = {
        [ERRCODE_OFFSET(EVENTNAME)]     = "No event name found in config string",
        [ERRCODE_OFFSET(INTERNAL)]      = "BPF loader internal error",
        [ERRCODE_OFFSET(COMPILE)]       = "Error when compiling BPF scriptlet",
+       [ERRCODE_OFFSET(PROGCONF_TERM)] = "Invalid program config term in config string",
+       [ERRCODE_OFFSET(PROLOGUE)]      = "Failed to generate prologue",
+       [ERRCODE_OFFSET(PROLOGUE2BIG)]  = "Prologue too big for program",
+       [ERRCODE_OFFSET(PROLOGUEOOB)]   = "Offset out of bound for prologue",
 };
 
 static int
@@ -420,7 +833,11 @@ int bpf__strerror_probe(struct bpf_object *obj __maybe_unused,
                        int err, char *buf, size_t size)
 {
        bpf__strerror_head(err, buf, size);
-       bpf__strerror_entry(EEXIST, "Probe point exist. Try use 'perf probe -d \"*\"'");
+       case BPF_LOADER_ERRNO__PROGCONF_TERM: {
+               scnprintf(buf, size, "%s (add -v to see detail)", emsg);
+               break;
+       }
+       bpf__strerror_entry(EEXIST, "Probe point exist. Try 'perf probe -d \"*\"' and set 'force=yes'");
        bpf__strerror_entry(EACCES, "You need to be root");
        bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0");
        bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file");
index 9caf3ae4acf3d018a87d92bb62f16c4337bd6388..6fdc0457e2b66ea3fedd8e26c4a0e8f6a4bcc6e2 100644 (file)
@@ -20,6 +20,10 @@ enum bpf_loader_errno {
        BPF_LOADER_ERRNO__EVENTNAME,    /* Event name is missing */
        BPF_LOADER_ERRNO__INTERNAL,     /* BPF loader internal error */
        BPF_LOADER_ERRNO__COMPILE,      /* Error when compiling BPF scriptlet */
+       BPF_LOADER_ERRNO__PROGCONF_TERM,/* Invalid program config term in config string */
+       BPF_LOADER_ERRNO__PROLOGUE,     /* Failed to generate prologue */
+       BPF_LOADER_ERRNO__PROLOGUE2BIG, /* Prologue too big for program */
+       BPF_LOADER_ERRNO__PROLOGUEOOB,  /* Offset out of bound for prologue */
        __BPF_LOADER_ERRNO__END,
 };
 
diff --git a/tools/perf/util/bpf-prologue.c b/tools/perf/util/bpf-prologue.c
new file mode 100644 (file)
index 0000000..6cdbee1
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * bpf-prologue.c
+ *
+ * Copyright (C) 2015 He Kuang <hekuang@huawei.com>
+ * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>
+ * Copyright (C) 2015 Huawei Inc.
+ */
+
+#include <bpf/libbpf.h>
+#include "perf.h"
+#include "debug.h"
+#include "bpf-loader.h"
+#include "bpf-prologue.h"
+#include "probe-finder.h"
+#include <dwarf-regs.h>
+#include <linux/filter.h>
+
+#define BPF_REG_SIZE           8
+
+#define JMP_TO_ERROR_CODE      -1
+#define JMP_TO_SUCCESS_CODE    -2
+#define JMP_TO_USER_CODE       -3
+
+struct bpf_insn_pos {
+       struct bpf_insn *begin;
+       struct bpf_insn *end;
+       struct bpf_insn *pos;
+};
+
+static inline int
+pos_get_cnt(struct bpf_insn_pos *pos)
+{
+       return pos->pos - pos->begin;
+}
+
+static int
+append_insn(struct bpf_insn new_insn, struct bpf_insn_pos *pos)
+{
+       if (!pos->pos)
+               return -BPF_LOADER_ERRNO__PROLOGUE2BIG;
+
+       if (pos->pos + 1 >= pos->end) {
+               pr_err("bpf prologue: prologue too long\n");
+               pos->pos = NULL;
+               return -BPF_LOADER_ERRNO__PROLOGUE2BIG;
+       }
+
+       *(pos->pos)++ = new_insn;
+       return 0;
+}
+
+static int
+check_pos(struct bpf_insn_pos *pos)
+{
+       if (!pos->pos || pos->pos >= pos->end)
+               return -BPF_LOADER_ERRNO__PROLOGUE2BIG;
+       return 0;
+}
+
+/* Give it a shorter name */
+#define ins(i, p) append_insn((i), (p))
+
+/*
+ * Give a register name (in 'reg'), generate instruction to
+ * load register into an eBPF register rd:
+ *   'ldd target_reg, offset(ctx_reg)', where:
+ * ctx_reg is pre initialized to pointer of 'struct pt_regs'.
+ */
+static int
+gen_ldx_reg_from_ctx(struct bpf_insn_pos *pos, int ctx_reg,
+                    const char *reg, int target_reg)
+{
+       int offset = regs_query_register_offset(reg);
+
+       if (offset < 0) {
+               pr_err("bpf: prologue: failed to get register %s\n",
+                      reg);
+               return offset;
+       }
+       ins(BPF_LDX_MEM(BPF_DW, target_reg, ctx_reg, offset), pos);
+
+       return check_pos(pos);
+}
+
+/*
+ * Generate a BPF_FUNC_probe_read function call.
+ *
+ * src_base_addr_reg is a register holding base address,
+ * dst_addr_reg is a register holding dest address (on stack),
+ * result is:
+ *
+ *  *[dst_addr_reg] = *([src_base_addr_reg] + offset)
+ *
+ * Arguments of BPF_FUNC_probe_read:
+ *     ARG1: ptr to stack (dest)
+ *     ARG2: size (8)
+ *     ARG3: unsafe ptr (src)
+ */
+static int
+gen_read_mem(struct bpf_insn_pos *pos,
+            int src_base_addr_reg,
+            int dst_addr_reg,
+            long offset)
+{
+       /* mov arg3, src_base_addr_reg */
+       if (src_base_addr_reg != BPF_REG_ARG3)
+               ins(BPF_MOV64_REG(BPF_REG_ARG3, src_base_addr_reg), pos);
+       /* add arg3, #offset */
+       if (offset)
+               ins(BPF_ALU64_IMM(BPF_ADD, BPF_REG_ARG3, offset), pos);
+
+       /* mov arg2, #reg_size */
+       ins(BPF_ALU64_IMM(BPF_MOV, BPF_REG_ARG2, BPF_REG_SIZE), pos);
+
+       /* mov arg1, dst_addr_reg */
+       if (dst_addr_reg != BPF_REG_ARG1)
+               ins(BPF_MOV64_REG(BPF_REG_ARG1, dst_addr_reg), pos);
+
+       /* Call probe_read  */
+       ins(BPF_EMIT_CALL(BPF_FUNC_probe_read), pos);
+       /*
+        * Error processing: if read fail, goto error code,
+        * will be relocated. Target should be the start of
+        * error processing code.
+        */
+       ins(BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, JMP_TO_ERROR_CODE),
+           pos);
+
+       return check_pos(pos);
+}
+
+/*
+ * Each arg should be bare register. Fetch and save them into argument
+ * registers (r3 - r5).
+ *
+ * BPF_REG_1 should have been initialized with pointer to
+ * 'struct pt_regs'.
+ */
+static int
+gen_prologue_fastpath(struct bpf_insn_pos *pos,
+                     struct probe_trace_arg *args, int nargs)
+{
+       int i, err = 0;
+
+       for (i = 0; i < nargs; i++) {
+               err = gen_ldx_reg_from_ctx(pos, BPF_REG_1, args[i].value,
+                                          BPF_PROLOGUE_START_ARG_REG + i);
+               if (err)
+                       goto errout;
+       }
+
+       return check_pos(pos);
+errout:
+       return err;
+}
+
+/*
+ * Slow path:
+ *   At least one argument has the form of 'offset($rx)'.
+ *
+ * Following code first stores them into stack, then loads all of then
+ * to r2 - r5.
+ * Before final loading, the final result should be:
+ *
+ * low address
+ * BPF_REG_FP - 24  ARG3
+ * BPF_REG_FP - 16  ARG2
+ * BPF_REG_FP - 8   ARG1
+ * BPF_REG_FP
+ * high address
+ *
+ * For each argument (described as: offn(...off2(off1(reg)))),
+ * generates following code:
+ *
+ *  r7 <- fp
+ *  r7 <- r7 - stack_offset  // Ideal code should initialize r7 using
+ *                           // fp before generating args. However,
+ *                           // eBPF won't regard r7 as stack pointer
+ *                           // if it is generated by minus 8 from
+ *                           // another stack pointer except fp.
+ *                           // This is why we have to set r7
+ *                           // to fp for each variable.
+ *  r3 <- value of 'reg'-> generated using gen_ldx_reg_from_ctx()
+ *  (r7) <- r3       // skip following instructions for bare reg
+ *  r3 <- r3 + off1  . // skip if off1 == 0
+ *  r2 <- 8           \
+ *  r1 <- r7           |-> generated by gen_read_mem()
+ *  call probe_read    /
+ *  jnei r0, 0, err  ./
+ *  r3 <- (r7)
+ *  r3 <- r3 + off2  . // skip if off2 == 0
+ *  r2 <- 8           \  // r2 may be broken by probe_read, so set again
+ *  r1 <- r7           |-> generated by gen_read_mem()
+ *  call probe_read    /
+ *  jnei r0, 0, err  ./
+ *  ...
+ */
+static int
+gen_prologue_slowpath(struct bpf_insn_pos *pos,
+                     struct probe_trace_arg *args, int nargs)
+{
+       int err, i;
+
+       for (i = 0; i < nargs; i++) {
+               struct probe_trace_arg *arg = &args[i];
+               const char *reg = arg->value;
+               struct probe_trace_arg_ref *ref = NULL;
+               int stack_offset = (i + 1) * -8;
+
+               pr_debug("prologue: fetch arg %d, base reg is %s\n",
+                        i, reg);
+
+               /* value of base register is stored into ARG3 */
+               err = gen_ldx_reg_from_ctx(pos, BPF_REG_CTX, reg,
+                                          BPF_REG_ARG3);
+               if (err) {
+                       pr_err("prologue: failed to get offset of register %s\n",
+                              reg);
+                       goto errout;
+               }
+
+               /* Make r7 the stack pointer. */
+               ins(BPF_MOV64_REG(BPF_REG_7, BPF_REG_FP), pos);
+               /* r7 += -8 */
+               ins(BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, stack_offset), pos);
+               /*
+                * Store r3 (base register) onto stack
+                * Ensure fp[offset] is set.
+                * fp is the only valid base register when storing
+                * into stack. We are not allowed to use r7 as base
+                * register here.
+                */
+               ins(BPF_STX_MEM(BPF_DW, BPF_REG_FP, BPF_REG_ARG3,
+                               stack_offset), pos);
+
+               ref = arg->ref;
+               while (ref) {
+                       pr_debug("prologue: arg %d: offset %ld\n",
+                                i, ref->offset);
+                       err = gen_read_mem(pos, BPF_REG_3, BPF_REG_7,
+                                          ref->offset);
+                       if (err) {
+                               pr_err("prologue: failed to generate probe_read function call\n");
+                               goto errout;
+                       }
+
+                       ref = ref->next;
+                       /*
+                        * Load previous result into ARG3. Use
+                        * BPF_REG_FP instead of r7 because verifier
+                        * allows FP based addressing only.
+                        */
+                       if (ref)
+                               ins(BPF_LDX_MEM(BPF_DW, BPF_REG_ARG3,
+                                               BPF_REG_FP, stack_offset), pos);
+               }
+       }
+
+       /* Final pass: read to registers */
+       for (i = 0; i < nargs; i++)
+               ins(BPF_LDX_MEM(BPF_DW, BPF_PROLOGUE_START_ARG_REG + i,
+                               BPF_REG_FP, -BPF_REG_SIZE * (i + 1)), pos);
+
+       ins(BPF_JMP_IMM(BPF_JA, BPF_REG_0, 0, JMP_TO_SUCCESS_CODE), pos);
+
+       return check_pos(pos);
+errout:
+       return err;
+}
+
+static int
+prologue_relocate(struct bpf_insn_pos *pos, struct bpf_insn *error_code,
+                 struct bpf_insn *success_code, struct bpf_insn *user_code)
+{
+       struct bpf_insn *insn;
+
+       if (check_pos(pos))
+               return -BPF_LOADER_ERRNO__PROLOGUE2BIG;
+
+       for (insn = pos->begin; insn < pos->pos; insn++) {
+               struct bpf_insn *target;
+               u8 class = BPF_CLASS(insn->code);
+               u8 opcode;
+
+               if (class != BPF_JMP)
+                       continue;
+               opcode = BPF_OP(insn->code);
+               if (opcode == BPF_CALL)
+                       continue;
+
+               switch (insn->off) {
+               case JMP_TO_ERROR_CODE:
+                       target = error_code;
+                       break;
+               case JMP_TO_SUCCESS_CODE:
+                       target = success_code;
+                       break;
+               case JMP_TO_USER_CODE:
+                       target = user_code;
+                       break;
+               default:
+                       pr_err("bpf prologue: internal error: relocation failed\n");
+                       return -BPF_LOADER_ERRNO__PROLOGUE;
+               }
+
+               insn->off = target - (insn + 1);
+       }
+       return 0;
+}
+
+int bpf__gen_prologue(struct probe_trace_arg *args, int nargs,
+                     struct bpf_insn *new_prog, size_t *new_cnt,
+                     size_t cnt_space)
+{
+       struct bpf_insn *success_code = NULL;
+       struct bpf_insn *error_code = NULL;
+       struct bpf_insn *user_code = NULL;
+       struct bpf_insn_pos pos;
+       bool fastpath = true;
+       int err = 0, i;
+
+       if (!new_prog || !new_cnt)
+               return -EINVAL;
+
+       if (cnt_space > BPF_MAXINSNS)
+               cnt_space = BPF_MAXINSNS;
+
+       pos.begin = new_prog;
+       pos.end = new_prog + cnt_space;
+       pos.pos = new_prog;
+
+       if (!nargs) {
+               ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 0),
+                   &pos);
+
+               if (check_pos(&pos))
+                       goto errout;
+
+               *new_cnt = pos_get_cnt(&pos);
+               return 0;
+       }
+
+       if (nargs > BPF_PROLOGUE_MAX_ARGS) {
+               pr_warning("bpf: prologue: %d arguments are dropped\n",
+                          nargs - BPF_PROLOGUE_MAX_ARGS);
+               nargs = BPF_PROLOGUE_MAX_ARGS;
+       }
+
+       /* First pass: validation */
+       for (i = 0; i < nargs; i++) {
+               struct probe_trace_arg_ref *ref = args[i].ref;
+
+               if (args[i].value[0] == '@') {
+                       /* TODO: fetch global variable */
+                       pr_err("bpf: prologue: global %s%+ld not support\n",
+                               args[i].value, ref ? ref->offset : 0);
+                       return -ENOTSUP;
+               }
+
+               while (ref) {
+                       /* fastpath is true if all args has ref == NULL */
+                       fastpath = false;
+
+                       /*
+                        * Instruction encodes immediate value using
+                        * s32, ref->offset is long. On systems which
+                        * can't fill long in s32, refuse to process if
+                        * ref->offset too large (or small).
+                        */
+#ifdef __LP64__
+#define OFFSET_MAX     ((1LL << 31) - 1)
+#define OFFSET_MIN     ((1LL << 31) * -1)
+                       if (ref->offset > OFFSET_MAX ||
+                                       ref->offset < OFFSET_MIN) {
+                               pr_err("bpf: prologue: offset out of bound: %ld\n",
+                                      ref->offset);
+                               return -BPF_LOADER_ERRNO__PROLOGUEOOB;
+                       }
+#endif
+                       ref = ref->next;
+               }
+       }
+       pr_debug("prologue: pass validation\n");
+
+       if (fastpath) {
+               /* If all variables are registers... */
+               pr_debug("prologue: fast path\n");
+               err = gen_prologue_fastpath(&pos, args, nargs);
+               if (err)
+                       goto errout;
+       } else {
+               pr_debug("prologue: slow path\n");
+
+               /* Initialization: move ctx to a callee saved register. */
+               ins(BPF_MOV64_REG(BPF_REG_CTX, BPF_REG_ARG1), &pos);
+
+               err = gen_prologue_slowpath(&pos, args, nargs);
+               if (err)
+                       goto errout;
+               /*
+                * start of ERROR_CODE (only slow pass needs error code)
+                *   mov r2 <- 1  // r2 is error number
+                *   mov r3 <- 0  // r3, r4... should be touched or
+                *                // verifier would complain
+                *   mov r4 <- 0
+                *   ...
+                *   goto usercode
+                */
+               error_code = pos.pos;
+               ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 1),
+                   &pos);
+
+               for (i = 0; i < nargs; i++)
+                       ins(BPF_ALU64_IMM(BPF_MOV,
+                                         BPF_PROLOGUE_START_ARG_REG + i,
+                                         0),
+                           &pos);
+               ins(BPF_JMP_IMM(BPF_JA, BPF_REG_0, 0, JMP_TO_USER_CODE),
+                               &pos);
+       }
+
+       /*
+        * start of SUCCESS_CODE:
+        *   mov r2 <- 0
+        *   goto usercode  // skip
+        */
+       success_code = pos.pos;
+       ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 0), &pos);
+
+       /*
+        * start of USER_CODE:
+        *   Restore ctx to r1
+        */
+       user_code = pos.pos;
+       if (!fastpath) {
+               /*
+                * Only slow path needs restoring of ctx. In fast path,
+                * register are loaded directly from r1.
+                */
+               ins(BPF_MOV64_REG(BPF_REG_ARG1, BPF_REG_CTX), &pos);
+               err = prologue_relocate(&pos, error_code, success_code,
+                                       user_code);
+               if (err)
+                       goto errout;
+       }
+
+       err = check_pos(&pos);
+       if (err)
+               goto errout;
+
+       *new_cnt = pos_get_cnt(&pos);
+       return 0;
+errout:
+       return err;
+}
diff --git a/tools/perf/util/bpf-prologue.h b/tools/perf/util/bpf-prologue.h
new file mode 100644 (file)
index 0000000..d94cbea
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015, He Kuang <hekuang@huawei.com>
+ * Copyright (C) 2015, Huawei Inc.
+ */
+#ifndef __BPF_PROLOGUE_H
+#define __BPF_PROLOGUE_H
+
+#include <linux/compiler.h>
+#include <linux/filter.h>
+#include "probe-event.h"
+
+#define BPF_PROLOGUE_MAX_ARGS 3
+#define BPF_PROLOGUE_START_ARG_REG BPF_REG_3
+#define BPF_PROLOGUE_FETCH_RESULT_REG BPF_REG_2
+
+#ifdef HAVE_BPF_PROLOGUE
+int bpf__gen_prologue(struct probe_trace_arg *args, int nargs,
+                     struct bpf_insn *new_prog, size_t *new_cnt,
+                     size_t cnt_space);
+#else
+static inline int
+bpf__gen_prologue(struct probe_trace_arg *args __maybe_unused,
+                 int nargs __maybe_unused,
+                 struct bpf_insn *new_prog __maybe_unused,
+                 size_t *new_cnt,
+                 size_t cnt_space __maybe_unused)
+{
+       if (!new_cnt)
+               return -EINVAL;
+       *new_cnt = 0;
+       return -ENOTSUP;
+}
+#endif
+#endif /* __BPF_PROLOGUE_H */
index 217b5a60e2ab0e000fbd4ff75445665d08833ba6..6a7e273a514a642b30a477c3119696dc7fa09975 100644 (file)
@@ -91,7 +91,7 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf)
                bid += 2;
        }
 
-       return raw - build_id;
+       return (bid - bf) + 1;
 }
 
 int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id)
index c861373aaed33dafd233a7bf5eebefa4dfd9874b..07b5d63947b11ec5f70029c6e41266e56b2bd8aa 100644 (file)
@@ -4,9 +4,12 @@
 #include <stdbool.h>
 #include "util.h"
 #include "strbuf.h"
+#include <subcmd/pager.h>
 #include "../perf.h"
 #include "../ui/ui.h"
 
+#include <linux/string.h>
+
 #define CMD_EXEC_PATH "--exec-path"
 #define CMD_PERF_DIR "--perf-dir="
 #define CMD_WORK_TREE "--work-tree="
@@ -18,6 +21,7 @@
 #define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
 #define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
 #define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
+#define PERF_PAGER_ENVIRONMENT "PERF_PAGER"
 
 typedef int (*config_fn_t)(const char *, const char *, void *);
 extern int perf_default_config(const char *, const char *, void *);
@@ -28,11 +32,6 @@ extern int perf_config_bool(const char *, const char *);
 extern int config_error_nonbool(const char *);
 extern const char *perf_config_dirname(const char *, const char *);
 
-/* pager.c */
-extern void setup_pager(void);
-extern int pager_in_use(void);
-extern int pager_use_color;
-
 char *alias_lookup(const char *alias);
 int split_cmdline(char *cmdline, const char ***argv);
 
@@ -71,9 +70,4 @@ extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2
 extern char *perf_pathdup(const char *fmt, ...)
        __attribute__((format (printf, 1, 2)));
 
-#ifndef __UCLIBC__
-/* Matches the libc/libbsd function attribute so we declare this unconditionally: */
-extern size_t strlcpy(char *dest, const char *src, size_t size);
-#endif
-
 #endif /* __PERF_CACHE_H */
index 735ad48e1858b0382c9aacc84e0b912e9329c86a..53c43eb9489e4ba4a4e56a795bc05c2b85fb4cbc 100644 (file)
@@ -44,6 +44,10 @@ static int parse_callchain_mode(const char *value)
                callchain_param.mode = CHAIN_GRAPH_REL;
                return 0;
        }
+       if (!strncmp(value, "folded", strlen(value))) {
+               callchain_param.mode = CHAIN_FOLDED;
+               return 0;
+       }
        return -1;
 }
 
@@ -79,6 +83,23 @@ static int parse_callchain_sort_key(const char *value)
        return -1;
 }
 
+static int parse_callchain_value(const char *value)
+{
+       if (!strncmp(value, "percent", strlen(value))) {
+               callchain_param.value = CCVAL_PERCENT;
+               return 0;
+       }
+       if (!strncmp(value, "period", strlen(value))) {
+               callchain_param.value = CCVAL_PERIOD;
+               return 0;
+       }
+       if (!strncmp(value, "count", strlen(value))) {
+               callchain_param.value = CCVAL_COUNT;
+               return 0;
+       }
+       return -1;
+}
+
 static int
 __parse_callchain_report_opt(const char *arg, bool allow_record_opt)
 {
@@ -102,7 +123,8 @@ __parse_callchain_report_opt(const char *arg, bool allow_record_opt)
 
                if (!parse_callchain_mode(tok) ||
                    !parse_callchain_order(tok) ||
-                   !parse_callchain_sort_key(tok)) {
+                   !parse_callchain_sort_key(tok) ||
+                   !parse_callchain_value(tok)) {
                        /* parsing ok - move on to the next */
                        try_stack_size = false;
                        goto next;
@@ -218,6 +240,7 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
 
                switch (mode) {
                case CHAIN_FLAT:
+               case CHAIN_FOLDED:
                        if (rnode->hit < chain->hit)
                                p = &(*p)->rb_left;
                        else
@@ -267,6 +290,7 @@ static void
 sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
                u64 min_hit, struct callchain_param *param __maybe_unused)
 {
+       *rb_root = RB_ROOT;
        __sort_chain_flat(rb_root, &root->node, min_hit);
 }
 
@@ -338,6 +362,7 @@ int callchain_register_param(struct callchain_param *param)
                param->sort = sort_chain_graph_rel;
                break;
        case CHAIN_FLAT:
+       case CHAIN_FOLDED:
                param->sort = sort_chain_flat;
                break;
        case CHAIN_NONE:
@@ -363,6 +388,7 @@ create_child(struct callchain_node *parent, bool inherit_children)
        }
        new->parent = parent;
        INIT_LIST_HEAD(&new->val);
+       INIT_LIST_HEAD(&new->parent_val);
 
        if (inherit_children) {
                struct rb_node *n;
@@ -431,6 +457,8 @@ add_child(struct callchain_node *parent,
 
        new->children_hit = 0;
        new->hit = period;
+       new->children_count = 0;
+       new->count = 1;
        return new;
 }
 
@@ -478,6 +506,9 @@ split_add_child(struct callchain_node *parent,
        parent->children_hit = callchain_cumul_hits(new);
        new->val_nr = parent->val_nr - idx_local;
        parent->val_nr = idx_local;
+       new->count = parent->count;
+       new->children_count = parent->children_count;
+       parent->children_count = callchain_cumul_counts(new);
 
        /* create a new child for the new branch if any */
        if (idx_total < cursor->nr) {
@@ -488,6 +519,8 @@ split_add_child(struct callchain_node *parent,
 
                parent->hit = 0;
                parent->children_hit += period;
+               parent->count = 0;
+               parent->children_count += 1;
 
                node = callchain_cursor_current(cursor);
                new = add_child(parent, cursor, period);
@@ -510,6 +543,7 @@ split_add_child(struct callchain_node *parent,
                rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
        } else {
                parent->hit = period;
+               parent->count = 1;
        }
 }
 
@@ -556,6 +590,7 @@ append_chain_children(struct callchain_node *root,
 
 inc_children_hit:
        root->children_hit += period;
+       root->children_count++;
 }
 
 static int
@@ -608,6 +643,7 @@ append_chain(struct callchain_node *root,
        /* we match 100% of the path, increment the hit */
        if (matches == root->val_nr && cursor->pos == cursor->nr) {
                root->hit += period;
+               root->count++;
                return 0;
        }
 
@@ -799,12 +835,72 @@ char *callchain_list__sym_name(struct callchain_list *cl,
        return bf;
 }
 
+char *callchain_node__scnprintf_value(struct callchain_node *node,
+                                     char *bf, size_t bfsize, u64 total)
+{
+       double percent = 0.0;
+       u64 period = callchain_cumul_hits(node);
+       unsigned count = callchain_cumul_counts(node);
+
+       if (callchain_param.mode == CHAIN_FOLDED) {
+               period = node->hit;
+               count = node->count;
+       }
+
+       switch (callchain_param.value) {
+       case CCVAL_PERIOD:
+               scnprintf(bf, bfsize, "%"PRIu64, period);
+               break;
+       case CCVAL_COUNT:
+               scnprintf(bf, bfsize, "%u", count);
+               break;
+       case CCVAL_PERCENT:
+       default:
+               if (total)
+                       percent = period * 100.0 / total;
+               scnprintf(bf, bfsize, "%.2f%%", percent);
+               break;
+       }
+       return bf;
+}
+
+int callchain_node__fprintf_value(struct callchain_node *node,
+                                FILE *fp, u64 total)
+{
+       double percent = 0.0;
+       u64 period = callchain_cumul_hits(node);
+       unsigned count = callchain_cumul_counts(node);
+
+       if (callchain_param.mode == CHAIN_FOLDED) {
+               period = node->hit;
+               count = node->count;
+       }
+
+       switch (callchain_param.value) {
+       case CCVAL_PERIOD:
+               return fprintf(fp, "%"PRIu64, period);
+       case CCVAL_COUNT:
+               return fprintf(fp, "%u", count);
+       case CCVAL_PERCENT:
+       default:
+               if (total)
+                       percent = period * 100.0 / total;
+               return percent_color_fprintf(fp, "%.2f%%", percent);
+       }
+       return 0;
+}
+
 static void free_callchain_node(struct callchain_node *node)
 {
        struct callchain_list *list, *tmp;
        struct callchain_node *child;
        struct rb_node *n;
 
+       list_for_each_entry_safe(list, tmp, &node->parent_val, list) {
+               list_del(&list->list);
+               free(list);
+       }
+
        list_for_each_entry_safe(list, tmp, &node->val, list) {
                list_del(&list->list);
                free(list);
@@ -828,3 +924,69 @@ void free_callchain(struct callchain_root *root)
 
        free_callchain_node(&root->node);
 }
+
+static u64 decay_callchain_node(struct callchain_node *node)
+{
+       struct callchain_node *child;
+       struct rb_node *n;
+       u64 child_hits = 0;
+
+       n = rb_first(&node->rb_root_in);
+       while (n) {
+               child = container_of(n, struct callchain_node, rb_node_in);
+
+               child_hits += decay_callchain_node(child);
+               n = rb_next(n);
+       }
+
+       node->hit = (node->hit * 7) / 8;
+       node->children_hit = child_hits;
+
+       return node->hit;
+}
+
+void decay_callchain(struct callchain_root *root)
+{
+       if (!symbol_conf.use_callchain)
+               return;
+
+       decay_callchain_node(&root->node);
+}
+
+int callchain_node__make_parent_list(struct callchain_node *node)
+{
+       struct callchain_node *parent = node->parent;
+       struct callchain_list *chain, *new;
+       LIST_HEAD(head);
+
+       while (parent) {
+               list_for_each_entry_reverse(chain, &parent->val, list) {
+                       new = malloc(sizeof(*new));
+                       if (new == NULL)
+                               goto out;
+                       *new = *chain;
+                       new->has_children = false;
+                       list_add_tail(&new->list, &head);
+               }
+               parent = parent->parent;
+       }
+
+       list_for_each_entry_safe_reverse(chain, new, &head, list)
+               list_move_tail(&chain->list, &node->parent_val);
+
+       if (!list_empty(&node->parent_val)) {
+               chain = list_first_entry(&node->parent_val, struct callchain_list, list);
+               chain->has_children = rb_prev(&node->rb_node) || rb_next(&node->rb_node);
+
+               chain = list_first_entry(&node->val, struct callchain_list, list);
+               chain->has_children = false;
+       }
+       return 0;
+
+out:
+       list_for_each_entry_safe(chain, new, &head, list) {
+               list_del(&chain->list);
+               free(chain);
+       }
+       return -ENOMEM;
+}
index fce8161e54dbbbae16f0667c0cd86cb50d7b58a2..18dd22269764cfe29e34964e02f70b5d1f77831d 100644 (file)
 #define CALLCHAIN_RECORD_HELP  CALLCHAIN_HELP RECORD_MODE_HELP RECORD_SIZE_HELP
 
 #define CALLCHAIN_REPORT_HELP                                          \
-       HELP_PAD "print_type:\tcall graph printing style (graph|flat|fractal|none)\n" \
+       HELP_PAD "print_type:\tcall graph printing style (graph|flat|fractal|folded|none)\n" \
        HELP_PAD "threshold:\tminimum call graph inclusion threshold (<percent>)\n" \
        HELP_PAD "print_limit:\tmaximum number of call graph entry (<number>)\n" \
        HELP_PAD "order:\t\tcall graph order (caller|callee)\n" \
        HELP_PAD "sort_key:\tcall graph sort key (function|address)\n"  \
-       HELP_PAD "branch:\t\tinclude last branch info to call graph (branch)\n"
+       HELP_PAD "branch:\t\tinclude last branch info to call graph (branch)\n" \
+       HELP_PAD "value:\t\tcall graph value (percent|period|count)\n"
 
 enum perf_call_graph_mode {
        CALLCHAIN_NONE,
@@ -43,7 +44,8 @@ enum chain_mode {
        CHAIN_NONE,
        CHAIN_FLAT,
        CHAIN_GRAPH_ABS,
-       CHAIN_GRAPH_REL
+       CHAIN_GRAPH_REL,
+       CHAIN_FOLDED,
 };
 
 enum chain_order {
@@ -54,11 +56,14 @@ enum chain_order {
 struct callchain_node {
        struct callchain_node   *parent;
        struct list_head        val;
+       struct list_head        parent_val;
        struct rb_node          rb_node_in; /* to insert nodes in an rbtree */
        struct rb_node          rb_node;    /* to sort nodes in an output tree */
        struct rb_root          rb_root_in; /* input tree of children */
        struct rb_root          rb_root;    /* sorted output tree of children */
        unsigned int            val_nr;
+       unsigned int            count;
+       unsigned int            children_count;
        u64                     hit;
        u64                     children_hit;
 };
@@ -78,6 +83,12 @@ enum chain_key {
        CCKEY_ADDRESS
 };
 
+enum chain_value {
+       CCVAL_PERCENT,
+       CCVAL_PERIOD,
+       CCVAL_COUNT,
+};
+
 struct callchain_param {
        bool                    enabled;
        enum perf_call_graph_mode record_mode;
@@ -90,6 +101,7 @@ struct callchain_param {
        bool                    order_set;
        enum chain_key          key;
        bool                    branch_callstack;
+       enum chain_value        value;
 };
 
 extern struct callchain_param callchain_param;
@@ -131,6 +143,7 @@ extern __thread struct callchain_cursor callchain_cursor;
 static inline void callchain_init(struct callchain_root *root)
 {
        INIT_LIST_HEAD(&root->node.val);
+       INIT_LIST_HEAD(&root->node.parent_val);
 
        root->node.parent = NULL;
        root->node.hit = 0;
@@ -144,6 +157,11 @@ static inline u64 callchain_cumul_hits(struct callchain_node *node)
        return node->hit + node->children_hit;
 }
 
+static inline unsigned callchain_cumul_counts(struct callchain_node *node)
+{
+       return node->count + node->children_count;
+}
+
 int callchain_register_param(struct callchain_param *param);
 int callchain_append(struct callchain_root *root,
                     struct callchain_cursor *cursor,
@@ -229,7 +247,13 @@ static inline int arch_skip_callchain_idx(struct thread *thread __maybe_unused,
 
 char *callchain_list__sym_name(struct callchain_list *cl,
                               char *bf, size_t bfsize, bool show_dso);
+char *callchain_node__scnprintf_value(struct callchain_node *node,
+                                     char *bf, size_t bfsize, u64 total);
+int callchain_node__fprintf_value(struct callchain_node *node,
+                                 FILE *fp, u64 total);
 
 void free_callchain(struct callchain_root *root);
+void decay_callchain(struct callchain_root *root);
+int callchain_node__make_parent_list(struct callchain_node *node);
 
 #endif /* __PERF_CALLCHAIN_H */
index 32e12ecfe9c576767f18a3cb42e6c5dedfc3f048..90aa1b46b2e5be06578befd275b6104bc9522dd3 100644 (file)
@@ -1,6 +1,6 @@
 #include "util.h"
 #include "../perf.h"
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
 #include "evsel.h"
 #include "cgroup.h"
 #include "evlist.h"
index 9b9565416f9037fb59e7e4382b58b34e4857a136..e5fb88bab9e1c416a3c53fe5036f8eb57f64a55d 100644 (file)
@@ -24,7 +24,7 @@ int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty)
  auto_color:
        if (stdout_is_tty < 0)
                stdout_is_tty = isatty(1);
-       if (stdout_is_tty || (pager_in_use() && pager_use_color)) {
+       if (stdout_is_tty || pager_in_use()) {
                char *term = getenv("TERM");
                if (term && strcmp(term, "dumb"))
                        return 1;
index 2e452ac1353d0ab8f6797d6ac9cd7bce94edf661..d3e12e30e1d520f8073d1f01d17e1eaf4ac30254 100644 (file)
@@ -10,7 +10,7 @@
  */
 #include "util.h"
 #include "cache.h"
-#include "exec_cmd.h"
+#include <subcmd/exec-cmd.h>
 #include "util/hist.h"  /* perf_hist_config */
 #include "util/llvm-utils.h"   /* perf_llvm_config */
 
index 10af1e7524fbd24de791c38fa23c7d730d54a193..fa935093a599429011fa214c24645fd0230e3b3a 100644 (file)
@@ -5,6 +5,7 @@
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <linux/bitmap.h>
 #include "asm/bug.h"
 
 static struct cpu_map *cpu_map__default_new(void)
@@ -179,6 +180,56 @@ out:
        return cpus;
 }
 
+static struct cpu_map *cpu_map__from_entries(struct cpu_map_entries *cpus)
+{
+       struct cpu_map *map;
+
+       map = cpu_map__empty_new(cpus->nr);
+       if (map) {
+               unsigned i;
+
+               for (i = 0; i < cpus->nr; i++) {
+                       /*
+                        * Special treatment for -1, which is not real cpu number,
+                        * and we need to use (int) -1 to initialize map[i],
+                        * otherwise it would become 65535.
+                        */
+                       if (cpus->cpu[i] == (u16) -1)
+                               map->map[i] = -1;
+                       else
+                               map->map[i] = (int) cpus->cpu[i];
+               }
+       }
+
+       return map;
+}
+
+static struct cpu_map *cpu_map__from_mask(struct cpu_map_mask *mask)
+{
+       struct cpu_map *map;
+       int nr, nbits = mask->nr * mask->long_size * BITS_PER_BYTE;
+
+       nr = bitmap_weight(mask->mask, nbits);
+
+       map = cpu_map__empty_new(nr);
+       if (map) {
+               int cpu, i = 0;
+
+               for_each_set_bit(cpu, mask->mask, nbits)
+                       map->map[i++] = cpu;
+       }
+       return map;
+
+}
+
+struct cpu_map *cpu_map__new_data(struct cpu_map_data *data)
+{
+       if (data->type == PERF_CPU_MAP__CPUS)
+               return cpu_map__from_entries((struct cpu_map_entries *)data->data);
+       else
+               return cpu_map__from_mask((struct cpu_map_mask *)data->data);
+}
+
 size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp)
 {
        int i;
index 85f7772457fa091655d62212067f2edddf6e55ae..71c41b9efabb3b38dd17a7374413985dfd944f77 100644 (file)
@@ -17,6 +17,7 @@ struct cpu_map {
 struct cpu_map *cpu_map__new(const char *cpu_list);
 struct cpu_map *cpu_map__empty_new(int nr);
 struct cpu_map *cpu_map__dummy_new(void);
+struct cpu_map *cpu_map__new_data(struct cpu_map_data *data);
 struct cpu_map *cpu_map__read(FILE *file);
 size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
 int cpu_map__get_socket_id(int cpu);
index 5bfc1198ab465c1873c7a112eefaa97bf286ee6f..34cd1e4039d35e05be0460ff0a259e7d8b2bb80a 100644 (file)
@@ -63,6 +63,7 @@ struct ctf_writer {
                        struct bt_ctf_field_type        *s32;
                        struct bt_ctf_field_type        *u32;
                        struct bt_ctf_field_type        *string;
+                       struct bt_ctf_field_type        *u32_hex;
                        struct bt_ctf_field_type        *u64_hex;
                };
                struct bt_ctf_field_type *array[6];
@@ -982,6 +983,7 @@ do {                                                        \
        CREATE_INT_TYPE(cw->data.u64, 64, false, false);
        CREATE_INT_TYPE(cw->data.s32, 32, true,  false);
        CREATE_INT_TYPE(cw->data.u32, 32, false, false);
+       CREATE_INT_TYPE(cw->data.u32_hex, 32, false, true);
        CREATE_INT_TYPE(cw->data.u64_hex, 64, false, true);
 
        cw->data.string  = bt_ctf_field_type_string_create();
index 425df5c86c9c9acc8a1cb9dd87540f677e885c5e..e8e9a9dbf5e395a20d589c80b253c2d869b927c1 100644 (file)
@@ -1243,6 +1243,8 @@ struct dso *__dsos__addnew(struct dsos *dsos, const char *name)
        if (dso != NULL) {
                __dsos__add(dsos, dso);
                dso__set_basename(dso);
+               /* Put dso here because __dsos_add already got it */
+               dso__put(dso);
        }
        return dso;
 }
index 6af4f7c36820aee49ff6c7f563e56195553a97cc..7dd5939dea2e58385bd374a3e59aecf766e799c1 100644 (file)
@@ -25,15 +25,6 @@ int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
 {
        int i;
 
-       /*
-        * If env->cmdline_argv has already been set, do not override it.  This allows
-        * a command to set the cmdline, parse args and then call another
-        * builtin function that implements a command -- e.g, cmd_kvm calling
-        * cmd_record.
-        */
-       if (env->cmdline_argv != NULL)
-               return 0;
-
        /* do not include NULL termination */
        env->cmdline_argv = calloc(argc, sizeof(char *));
        if (env->cmdline_argv == NULL)
diff --git a/tools/perf/util/environment.c b/tools/perf/util/environment.c
deleted file mode 100644 (file)
index 7405123..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * We put all the perf config variables in this same object
- * file, so that programs can link against the config parser
- * without having to link against all the rest of perf.
- */
-#include "cache.h"
-
-int pager_use_color = 1;
index 8b10621b415c684564a6dd5af130ebc9d3ab33c7..cd61bb1f3917f1c2a03f7274250a0f7e26531edc 100644 (file)
@@ -10,6 +10,8 @@
 #include "thread.h"
 #include "thread_map.h"
 #include "symbol/kallsyms.h"
+#include "asm/bug.h"
+#include "stat.h"
 
 static const char *perf_event__names[] = {
        [0]                                     = "TOTAL",
@@ -37,6 +39,12 @@ static const char *perf_event__names[] = {
        [PERF_RECORD_AUXTRACE_INFO]             = "AUXTRACE_INFO",
        [PERF_RECORD_AUXTRACE]                  = "AUXTRACE",
        [PERF_RECORD_AUXTRACE_ERROR]            = "AUXTRACE_ERROR",
+       [PERF_RECORD_THREAD_MAP]                = "THREAD_MAP",
+       [PERF_RECORD_CPU_MAP]                   = "CPU_MAP",
+       [PERF_RECORD_STAT_CONFIG]               = "STAT_CONFIG",
+       [PERF_RECORD_STAT]                      = "STAT",
+       [PERF_RECORD_STAT_ROUND]                = "STAT_ROUND",
+       [PERF_RECORD_EVENT_UPDATE]              = "EVENT_UPDATE",
 };
 
 const char *perf_event__name(unsigned int id)
@@ -699,6 +707,274 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
        return err;
 }
 
+int perf_event__synthesize_thread_map2(struct perf_tool *tool,
+                                     struct thread_map *threads,
+                                     perf_event__handler_t process,
+                                     struct machine *machine)
+{
+       union perf_event *event;
+       int i, err, size;
+
+       size  = sizeof(event->thread_map);
+       size += threads->nr * sizeof(event->thread_map.entries[0]);
+
+       event = zalloc(size);
+       if (!event)
+               return -ENOMEM;
+
+       event->header.type = PERF_RECORD_THREAD_MAP;
+       event->header.size = size;
+       event->thread_map.nr = threads->nr;
+
+       for (i = 0; i < threads->nr; i++) {
+               struct thread_map_event_entry *entry = &event->thread_map.entries[i];
+               char *comm = thread_map__comm(threads, i);
+
+               if (!comm)
+                       comm = (char *) "";
+
+               entry->pid = thread_map__pid(threads, i);
+               strncpy((char *) &entry->comm, comm, sizeof(entry->comm));
+       }
+
+       err = process(tool, event, NULL, machine);
+
+       free(event);
+       return err;
+}
+
+static void synthesize_cpus(struct cpu_map_entries *cpus,
+                           struct cpu_map *map)
+{
+       int i;
+
+       cpus->nr = map->nr;
+
+       for (i = 0; i < map->nr; i++)
+               cpus->cpu[i] = map->map[i];
+}
+
+static void synthesize_mask(struct cpu_map_mask *mask,
+                           struct cpu_map *map, int max)
+{
+       int i;
+
+       mask->nr = BITS_TO_LONGS(max);
+       mask->long_size = sizeof(long);
+
+       for (i = 0; i < map->nr; i++)
+               set_bit(map->map[i], mask->mask);
+}
+
+static size_t cpus_size(struct cpu_map *map)
+{
+       return sizeof(struct cpu_map_entries) + map->nr * sizeof(u16);
+}
+
+static size_t mask_size(struct cpu_map *map, int *max)
+{
+       int i;
+
+       *max = 0;
+
+       for (i = 0; i < map->nr; i++) {
+               /* bit possition of the cpu is + 1 */
+               int bit = map->map[i] + 1;
+
+               if (bit > *max)
+                       *max = bit;
+       }
+
+       return sizeof(struct cpu_map_mask) + BITS_TO_LONGS(*max) * sizeof(long);
+}
+
+void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max)
+{
+       size_t size_cpus, size_mask;
+       bool is_dummy = cpu_map__empty(map);
+
+       /*
+        * Both array and mask data have variable size based
+        * on the number of cpus and their actual values.
+        * The size of the 'struct cpu_map_data' is:
+        *
+        *   array = size of 'struct cpu_map_entries' +
+        *           number of cpus * sizeof(u64)
+        *
+        *   mask  = size of 'struct cpu_map_mask' +
+        *           maximum cpu bit converted to size of longs
+        *
+        * and finaly + the size of 'struct cpu_map_data'.
+        */
+       size_cpus = cpus_size(map);
+       size_mask = mask_size(map, max);
+
+       if (is_dummy || (size_cpus < size_mask)) {
+               *size += size_cpus;
+               *type  = PERF_CPU_MAP__CPUS;
+       } else {
+               *size += size_mask;
+               *type  = PERF_CPU_MAP__MASK;
+       }
+
+       *size += sizeof(struct cpu_map_data);
+       return zalloc(*size);
+}
+
+void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map,
+                             u16 type, int max)
+{
+       data->type = type;
+
+       switch (type) {
+       case PERF_CPU_MAP__CPUS:
+               synthesize_cpus((struct cpu_map_entries *) data->data, map);
+               break;
+       case PERF_CPU_MAP__MASK:
+               synthesize_mask((struct cpu_map_mask *) data->data, map, max);
+       default:
+               break;
+       };
+}
+
+static struct cpu_map_event* cpu_map_event__new(struct cpu_map *map)
+{
+       size_t size = sizeof(struct cpu_map_event);
+       struct cpu_map_event *event;
+       int max;
+       u16 type;
+
+       event = cpu_map_data__alloc(map, &size, &type, &max);
+       if (!event)
+               return NULL;
+
+       event->header.type = PERF_RECORD_CPU_MAP;
+       event->header.size = size;
+       event->data.type   = type;
+
+       cpu_map_data__synthesize(&event->data, map, type, max);
+       return event;
+}
+
+int perf_event__synthesize_cpu_map(struct perf_tool *tool,
+                                  struct cpu_map *map,
+                                  perf_event__handler_t process,
+                                  struct machine *machine)
+{
+       struct cpu_map_event *event;
+       int err;
+
+       event = cpu_map_event__new(map);
+       if (!event)
+               return -ENOMEM;
+
+       err = process(tool, (union perf_event *) event, NULL, machine);
+
+       free(event);
+       return err;
+}
+
+int perf_event__synthesize_stat_config(struct perf_tool *tool,
+                                      struct perf_stat_config *config,
+                                      perf_event__handler_t process,
+                                      struct machine *machine)
+{
+       struct stat_config_event *event;
+       int size, i = 0, err;
+
+       size  = sizeof(*event);
+       size += (PERF_STAT_CONFIG_TERM__MAX * sizeof(event->data[0]));
+
+       event = zalloc(size);
+       if (!event)
+               return -ENOMEM;
+
+       event->header.type = PERF_RECORD_STAT_CONFIG;
+       event->header.size = size;
+       event->nr          = PERF_STAT_CONFIG_TERM__MAX;
+
+#define ADD(__term, __val)                                     \
+       event->data[i].tag = PERF_STAT_CONFIG_TERM__##__term;   \
+       event->data[i].val = __val;                             \
+       i++;
+
+       ADD(AGGR_MODE,  config->aggr_mode)
+       ADD(INTERVAL,   config->interval)
+       ADD(SCALE,      config->scale)
+
+       WARN_ONCE(i != PERF_STAT_CONFIG_TERM__MAX,
+                 "stat config terms unbalanced\n");
+#undef ADD
+
+       err = process(tool, (union perf_event *) event, NULL, machine);
+
+       free(event);
+       return err;
+}
+
+int perf_event__synthesize_stat(struct perf_tool *tool,
+                               u32 cpu, u32 thread, u64 id,
+                               struct perf_counts_values *count,
+                               perf_event__handler_t process,
+                               struct machine *machine)
+{
+       struct stat_event event;
+
+       event.header.type = PERF_RECORD_STAT;
+       event.header.size = sizeof(event);
+       event.header.misc = 0;
+
+       event.id        = id;
+       event.cpu       = cpu;
+       event.thread    = thread;
+       event.val       = count->val;
+       event.ena       = count->ena;
+       event.run       = count->run;
+
+       return process(tool, (union perf_event *) &event, NULL, machine);
+}
+
+int perf_event__synthesize_stat_round(struct perf_tool *tool,
+                                     u64 evtime, u64 type,
+                                     perf_event__handler_t process,
+                                     struct machine *machine)
+{
+       struct stat_round_event event;
+
+       event.header.type = PERF_RECORD_STAT_ROUND;
+       event.header.size = sizeof(event);
+       event.header.misc = 0;
+
+       event.time = evtime;
+       event.type = type;
+
+       return process(tool, (union perf_event *) &event, NULL, machine);
+}
+
+void perf_event__read_stat_config(struct perf_stat_config *config,
+                                 struct stat_config_event *event)
+{
+       unsigned i;
+
+       for (i = 0; i < event->nr; i++) {
+
+               switch (event->data[i].tag) {
+#define CASE(__term, __val)                                    \
+               case PERF_STAT_CONFIG_TERM__##__term:           \
+                       config->__val = event->data[i].val;     \
+                       break;
+
+               CASE(AGGR_MODE, aggr_mode)
+               CASE(SCALE,     scale)
+               CASE(INTERVAL,  interval)
+#undef CASE
+               default:
+                       pr_warning("unknown stat config term %" PRIu64 "\n",
+                                  event->data[i].tag);
+               }
+       }
+}
+
 size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
 {
        const char *s;
@@ -783,6 +1059,38 @@ size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
                       event->mmap2.filename);
 }
 
+size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp)
+{
+       struct thread_map *threads = thread_map__new_event(&event->thread_map);
+       size_t ret;
+
+       ret = fprintf(fp, " nr: ");
+
+       if (threads)
+               ret += thread_map__fprintf(threads, fp);
+       else
+               ret += fprintf(fp, "failed to get threads from event\n");
+
+       thread_map__put(threads);
+       return ret;
+}
+
+size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp)
+{
+       struct cpu_map *cpus = cpu_map__new_data(&event->cpu_map.data);
+       size_t ret;
+
+       ret = fprintf(fp, " nr: ");
+
+       if (cpus)
+               ret += cpu_map__fprintf(cpus, fp);
+       else
+               ret += fprintf(fp, "failed to get cpumap from event\n");
+
+       cpu_map__put(cpus);
+       return ret;
+}
+
 int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
                             union perf_event *event,
                             struct perf_sample *sample,
index a0dbcbd4f6d82d6564d56e48c0672ea56cba45bc..b7ffb7ee9971f020f1b2320baa478ed1421a01e9 100644 (file)
@@ -226,6 +226,12 @@ enum perf_user_event_type { /* above any possible kernel type */
        PERF_RECORD_AUXTRACE_INFO               = 70,
        PERF_RECORD_AUXTRACE                    = 71,
        PERF_RECORD_AUXTRACE_ERROR              = 72,
+       PERF_RECORD_THREAD_MAP                  = 73,
+       PERF_RECORD_CPU_MAP                     = 74,
+       PERF_RECORD_STAT_CONFIG                 = 75,
+       PERF_RECORD_STAT                        = 76,
+       PERF_RECORD_STAT_ROUND                  = 77,
+       PERF_RECORD_EVENT_UPDATE                = 78,
        PERF_RECORD_HEADER_MAX
 };
 
@@ -270,12 +276,61 @@ struct events_stats {
        u32 nr_proc_map_timeout;
 };
 
+enum {
+       PERF_CPU_MAP__CPUS = 0,
+       PERF_CPU_MAP__MASK = 1,
+};
+
+struct cpu_map_entries {
+       u16     nr;
+       u16     cpu[];
+};
+
+struct cpu_map_mask {
+       u16     nr;
+       u16     long_size;
+       unsigned long mask[];
+};
+
+struct cpu_map_data {
+       u16     type;
+       char    data[];
+};
+
+struct cpu_map_event {
+       struct perf_event_header        header;
+       struct cpu_map_data             data;
+};
+
 struct attr_event {
        struct perf_event_header header;
        struct perf_event_attr attr;
        u64 id[];
 };
 
+enum {
+       PERF_EVENT_UPDATE__UNIT  = 0,
+       PERF_EVENT_UPDATE__SCALE = 1,
+       PERF_EVENT_UPDATE__NAME  = 2,
+       PERF_EVENT_UPDATE__CPUS  = 3,
+};
+
+struct event_update_event_cpus {
+       struct cpu_map_data cpus;
+};
+
+struct event_update_event_scale {
+       double scale;
+};
+
+struct event_update_event {
+       struct perf_event_header header;
+       u64 type;
+       u64 id;
+
+       char data[];
+};
+
 #define MAX_EVENT_NAME 64
 
 struct perf_trace_event_type {
@@ -356,6 +411,63 @@ struct context_switch_event {
        u32 next_prev_tid;
 };
 
+struct thread_map_event_entry {
+       u64     pid;
+       char    comm[16];
+};
+
+struct thread_map_event {
+       struct perf_event_header        header;
+       u64                             nr;
+       struct thread_map_event_entry   entries[];
+};
+
+enum {
+       PERF_STAT_CONFIG_TERM__AGGR_MODE        = 0,
+       PERF_STAT_CONFIG_TERM__INTERVAL         = 1,
+       PERF_STAT_CONFIG_TERM__SCALE            = 2,
+       PERF_STAT_CONFIG_TERM__MAX              = 3,
+};
+
+struct stat_config_event_entry {
+       u64     tag;
+       u64     val;
+};
+
+struct stat_config_event {
+       struct perf_event_header        header;
+       u64                             nr;
+       struct stat_config_event_entry  data[];
+};
+
+struct stat_event {
+       struct perf_event_header        header;
+
+       u64     id;
+       u32     cpu;
+       u32     thread;
+
+       union {
+               struct {
+                       u64 val;
+                       u64 ena;
+                       u64 run;
+               };
+               u64 values[3];
+       };
+};
+
+enum {
+       PERF_STAT_ROUND_TYPE__INTERVAL  = 0,
+       PERF_STAT_ROUND_TYPE__FINAL     = 1,
+};
+
+struct stat_round_event {
+       struct perf_event_header        header;
+       u64                             type;
+       u64                             time;
+};
+
 union perf_event {
        struct perf_event_header        header;
        struct mmap_event               mmap;
@@ -368,6 +480,7 @@ union perf_event {
        struct throttle_event           throttle;
        struct sample_event             sample;
        struct attr_event               attr;
+       struct event_update_event       event_update;
        struct event_type_event         event_type;
        struct tracing_data_event       tracing_data;
        struct build_id_event           build_id;
@@ -378,12 +491,20 @@ union perf_event {
        struct aux_event                aux;
        struct itrace_start_event       itrace_start;
        struct context_switch_event     context_switch;
+       struct thread_map_event         thread_map;
+       struct cpu_map_event            cpu_map;
+       struct stat_config_event        stat_config;
+       struct stat_event               stat;
+       struct stat_round_event         stat_round;
 };
 
 void perf_event__print_totals(void);
 
 struct perf_tool;
 struct thread_map;
+struct cpu_map;
+struct perf_stat_config;
+struct perf_counts_values;
 
 typedef int (*perf_event__handler_t)(struct perf_tool *tool,
                                     union perf_event *event,
@@ -395,6 +516,14 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
                                      perf_event__handler_t process,
                                      struct machine *machine, bool mmap_data,
                                      unsigned int proc_map_timeout);
+int perf_event__synthesize_thread_map2(struct perf_tool *tool,
+                                     struct thread_map *threads,
+                                     perf_event__handler_t process,
+                                     struct machine *machine);
+int perf_event__synthesize_cpu_map(struct perf_tool *tool,
+                                  struct cpu_map *cpus,
+                                  perf_event__handler_t process,
+                                  struct machine *machine);
 int perf_event__synthesize_threads(struct perf_tool *tool,
                                   perf_event__handler_t process,
                                   struct machine *machine, bool mmap_data,
@@ -402,7 +531,21 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
 int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
                                       perf_event__handler_t process,
                                       struct machine *machine);
-
+int perf_event__synthesize_stat_config(struct perf_tool *tool,
+                                      struct perf_stat_config *config,
+                                      perf_event__handler_t process,
+                                      struct machine *machine);
+void perf_event__read_stat_config(struct perf_stat_config *config,
+                                 struct stat_config_event *event);
+int perf_event__synthesize_stat(struct perf_tool *tool,
+                               u32 cpu, u32 thread, u64 id,
+                               struct perf_counts_values *count,
+                               perf_event__handler_t process,
+                               struct machine *machine);
+int perf_event__synthesize_stat_round(struct perf_tool *tool,
+                                     u64 time, u64 type,
+                                     perf_event__handler_t process,
+                                     struct machine *machine);
 int perf_event__synthesize_modules(struct perf_tool *tool,
                                   perf_event__handler_t process,
                                   struct machine *machine);
@@ -499,9 +642,14 @@ size_t perf_event__fprintf_task(union perf_event *event, FILE *fp);
 size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp);
 size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp);
 size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp);
+size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp);
+size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp);
 size_t perf_event__fprintf(union perf_event *event, FILE *fp);
 
 u64 kallsyms__get_function_start(const char *kallsyms_filename,
                                 const char *symbol_name);
 
+void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max);
+void  cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map,
+                              u16 type, int max);
 #endif /* __PERF_RECORD_H */
index d1392194a9a951bd3e1dd5c9b72fd383ede98439..d81f13de24769963f6c32c3f809a714e6868dc5e 100644 (file)
@@ -18,7 +18,7 @@
 #include <unistd.h>
 
 #include "parse-events.h"
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
 
 #include <sys/mman.h>
 
@@ -68,6 +68,18 @@ struct perf_evlist *perf_evlist__new_default(void)
        return evlist;
 }
 
+struct perf_evlist *perf_evlist__new_dummy(void)
+{
+       struct perf_evlist *evlist = perf_evlist__new();
+
+       if (evlist && perf_evlist__add_dummy(evlist)) {
+               perf_evlist__delete(evlist);
+               evlist = NULL;
+       }
+
+       return evlist;
+}
+
 /**
  * perf_evlist__set_id_pos - set the positions of event ids.
  * @evlist: selected event list
@@ -248,6 +260,22 @@ error:
        return -ENOMEM;
 }
 
+int perf_evlist__add_dummy(struct perf_evlist *evlist)
+{
+       struct perf_event_attr attr = {
+               .type   = PERF_TYPE_SOFTWARE,
+               .config = PERF_COUNT_SW_DUMMY,
+               .size   = sizeof(attr), /* to capture ABI version */
+       };
+       struct perf_evsel *evsel = perf_evsel__new(&attr);
+
+       if (evsel == NULL)
+               return -ENOMEM;
+
+       perf_evlist__add(evlist, evsel);
+       return 0;
+}
+
 static int perf_evlist__add_attrs(struct perf_evlist *evlist,
                                  struct perf_event_attr *attrs, size_t nr_attrs)
 {
@@ -336,20 +364,12 @@ static int perf_evlist__nr_threads(struct perf_evlist *evlist,
 
 void perf_evlist__disable(struct perf_evlist *evlist)
 {
-       int cpu, thread;
        struct perf_evsel *pos;
-       int nr_cpus = cpu_map__nr(evlist->cpus);
-       int nr_threads;
 
-       for (cpu = 0; cpu < nr_cpus; cpu++) {
-               evlist__for_each(evlist, pos) {
-                       if (!perf_evsel__is_group_leader(pos) || !pos->fd)
-                               continue;
-                       nr_threads = perf_evlist__nr_threads(evlist, pos);
-                       for (thread = 0; thread < nr_threads; thread++)
-                               ioctl(FD(pos, cpu, thread),
-                                     PERF_EVENT_IOC_DISABLE, 0);
-               }
+       evlist__for_each(evlist, pos) {
+               if (!perf_evsel__is_group_leader(pos) || !pos->fd)
+                       continue;
+               perf_evsel__disable(pos);
        }
 
        evlist->enabled = false;
@@ -357,20 +377,12 @@ void perf_evlist__disable(struct perf_evlist *evlist)
 
 void perf_evlist__enable(struct perf_evlist *evlist)
 {
-       int cpu, thread;
        struct perf_evsel *pos;
-       int nr_cpus = cpu_map__nr(evlist->cpus);
-       int nr_threads;
 
-       for (cpu = 0; cpu < nr_cpus; cpu++) {
-               evlist__for_each(evlist, pos) {
-                       if (!perf_evsel__is_group_leader(pos) || !pos->fd)
-                               continue;
-                       nr_threads = perf_evlist__nr_threads(evlist, pos);
-                       for (thread = 0; thread < nr_threads; thread++)
-                               ioctl(FD(pos, cpu, thread),
-                                     PERF_EVENT_IOC_ENABLE, 0);
-               }
+       evlist__for_each(evlist, pos) {
+               if (!perf_evsel__is_group_leader(pos) || !pos->fd)
+                       continue;
+               perf_evsel__enable(pos);
        }
 
        evlist->enabled = true;
@@ -381,48 +393,6 @@ void perf_evlist__toggle_enable(struct perf_evlist *evlist)
        (evlist->enabled ? perf_evlist__disable : perf_evlist__enable)(evlist);
 }
 
-int perf_evlist__disable_event(struct perf_evlist *evlist,
-                              struct perf_evsel *evsel)
-{
-       int cpu, thread, err;
-       int nr_cpus = cpu_map__nr(evlist->cpus);
-       int nr_threads = perf_evlist__nr_threads(evlist, evsel);
-
-       if (!evsel->fd)
-               return 0;
-
-       for (cpu = 0; cpu < nr_cpus; cpu++) {
-               for (thread = 0; thread < nr_threads; thread++) {
-                       err = ioctl(FD(evsel, cpu, thread),
-                                   PERF_EVENT_IOC_DISABLE, 0);
-                       if (err)
-                               return err;
-               }
-       }
-       return 0;
-}
-
-int perf_evlist__enable_event(struct perf_evlist *evlist,
-                             struct perf_evsel *evsel)
-{
-       int cpu, thread, err;
-       int nr_cpus = cpu_map__nr(evlist->cpus);
-       int nr_threads = perf_evlist__nr_threads(evlist, evsel);
-
-       if (!evsel->fd)
-               return -EINVAL;
-
-       for (cpu = 0; cpu < nr_cpus; cpu++) {
-               for (thread = 0; thread < nr_threads; thread++) {
-                       err = ioctl(FD(evsel, cpu, thread),
-                                   PERF_EVENT_IOC_ENABLE, 0);
-                       if (err)
-                               return err;
-               }
-       }
-       return 0;
-}
-
 static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist,
                                         struct perf_evsel *evsel, int cpu)
 {
@@ -550,9 +520,9 @@ void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
        evsel->id[evsel->ids++] = id;
 }
 
-static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
-                                 struct perf_evsel *evsel,
-                                 int cpu, int thread, int fd)
+int perf_evlist__id_add_fd(struct perf_evlist *evlist,
+                          struct perf_evsel *evsel,
+                          int cpu, int thread, int fd)
 {
        u64 read_data[4] = { 0, };
        int id_idx = 1; /* The first entry is the counter value */
@@ -1486,7 +1456,7 @@ int perf_evlist__open(struct perf_evlist *evlist)
        perf_evlist__update_id_pos(evlist);
 
        evlist__for_each(evlist, evsel) {
-               err = perf_evsel__open(evsel, evlist->cpus, evlist->threads);
+               err = perf_evsel__open(evsel, evsel->cpus, evsel->threads);
                if (err < 0)
                        goto out_err;
        }
index a459fe71b452e0b721d798cc73cc6287ae87dc1c..7c4d9a2067769b0e3de2d96a11e6f7dd7d62106a 100644 (file)
@@ -67,6 +67,7 @@ struct perf_evsel_str_handler {
 
 struct perf_evlist *perf_evlist__new(void);
 struct perf_evlist *perf_evlist__new_default(void);
+struct perf_evlist *perf_evlist__new_dummy(void);
 void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
                       struct thread_map *threads);
 void perf_evlist__exit(struct perf_evlist *evlist);
@@ -81,6 +82,8 @@ int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,
 #define perf_evlist__add_default_attrs(evlist, array) \
        __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array))
 
+int perf_evlist__add_dummy(struct perf_evlist *evlist);
+
 int perf_evlist__add_newtp(struct perf_evlist *evlist,
                           const char *sys, const char *name, void *handler);
 
@@ -97,6 +100,9 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist,
 
 void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
                         int cpu, int thread, u64 id);
+int perf_evlist__id_add_fd(struct perf_evlist *evlist,
+                          struct perf_evsel *evsel,
+                          int cpu, int thread, int fd);
 
 int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
 int perf_evlist__alloc_pollfd(struct perf_evlist *evlist);
@@ -149,10 +155,6 @@ void perf_evlist__disable(struct perf_evlist *evlist);
 void perf_evlist__enable(struct perf_evlist *evlist);
 void perf_evlist__toggle_enable(struct perf_evlist *evlist);
 
-int perf_evlist__disable_event(struct perf_evlist *evlist,
-                              struct perf_evsel *evsel);
-int perf_evlist__enable_event(struct perf_evlist *evlist,
-                             struct perf_evsel *evsel);
 int perf_evlist__enable_event_idx(struct perf_evlist *evlist,
                                  struct perf_evsel *evsel, int idx);
 
index 397fb4ed3c97b6deffeffd8f69bbceb886ac58ea..cdbaf9b51e428ad4537a38ded24ee07bec54e90c 100644 (file)
@@ -36,6 +36,7 @@ static struct {
        bool cloexec;
        bool clockid;
        bool clockid_wrong;
+       bool lbr_flags;
 } perf_missing_features;
 
 static clockid_t clockid;
@@ -574,7 +575,9 @@ perf_evsel__config_callgraph(struct perf_evsel *evsel,
                        } else {
                                perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
                                attr->branch_sample_type = PERF_SAMPLE_BRANCH_USER |
-                                                       PERF_SAMPLE_BRANCH_CALL_STACK;
+                                                       PERF_SAMPLE_BRANCH_CALL_STACK |
+                                                       PERF_SAMPLE_BRANCH_NO_CYCLES |
+                                                       PERF_SAMPLE_BRANCH_NO_FLAGS;
                        }
                } else
                         pr_warning("Cannot use LBR callstack with branch stack. "
@@ -981,13 +984,26 @@ int perf_evsel__append_filter(struct perf_evsel *evsel,
        return -1;
 }
 
-int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads)
+int perf_evsel__enable(struct perf_evsel *evsel)
 {
+       int nthreads = thread_map__nr(evsel->threads);
+       int ncpus = cpu_map__nr(evsel->cpus);
+
        return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
                                     PERF_EVENT_IOC_ENABLE,
                                     0);
 }
 
+int perf_evsel__disable(struct perf_evsel *evsel)
+{
+       int nthreads = thread_map__nr(evsel->threads);
+       int ncpus = cpu_map__nr(evsel->cpus);
+
+       return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
+                                    PERF_EVENT_IOC_DISABLE,
+                                    0);
+}
+
 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
        if (ncpus == 0 || nthreads == 0)
@@ -1192,6 +1208,7 @@ static void __p_sample_type(char *buf, size_t size, u64 value)
                bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW),
                bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER),
                bit_name(IDENTIFIER), bit_name(REGS_INTR), bit_name(DATA_SRC),
+               bit_name(WEIGHT),
                { .name = NULL, }
        };
 #undef bit_name
@@ -1323,6 +1340,9 @@ fallback_missing_features:
                evsel->attr.mmap2 = 0;
        if (perf_missing_features.exclude_guest)
                evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
+       if (perf_missing_features.lbr_flags)
+               evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS |
+                                    PERF_SAMPLE_BRANCH_NO_CYCLES);
 retry_sample_id:
        if (perf_missing_features.sample_id_all)
                evsel->attr.sample_id_all = 0;
@@ -1441,6 +1461,12 @@ try_fallback:
        } else if (!perf_missing_features.sample_id_all) {
                perf_missing_features.sample_id_all = true;
                goto retry_sample_id;
+       } else if (!perf_missing_features.lbr_flags &&
+                       (evsel->attr.branch_sample_type &
+                        (PERF_SAMPLE_BRANCH_NO_CYCLES |
+                         PERF_SAMPLE_BRANCH_NO_FLAGS))) {
+               perf_missing_features.lbr_flags = true;
+               goto fallback_missing_features;
        }
 
 out_close:
@@ -2272,6 +2298,29 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
                printed += comma_fprintf(fp, &first, " %s=%" PRIu64,
                                         term, (u64)evsel->attr.sample_freq);
        }
+
+       if (details->trace_fields) {
+               struct format_field *field;
+
+               if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
+                       printed += comma_fprintf(fp, &first, " (not a tracepoint)");
+                       goto out;
+               }
+
+               field = evsel->tp_format->format.fields;
+               if (field == NULL) {
+                       printed += comma_fprintf(fp, &first, " (no trace field)");
+                       goto out;
+               }
+
+               printed += comma_fprintf(fp, &first, " trace_fields: %s", field->name);
+
+               field = field->next;
+               while (field) {
+                       printed += comma_fprintf(fp, &first, "%s", field->name);
+                       field = field->next;
+               }
+       }
 out:
        fputc('\n', fp);
        return ++printed;
index 0e49bd742c639c02d1aef18f421c0204faa95823..8e75434bd01c671a8ed2e0c0b03a139212d7001c 100644 (file)
@@ -227,7 +227,8 @@ int perf_evsel__append_filter(struct perf_evsel *evsel,
                              const char *op, const char *filter);
 int perf_evsel__apply_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
                             const char *filter);
-int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads);
+int perf_evsel__enable(struct perf_evsel *evsel);
+int perf_evsel__disable(struct perf_evsel *evsel);
 
 int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
                             struct cpu_map *cpus);
@@ -368,6 +369,7 @@ struct perf_attr_details {
        bool verbose;
        bool event_group;
        bool force;
+       bool trace_fields;
 };
 
 int perf_evsel__fprintf(struct perf_evsel *evsel,
diff --git a/tools/perf/util/exec_cmd.c b/tools/perf/util/exec_cmd.c
deleted file mode 100644 (file)
index 7adf4ad..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-#include "cache.h"
-#include "exec_cmd.h"
-#include "quote.h"
-
-#include <string.h>
-
-#define MAX_ARGS       32
-
-static const char *argv_exec_path;
-static const char *argv0_path;
-
-const char *system_path(const char *path)
-{
-       static const char *prefix = PREFIX;
-       struct strbuf d = STRBUF_INIT;
-
-       if (is_absolute_path(path))
-               return path;
-
-       strbuf_addf(&d, "%s/%s", prefix, path);
-       path = strbuf_detach(&d, NULL);
-       return path;
-}
-
-const char *perf_extract_argv0_path(const char *argv0)
-{
-       const char *slash;
-
-       if (!argv0 || !*argv0)
-               return NULL;
-       slash = argv0 + strlen(argv0);
-
-       while (argv0 <= slash && !is_dir_sep(*slash))
-               slash--;
-
-       if (slash >= argv0) {
-               argv0_path = strndup(argv0, slash - argv0);
-               return argv0_path ? slash + 1 : NULL;
-       }
-
-       return argv0;
-}
-
-void perf_set_argv_exec_path(const char *exec_path)
-{
-       argv_exec_path = exec_path;
-       /*
-        * Propagate this setting to external programs.
-        */
-       setenv(EXEC_PATH_ENVIRONMENT, exec_path, 1);
-}
-
-
-/* Returns the highest-priority, location to look for perf programs. */
-const char *perf_exec_path(void)
-{
-       const char *env;
-
-       if (argv_exec_path)
-               return argv_exec_path;
-
-       env = getenv(EXEC_PATH_ENVIRONMENT);
-       if (env && *env) {
-               return env;
-       }
-
-       return system_path(PERF_EXEC_PATH);
-}
-
-static void add_path(struct strbuf *out, const char *path)
-{
-       if (path && *path) {
-               if (is_absolute_path(path))
-                       strbuf_addstr(out, path);
-               else
-                       strbuf_addstr(out, make_nonrelative_path(path));
-
-               strbuf_addch(out, PATH_SEP);
-       }
-}
-
-void setup_path(void)
-{
-       const char *old_path = getenv("PATH");
-       struct strbuf new_path = STRBUF_INIT;
-
-       add_path(&new_path, perf_exec_path());
-       add_path(&new_path, argv0_path);
-
-       if (old_path)
-               strbuf_addstr(&new_path, old_path);
-       else
-               strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin");
-
-       setenv("PATH", new_path.buf, 1);
-
-       strbuf_release(&new_path);
-}
-
-static const char **prepare_perf_cmd(const char **argv)
-{
-       int argc;
-       const char **nargv;
-
-       for (argc = 0; argv[argc]; argc++)
-               ; /* just counting */
-       nargv = malloc(sizeof(*nargv) * (argc + 2));
-
-       nargv[0] = "perf";
-       for (argc = 0; argv[argc]; argc++)
-               nargv[argc + 1] = argv[argc];
-       nargv[argc + 1] = NULL;
-       return nargv;
-}
-
-int execv_perf_cmd(const char **argv) {
-       const char **nargv = prepare_perf_cmd(argv);
-
-       /* execvp() can only ever return if it fails */
-       execvp("perf", (char **)nargv);
-
-       free(nargv);
-       return -1;
-}
-
-
-int execl_perf_cmd(const char *cmd,...)
-{
-       int argc;
-       const char *argv[MAX_ARGS + 1];
-       const char *arg;
-       va_list param;
-
-       va_start(param, cmd);
-       argv[0] = cmd;
-       argc = 1;
-       while (argc < MAX_ARGS) {
-               arg = argv[argc++] = va_arg(param, char *);
-               if (!arg)
-                       break;
-       }
-       va_end(param);
-       if (MAX_ARGS <= argc)
-               return error("too many args to run %s", cmd);
-
-       argv[argc] = NULL;
-       return execv_perf_cmd(argv);
-}
diff --git a/tools/perf/util/exec_cmd.h b/tools/perf/util/exec_cmd.h
deleted file mode 100644 (file)
index bc4b915..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __PERF_EXEC_CMD_H
-#define __PERF_EXEC_CMD_H
-
-extern void perf_set_argv_exec_path(const char *exec_path);
-extern const char *perf_extract_argv0_path(const char *path);
-extern const char *perf_exec_path(void);
-extern void setup_path(void);
-extern int execv_perf_cmd(const char **argv); /* NULL terminated */
-extern int execl_perf_cmd(const char *cmd, ...);
-extern const char *system_path(const char *path);
-
-#endif /* __PERF_EXEC_CMD_H */
index 36a885d2cd22d12ed004177f375bcaf4aac86a28..0ac2037c970c9c5f1b62b554809fb9a4f4dd6e00 100755 (executable)
@@ -36,4 +36,19 @@ do
      }' "Documentation/perf-$cmd.txt"
 done
 echo "#endif /* HAVE_LIBELF_SUPPORT */"
+
+echo "#ifdef HAVE_LIBAUDIT_SUPPORT"
+sed -n -e 's/^perf-\([^        ]*\)[   ].* audit*/\1/p' command-list.txt |
+sort |
+while read cmd
+do
+     sed -n '
+     /^NAME/,/perf-'"$cmd"'/H
+     ${
+            x
+            s/.*perf-'"$cmd"' - \(.*\)/  {"'"$cmd"'", "\1"},/
+           p
+     }' "Documentation/perf-$cmd.txt"
+done
+echo "#endif /* HAVE_LIBELF_SUPPORT */"
 echo "};"
index 43838003c1a160ff56a0ae72a70dcef68631fe2f..f50b7235ecb6558d167a475bf4199e8b05f52143 100644 (file)
@@ -724,7 +724,7 @@ static int write_numa_topology(int fd, struct perf_header *h __maybe_unused,
 done:
        free(buf);
        fclose(fp);
-       free(node_map);
+       cpu_map__put(node_map);
        return ret;
 }
 
@@ -868,6 +868,13 @@ static int write_auxtrace(int fd, struct perf_header *h,
        return err;
 }
 
+static int write_stat(int fd __maybe_unused,
+                     struct perf_header *h __maybe_unused,
+                     struct perf_evlist *evlist __maybe_unused)
+{
+       return 0;
+}
+
 static void print_hostname(struct perf_header *ph, int fd __maybe_unused,
                           FILE *fp)
 {
@@ -1159,6 +1166,12 @@ static void print_auxtrace(struct perf_header *ph __maybe_unused,
        fprintf(fp, "# contains AUX area data (e.g. instruction trace)\n");
 }
 
+static void print_stat(struct perf_header *ph __maybe_unused,
+                      int fd __maybe_unused, FILE *fp)
+{
+       fprintf(fp, "# contains stat data\n");
+}
+
 static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused,
                               FILE *fp)
 {
@@ -1948,6 +1961,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
        FEAT_OPP(HEADER_PMU_MAPPINGS,   pmu_mappings),
        FEAT_OPP(HEADER_GROUP_DESC,     group_desc),
        FEAT_OPP(HEADER_AUXTRACE,       auxtrace),
+       FEAT_OPA(HEADER_STAT,           stat),
 };
 
 struct header_print_data {
@@ -2686,6 +2700,152 @@ int perf_event__synthesize_attr(struct perf_tool *tool,
        return err;
 }
 
+static struct event_update_event *
+event_update_event__new(size_t size, u64 type, u64 id)
+{
+       struct event_update_event *ev;
+
+       size += sizeof(*ev);
+       size  = PERF_ALIGN(size, sizeof(u64));
+
+       ev = zalloc(size);
+       if (ev) {
+               ev->header.type = PERF_RECORD_EVENT_UPDATE;
+               ev->header.size = (u16)size;
+               ev->type = type;
+               ev->id = id;
+       }
+       return ev;
+}
+
+int
+perf_event__synthesize_event_update_unit(struct perf_tool *tool,
+                                        struct perf_evsel *evsel,
+                                        perf_event__handler_t process)
+{
+       struct event_update_event *ev;
+       size_t size = strlen(evsel->unit);
+       int err;
+
+       ev = event_update_event__new(size + 1, PERF_EVENT_UPDATE__UNIT, evsel->id[0]);
+       if (ev == NULL)
+               return -ENOMEM;
+
+       strncpy(ev->data, evsel->unit, size);
+       err = process(tool, (union perf_event *)ev, NULL, NULL);
+       free(ev);
+       return err;
+}
+
+int
+perf_event__synthesize_event_update_scale(struct perf_tool *tool,
+                                         struct perf_evsel *evsel,
+                                         perf_event__handler_t process)
+{
+       struct event_update_event *ev;
+       struct event_update_event_scale *ev_data;
+       int err;
+
+       ev = event_update_event__new(sizeof(*ev_data), PERF_EVENT_UPDATE__SCALE, evsel->id[0]);
+       if (ev == NULL)
+               return -ENOMEM;
+
+       ev_data = (struct event_update_event_scale *) ev->data;
+       ev_data->scale = evsel->scale;
+       err = process(tool, (union perf_event*) ev, NULL, NULL);
+       free(ev);
+       return err;
+}
+
+int
+perf_event__synthesize_event_update_name(struct perf_tool *tool,
+                                        struct perf_evsel *evsel,
+                                        perf_event__handler_t process)
+{
+       struct event_update_event *ev;
+       size_t len = strlen(evsel->name);
+       int err;
+
+       ev = event_update_event__new(len + 1, PERF_EVENT_UPDATE__NAME, evsel->id[0]);
+       if (ev == NULL)
+               return -ENOMEM;
+
+       strncpy(ev->data, evsel->name, len);
+       err = process(tool, (union perf_event*) ev, NULL, NULL);
+       free(ev);
+       return err;
+}
+
+int
+perf_event__synthesize_event_update_cpus(struct perf_tool *tool,
+                                       struct perf_evsel *evsel,
+                                       perf_event__handler_t process)
+{
+       size_t size = sizeof(struct event_update_event);
+       struct event_update_event *ev;
+       int max, err;
+       u16 type;
+
+       if (!evsel->own_cpus)
+               return 0;
+
+       ev = cpu_map_data__alloc(evsel->own_cpus, &size, &type, &max);
+       if (!ev)
+               return -ENOMEM;
+
+       ev->header.type = PERF_RECORD_EVENT_UPDATE;
+       ev->header.size = (u16)size;
+       ev->type = PERF_EVENT_UPDATE__CPUS;
+       ev->id   = evsel->id[0];
+
+       cpu_map_data__synthesize((struct cpu_map_data *) ev->data,
+                                evsel->own_cpus,
+                                type, max);
+
+       err = process(tool, (union perf_event*) ev, NULL, NULL);
+       free(ev);
+       return err;
+}
+
+size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp)
+{
+       struct event_update_event *ev = &event->event_update;
+       struct event_update_event_scale *ev_scale;
+       struct event_update_event_cpus *ev_cpus;
+       struct cpu_map *map;
+       size_t ret;
+
+       ret = fprintf(fp, "\n... id:    %" PRIu64 "\n", ev->id);
+
+       switch (ev->type) {
+       case PERF_EVENT_UPDATE__SCALE:
+               ev_scale = (struct event_update_event_scale *) ev->data;
+               ret += fprintf(fp, "... scale: %f\n", ev_scale->scale);
+               break;
+       case PERF_EVENT_UPDATE__UNIT:
+               ret += fprintf(fp, "... unit:  %s\n", ev->data);
+               break;
+       case PERF_EVENT_UPDATE__NAME:
+               ret += fprintf(fp, "... name:  %s\n", ev->data);
+               break;
+       case PERF_EVENT_UPDATE__CPUS:
+               ev_cpus = (struct event_update_event_cpus *) ev->data;
+               ret += fprintf(fp, "... ");
+
+               map = cpu_map__new_data(&ev_cpus->cpus);
+               if (map)
+                       ret += cpu_map__fprintf(map, fp);
+               else
+                       ret += fprintf(fp, "failed to get cpus\n");
+               break;
+       default:
+               ret += fprintf(fp, "... unknown type\n");
+               break;
+       }
+
+       return ret;
+}
+
 int perf_event__synthesize_attrs(struct perf_tool *tool,
                                   struct perf_session *session,
                                   perf_event__handler_t process)
@@ -2745,6 +2905,51 @@ int perf_event__process_attr(struct perf_tool *tool __maybe_unused,
        return 0;
 }
 
+int perf_event__process_event_update(struct perf_tool *tool __maybe_unused,
+                                    union perf_event *event,
+                                    struct perf_evlist **pevlist)
+{
+       struct event_update_event *ev = &event->event_update;
+       struct event_update_event_scale *ev_scale;
+       struct event_update_event_cpus *ev_cpus;
+       struct perf_evlist *evlist;
+       struct perf_evsel *evsel;
+       struct cpu_map *map;
+
+       if (!pevlist || *pevlist == NULL)
+               return -EINVAL;
+
+       evlist = *pevlist;
+
+       evsel = perf_evlist__id2evsel(evlist, ev->id);
+       if (evsel == NULL)
+               return -EINVAL;
+
+       switch (ev->type) {
+       case PERF_EVENT_UPDATE__UNIT:
+               evsel->unit = strdup(ev->data);
+               break;
+       case PERF_EVENT_UPDATE__NAME:
+               evsel->name = strdup(ev->data);
+               break;
+       case PERF_EVENT_UPDATE__SCALE:
+               ev_scale = (struct event_update_event_scale *) ev->data;
+               evsel->scale = ev_scale->scale;
+       case PERF_EVENT_UPDATE__CPUS:
+               ev_cpus = (struct event_update_event_cpus *) ev->data;
+
+               map = cpu_map__new_data(&ev_cpus->cpus);
+               if (map)
+                       evsel->own_cpus = map;
+               else
+                       pr_err("failed to get event_update cpus\n");
+       default:
+               break;
+       }
+
+       return 0;
+}
+
 int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
                                        struct perf_evlist *evlist,
                                        perf_event__handler_t process)
index 05f27cb6b7e36a2e663f7c18fb22513bc5280af2..cff9892452ee393764726a12895ad95d36f766fe 100644 (file)
@@ -31,6 +31,7 @@ enum {
        HEADER_PMU_MAPPINGS,
        HEADER_GROUP_DESC,
        HEADER_AUXTRACE,
+       HEADER_STAT,
        HEADER_LAST_FEATURE,
        HEADER_FEAT_BITS        = 256,
 };
@@ -105,8 +106,24 @@ int perf_event__synthesize_attr(struct perf_tool *tool,
 int perf_event__synthesize_attrs(struct perf_tool *tool,
                                 struct perf_session *session,
                                 perf_event__handler_t process);
+int perf_event__synthesize_event_update_unit(struct perf_tool *tool,
+                                            struct perf_evsel *evsel,
+                                            perf_event__handler_t process);
+int perf_event__synthesize_event_update_scale(struct perf_tool *tool,
+                                             struct perf_evsel *evsel,
+                                             perf_event__handler_t process);
+int perf_event__synthesize_event_update_name(struct perf_tool *tool,
+                                            struct perf_evsel *evsel,
+                                            perf_event__handler_t process);
+int perf_event__synthesize_event_update_cpus(struct perf_tool *tool,
+                                            struct perf_evsel *evsel,
+                                            perf_event__handler_t process);
 int perf_event__process_attr(struct perf_tool *tool, union perf_event *event,
                             struct perf_evlist **pevlist);
+int perf_event__process_event_update(struct perf_tool *tool __maybe_unused,
+                                    union perf_event *event,
+                                    struct perf_evlist **pevlist);
+size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp);
 
 int perf_event__synthesize_tracing_data(struct perf_tool *tool,
                                        int fd, struct perf_evlist *evlist,
diff --git a/tools/perf/util/help-unknown-cmd.c b/tools/perf/util/help-unknown-cmd.c
new file mode 100644 (file)
index 0000000..dc1e41c
--- /dev/null
@@ -0,0 +1,103 @@
+#include "cache.h"
+#include <subcmd/help.h>
+#include "../builtin.h"
+#include "levenshtein.h"
+
+static int autocorrect;
+static struct cmdnames aliases;
+
+static int perf_unknown_cmd_config(const char *var, const char *value, void *cb)
+{
+       if (!strcmp(var, "help.autocorrect"))
+               autocorrect = perf_config_int(var,value);
+       /* Also use aliases for command lookup */
+       if (!prefixcmp(var, "alias."))
+               add_cmdname(&aliases, var + 6, strlen(var + 6));
+
+       return perf_default_config(var, value, cb);
+}
+
+static int levenshtein_compare(const void *p1, const void *p2)
+{
+       const struct cmdname *const *c1 = p1, *const *c2 = p2;
+       const char *s1 = (*c1)->name, *s2 = (*c2)->name;
+       int l1 = (*c1)->len;
+       int l2 = (*c2)->len;
+       return l1 != l2 ? l1 - l2 : strcmp(s1, s2);
+}
+
+static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
+{
+       unsigned int i;
+
+       ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc);
+
+       for (i = 0; i < old->cnt; i++)
+               cmds->names[cmds->cnt++] = old->names[i];
+       zfree(&old->names);
+       old->cnt = 0;
+}
+
+const char *help_unknown_cmd(const char *cmd)
+{
+       unsigned int i, n = 0, best_similarity = 0;
+       struct cmdnames main_cmds, other_cmds;
+
+       memset(&main_cmds, 0, sizeof(main_cmds));
+       memset(&other_cmds, 0, sizeof(main_cmds));
+       memset(&aliases, 0, sizeof(aliases));
+
+       perf_config(perf_unknown_cmd_config, NULL);
+
+       load_command_list("perf-", &main_cmds, &other_cmds);
+
+       add_cmd_list(&main_cmds, &aliases);
+       add_cmd_list(&main_cmds, &other_cmds);
+       qsort(main_cmds.names, main_cmds.cnt,
+             sizeof(main_cmds.names), cmdname_compare);
+       uniq(&main_cmds);
+
+       if (main_cmds.cnt) {
+               /* This reuses cmdname->len for similarity index */
+               for (i = 0; i < main_cmds.cnt; ++i)
+                       main_cmds.names[i]->len =
+                               levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);
+
+               qsort(main_cmds.names, main_cmds.cnt,
+                     sizeof(*main_cmds.names), levenshtein_compare);
+
+               best_similarity = main_cmds.names[0]->len;
+               n = 1;
+               while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)
+                       ++n;
+       }
+
+       if (autocorrect && n == 1) {
+               const char *assumed = main_cmds.names[0]->name;
+
+               main_cmds.names[0] = NULL;
+               clean_cmdnames(&main_cmds);
+               fprintf(stderr, "WARNING: You called a perf program named '%s', "
+                       "which does not exist.\n"
+                       "Continuing under the assumption that you meant '%s'\n",
+                       cmd, assumed);
+               if (autocorrect > 0) {
+                       fprintf(stderr, "in %0.1f seconds automatically...\n",
+                               (float)autocorrect/10.0);
+                       poll(NULL, 0, autocorrect * 100);
+               }
+               return assumed;
+       }
+
+       fprintf(stderr, "perf: '%s' is not a perf-command. See 'perf --help'.\n", cmd);
+
+       if (main_cmds.cnt && best_similarity < 6) {
+               fprintf(stderr, "\nDid you mean %s?\n",
+                       n < 2 ? "this": "one of these");
+
+               for (i = 0; i < n; i++)
+                       fprintf(stderr, "\t%s\n", main_cmds.names[i]->name);
+       }
+
+       exit(1);
+}
diff --git a/tools/perf/util/help-unknown-cmd.h b/tools/perf/util/help-unknown-cmd.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tools/perf/util/help.c b/tools/perf/util/help.c
deleted file mode 100644 (file)
index 86c37c4..0000000
+++ /dev/null
@@ -1,339 +0,0 @@
-#include "cache.h"
-#include "../builtin.h"
-#include "exec_cmd.h"
-#include "levenshtein.h"
-#include "help.h"
-#include <termios.h>
-
-void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
-{
-       struct cmdname *ent = malloc(sizeof(*ent) + len + 1);
-
-       ent->len = len;
-       memcpy(ent->name, name, len);
-       ent->name[len] = 0;
-
-       ALLOC_GROW(cmds->names, cmds->cnt + 1, cmds->alloc);
-       cmds->names[cmds->cnt++] = ent;
-}
-
-static void clean_cmdnames(struct cmdnames *cmds)
-{
-       unsigned int i;
-
-       for (i = 0; i < cmds->cnt; ++i)
-               zfree(&cmds->names[i]);
-       zfree(&cmds->names);
-       cmds->cnt = 0;
-       cmds->alloc = 0;
-}
-
-static int cmdname_compare(const void *a_, const void *b_)
-{
-       struct cmdname *a = *(struct cmdname **)a_;
-       struct cmdname *b = *(struct cmdname **)b_;
-       return strcmp(a->name, b->name);
-}
-
-static void uniq(struct cmdnames *cmds)
-{
-       unsigned int i, j;
-
-       if (!cmds->cnt)
-               return;
-
-       for (i = j = 1; i < cmds->cnt; i++)
-               if (strcmp(cmds->names[i]->name, cmds->names[i-1]->name))
-                       cmds->names[j++] = cmds->names[i];
-
-       cmds->cnt = j;
-}
-
-void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
-{
-       size_t ci, cj, ei;
-       int cmp;
-
-       ci = cj = ei = 0;
-       while (ci < cmds->cnt && ei < excludes->cnt) {
-               cmp = strcmp(cmds->names[ci]->name, excludes->names[ei]->name);
-               if (cmp < 0)
-                       cmds->names[cj++] = cmds->names[ci++];
-               else if (cmp == 0)
-                       ci++, ei++;
-               else if (cmp > 0)
-                       ei++;
-       }
-
-       while (ci < cmds->cnt)
-               cmds->names[cj++] = cmds->names[ci++];
-
-       cmds->cnt = cj;
-}
-
-static void pretty_print_string_list(struct cmdnames *cmds, int longest)
-{
-       int cols = 1, rows;
-       int space = longest + 1; /* min 1 SP between words */
-       struct winsize win;
-       int max_cols;
-       int i, j;
-
-       get_term_dimensions(&win);
-       max_cols = win.ws_col - 1; /* don't print *on* the edge */
-
-       if (space < max_cols)
-               cols = max_cols / space;
-       rows = (cmds->cnt + cols - 1) / cols;
-
-       for (i = 0; i < rows; i++) {
-               printf("  ");
-
-               for (j = 0; j < cols; j++) {
-                       unsigned int n = j * rows + i;
-                       unsigned int size = space;
-
-                       if (n >= cmds->cnt)
-                               break;
-                       if (j == cols-1 || n + rows >= cmds->cnt)
-                               size = 1;
-                       printf("%-*s", size, cmds->names[n]->name);
-               }
-               putchar('\n');
-       }
-}
-
-static int is_executable(const char *name)
-{
-       struct stat st;
-
-       if (stat(name, &st) || /* stat, not lstat */
-           !S_ISREG(st.st_mode))
-               return 0;
-
-       return st.st_mode & S_IXUSR;
-}
-
-static void list_commands_in_dir(struct cmdnames *cmds,
-                                        const char *path,
-                                        const char *prefix)
-{
-       int prefix_len;
-       DIR *dir = opendir(path);
-       struct dirent *de;
-       struct strbuf buf = STRBUF_INIT;
-       int len;
-
-       if (!dir)
-               return;
-       if (!prefix)
-               prefix = "perf-";
-       prefix_len = strlen(prefix);
-
-       strbuf_addf(&buf, "%s/", path);
-       len = buf.len;
-
-       while ((de = readdir(dir)) != NULL) {
-               int entlen;
-
-               if (prefixcmp(de->d_name, prefix))
-                       continue;
-
-               strbuf_setlen(&buf, len);
-               strbuf_addstr(&buf, de->d_name);
-               if (!is_executable(buf.buf))
-                       continue;
-
-               entlen = strlen(de->d_name) - prefix_len;
-               if (has_extension(de->d_name, ".exe"))
-                       entlen -= 4;
-
-               add_cmdname(cmds, de->d_name + prefix_len, entlen);
-       }
-       closedir(dir);
-       strbuf_release(&buf);
-}
-
-void load_command_list(const char *prefix,
-               struct cmdnames *main_cmds,
-               struct cmdnames *other_cmds)
-{
-       const char *env_path = getenv("PATH");
-       const char *exec_path = perf_exec_path();
-
-       if (exec_path) {
-               list_commands_in_dir(main_cmds, exec_path, prefix);
-               qsort(main_cmds->names, main_cmds->cnt,
-                     sizeof(*main_cmds->names), cmdname_compare);
-               uniq(main_cmds);
-       }
-
-       if (env_path) {
-               char *paths, *path, *colon;
-               path = paths = strdup(env_path);
-               while (1) {
-                       if ((colon = strchr(path, PATH_SEP)))
-                               *colon = 0;
-                       if (!exec_path || strcmp(path, exec_path))
-                               list_commands_in_dir(other_cmds, path, prefix);
-
-                       if (!colon)
-                               break;
-                       path = colon + 1;
-               }
-               free(paths);
-
-               qsort(other_cmds->names, other_cmds->cnt,
-                     sizeof(*other_cmds->names), cmdname_compare);
-               uniq(other_cmds);
-       }
-       exclude_cmds(other_cmds, main_cmds);
-}
-
-void list_commands(const char *title, struct cmdnames *main_cmds,
-                  struct cmdnames *other_cmds)
-{
-       unsigned int i, longest = 0;
-
-       for (i = 0; i < main_cmds->cnt; i++)
-               if (longest < main_cmds->names[i]->len)
-                       longest = main_cmds->names[i]->len;
-       for (i = 0; i < other_cmds->cnt; i++)
-               if (longest < other_cmds->names[i]->len)
-                       longest = other_cmds->names[i]->len;
-
-       if (main_cmds->cnt) {
-               const char *exec_path = perf_exec_path();
-               printf("available %s in '%s'\n", title, exec_path);
-               printf("----------------");
-               mput_char('-', strlen(title) + strlen(exec_path));
-               putchar('\n');
-               pretty_print_string_list(main_cmds, longest);
-               putchar('\n');
-       }
-
-       if (other_cmds->cnt) {
-               printf("%s available from elsewhere on your $PATH\n", title);
-               printf("---------------------------------------");
-               mput_char('-', strlen(title));
-               putchar('\n');
-               pretty_print_string_list(other_cmds, longest);
-               putchar('\n');
-       }
-}
-
-int is_in_cmdlist(struct cmdnames *c, const char *s)
-{
-       unsigned int i;
-
-       for (i = 0; i < c->cnt; i++)
-               if (!strcmp(s, c->names[i]->name))
-                       return 1;
-       return 0;
-}
-
-static int autocorrect;
-static struct cmdnames aliases;
-
-static int perf_unknown_cmd_config(const char *var, const char *value, void *cb)
-{
-       if (!strcmp(var, "help.autocorrect"))
-               autocorrect = perf_config_int(var,value);
-       /* Also use aliases for command lookup */
-       if (!prefixcmp(var, "alias."))
-               add_cmdname(&aliases, var + 6, strlen(var + 6));
-
-       return perf_default_config(var, value, cb);
-}
-
-static int levenshtein_compare(const void *p1, const void *p2)
-{
-       const struct cmdname *const *c1 = p1, *const *c2 = p2;
-       const char *s1 = (*c1)->name, *s2 = (*c2)->name;
-       int l1 = (*c1)->len;
-       int l2 = (*c2)->len;
-       return l1 != l2 ? l1 - l2 : strcmp(s1, s2);
-}
-
-static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
-{
-       unsigned int i;
-
-       ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc);
-
-       for (i = 0; i < old->cnt; i++)
-               cmds->names[cmds->cnt++] = old->names[i];
-       zfree(&old->names);
-       old->cnt = 0;
-}
-
-const char *help_unknown_cmd(const char *cmd)
-{
-       unsigned int i, n = 0, best_similarity = 0;
-       struct cmdnames main_cmds, other_cmds;
-
-       memset(&main_cmds, 0, sizeof(main_cmds));
-       memset(&other_cmds, 0, sizeof(main_cmds));
-       memset(&aliases, 0, sizeof(aliases));
-
-       perf_config(perf_unknown_cmd_config, NULL);
-
-       load_command_list("perf-", &main_cmds, &other_cmds);
-
-       add_cmd_list(&main_cmds, &aliases);
-       add_cmd_list(&main_cmds, &other_cmds);
-       qsort(main_cmds.names, main_cmds.cnt,
-             sizeof(main_cmds.names), cmdname_compare);
-       uniq(&main_cmds);
-
-       if (main_cmds.cnt) {
-               /* This reuses cmdname->len for similarity index */
-               for (i = 0; i < main_cmds.cnt; ++i)
-                       main_cmds.names[i]->len =
-                               levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);
-
-               qsort(main_cmds.names, main_cmds.cnt,
-                     sizeof(*main_cmds.names), levenshtein_compare);
-
-               best_similarity = main_cmds.names[0]->len;
-               n = 1;
-               while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)
-                       ++n;
-       }
-
-       if (autocorrect && n == 1) {
-               const char *assumed = main_cmds.names[0]->name;
-
-               main_cmds.names[0] = NULL;
-               clean_cmdnames(&main_cmds);
-               fprintf(stderr, "WARNING: You called a perf program named '%s', "
-                       "which does not exist.\n"
-                       "Continuing under the assumption that you meant '%s'\n",
-                       cmd, assumed);
-               if (autocorrect > 0) {
-                       fprintf(stderr, "in %0.1f seconds automatically...\n",
-                               (float)autocorrect/10.0);
-                       poll(NULL, 0, autocorrect * 100);
-               }
-               return assumed;
-       }
-
-       fprintf(stderr, "perf: '%s' is not a perf-command. See 'perf --help'.\n", cmd);
-
-       if (main_cmds.cnt && best_similarity < 6) {
-               fprintf(stderr, "\nDid you mean %s?\n",
-                       n < 2 ? "this": "one of these");
-
-               for (i = 0; i < n; i++)
-                       fprintf(stderr, "\t%s\n", main_cmds.names[i]->name);
-       }
-
-       exit(1);
-}
-
-int cmd_version(int argc __maybe_unused, const char **argv __maybe_unused,
-               const char *prefix __maybe_unused)
-{
-       printf("perf version %s\n", perf_version_string);
-       return 0;
-}
diff --git a/tools/perf/util/help.h b/tools/perf/util/help.h
deleted file mode 100644 (file)
index 7f5c6de..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef __PERF_HELP_H
-#define __PERF_HELP_H
-
-struct cmdnames {
-       size_t alloc;
-       size_t cnt;
-       struct cmdname {
-               size_t len; /* also used for similarity index in help.c */
-               char name[FLEX_ARRAY];
-       } **names;
-};
-
-static inline void mput_char(char c, unsigned int num)
-{
-       while(num--)
-               putchar(c);
-}
-
-void load_command_list(const char *prefix,
-               struct cmdnames *main_cmds,
-               struct cmdnames *other_cmds);
-void add_cmdname(struct cmdnames *cmds, const char *name, size_t len);
-/* Here we require that excludes is a sorted list. */
-void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
-int is_in_cmdlist(struct cmdnames *c, const char *s);
-void list_commands(const char *title, struct cmdnames *main_cmds,
-                  struct cmdnames *other_cmds);
-
-#endif /* __PERF_HELP_H */
index 4fd37d6708cb973d2653c1ec4f6f17b086c712d0..c226303e3da045743fe676c7c2ffc0ff13eac674 100644 (file)
@@ -254,6 +254,7 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
        he_stat__decay(&he->stat);
        if (symbol_conf.cumulate_callchain)
                he_stat__decay(he->stat_acc);
+       decay_callchain(he->callchain);
 
        diff = prev_period - he->stat.period;
 
@@ -270,6 +271,8 @@ static void hists__delete_entry(struct hists *hists, struct hist_entry *he)
 
        if (sort__need_collapse)
                rb_erase(&he->rb_node_in, &hists->entries_collapsed);
+       else
+               rb_erase(&he->rb_node_in, hists->entries_in);
 
        --hists->nr_entries;
        if (!he->filtered)
@@ -367,6 +370,25 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template,
                if (symbol_conf.use_callchain)
                        callchain_init(he->callchain);
 
+               if (he->raw_data) {
+                       he->raw_data = memdup(he->raw_data, he->raw_size);
+
+                       if (he->raw_data == NULL) {
+                               map__put(he->ms.map);
+                               if (he->branch_info) {
+                                       map__put(he->branch_info->from.map);
+                                       map__put(he->branch_info->to.map);
+                                       free(he->branch_info);
+                               }
+                               if (he->mem_info) {
+                                       map__put(he->mem_info->iaddr.map);
+                                       map__put(he->mem_info->daddr.map);
+                               }
+                               free(he->stat_acc);
+                               free(he);
+                               return NULL;
+                       }
+               }
                INIT_LIST_HEAD(&he->pairs.node);
                thread__get(he->thread);
        }
@@ -459,7 +481,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
                                      struct symbol *sym_parent,
                                      struct branch_info *bi,
                                      struct mem_info *mi,
-                                     u64 period, u64 weight, u64 transaction,
+                                     struct perf_sample *sample,
                                      bool sample_self)
 {
        struct hist_entry entry = {
@@ -476,15 +498,17 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
                .level   = al->level,
                .stat = {
                        .nr_events = 1,
-                       .period = period,
-                       .weight = weight,
+                       .period = sample->period,
+                       .weight = sample->weight,
                },
                .parent = sym_parent,
                .filtered = symbol__parent_filter(sym_parent) | al->filtered,
                .hists  = hists,
                .branch_info = bi,
                .mem_info = mi,
-               .transaction = transaction,
+               .transaction = sample->transaction,
+               .raw_data = sample->raw_data,
+               .raw_size = sample->raw_size,
        };
 
        return hists__findnew_entry(hists, &entry, al, sample_self);
@@ -524,12 +548,13 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al
        u64 cost;
        struct mem_info *mi = iter->priv;
        struct hists *hists = evsel__hists(iter->evsel);
+       struct perf_sample *sample = iter->sample;
        struct hist_entry *he;
 
        if (mi == NULL)
                return -EINVAL;
 
-       cost = iter->sample->weight;
+       cost = sample->weight;
        if (!cost)
                cost = 1;
 
@@ -540,8 +565,10 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al
         * and this is indirectly achieved by passing period=weight here
         * and the he_stat__add_period() function.
         */
+       sample->period = cost;
+
        he = __hists__add_entry(hists, al, iter->parent, NULL, mi,
-                               cost, cost, 0, true);
+                               sample, true);
        if (!he)
                return -ENOMEM;
 
@@ -628,6 +655,7 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a
        struct branch_info *bi;
        struct perf_evsel *evsel = iter->evsel;
        struct hists *hists = evsel__hists(evsel);
+       struct perf_sample *sample = iter->sample;
        struct hist_entry *he = NULL;
        int i = iter->curr;
        int err = 0;
@@ -641,9 +669,11 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a
         * The report shows the percentage of total branches captured
         * and not events sampled. Thus we use a pseudo period of 1.
         */
+       sample->period = 1;
+       sample->weight = bi->flags.cycles ? bi->flags.cycles : 1;
+
        he = __hists__add_entry(hists, al, iter->parent, &bi[i], NULL,
-                               1, bi->flags.cycles ? bi->flags.cycles : 1,
-                               0, true);
+                               sample, true);
        if (he == NULL)
                return -ENOMEM;
 
@@ -680,8 +710,7 @@ iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location
        struct hist_entry *he;
 
        he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
-                               sample->period, sample->weight,
-                               sample->transaction, true);
+                               sample, true);
        if (he == NULL)
                return -ENOMEM;
 
@@ -742,8 +771,7 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter,
        int err = 0;
 
        he = __hists__add_entry(hists, al, iter->parent, NULL, NULL,
-                               sample->period, sample->weight,
-                               sample->transaction, true);
+                               sample, true);
        if (he == NULL)
                return -ENOMEM;
 
@@ -795,6 +823,8 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
                        .sym = al->sym,
                },
                .parent = iter->parent,
+               .raw_data = sample->raw_data,
+               .raw_size = sample->raw_size,
        };
        int i;
        struct callchain_cursor cursor;
@@ -816,8 +846,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
        }
 
        he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
-                               sample->period, sample->weight,
-                               sample->transaction, false);
+                               sample, false);
        if (he == NULL)
                return -ENOMEM;
 
@@ -924,9 +953,6 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
        int64_t cmp = 0;
 
        perf_hpp__for_each_sort_list(fmt) {
-               if (perf_hpp__should_skip(fmt))
-                       continue;
-
                cmp = fmt->cmp(fmt, left, right);
                if (cmp)
                        break;
@@ -942,9 +968,6 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
        int64_t cmp = 0;
 
        perf_hpp__for_each_sort_list(fmt) {
-               if (perf_hpp__should_skip(fmt))
-                       continue;
-
                cmp = fmt->collapse(fmt, left, right);
                if (cmp)
                        break;
@@ -975,6 +998,8 @@ void hist_entry__delete(struct hist_entry *he)
        if (he->srcfile && he->srcfile[0])
                free(he->srcfile);
        free_callchain(he->callchain);
+       free(he->trace_output);
+       free(he->raw_data);
        free(he);
 }
 
@@ -982,9 +1007,8 @@ void hist_entry__delete(struct hist_entry *he)
  * collapse the histogram
  */
 
-static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
-                                        struct rb_root *root,
-                                        struct hist_entry *he)
+bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
+                                 struct rb_root *root, struct hist_entry *he)
 {
        struct rb_node **p = &root->rb_node;
        struct rb_node *parent = NULL;
@@ -1024,7 +1048,7 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
        return true;
 }
 
-static struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
+struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
 {
        struct rb_root *root;
 
@@ -1088,7 +1112,7 @@ static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b)
        int64_t cmp = 0;
 
        perf_hpp__for_each_sort_list(fmt) {
-               if (perf_hpp__should_skip(fmt))
+               if (perf_hpp__should_skip(fmt, a->hists))
                        continue;
 
                cmp = fmt->sort(fmt, a, b);
@@ -1559,10 +1583,8 @@ int perf_hist_config(const char *var, const char *value)
        return 0;
 }
 
-static int hists_evsel__init(struct perf_evsel *evsel)
+int __hists__init(struct hists *hists)
 {
-       struct hists *hists = evsel__hists(evsel);
-
        memset(hists, 0, sizeof(*hists));
        hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
        hists->entries_in = &hists->entries_in_array[0];
@@ -1573,6 +1595,43 @@ static int hists_evsel__init(struct perf_evsel *evsel)
        return 0;
 }
 
+static void hists__delete_remaining_entries(struct rb_root *root)
+{
+       struct rb_node *node;
+       struct hist_entry *he;
+
+       while (!RB_EMPTY_ROOT(root)) {
+               node = rb_first(root);
+               rb_erase(node, root);
+
+               he = rb_entry(node, struct hist_entry, rb_node_in);
+               hist_entry__delete(he);
+       }
+}
+
+static void hists__delete_all_entries(struct hists *hists)
+{
+       hists__delete_entries(hists);
+       hists__delete_remaining_entries(&hists->entries_in_array[0]);
+       hists__delete_remaining_entries(&hists->entries_in_array[1]);
+       hists__delete_remaining_entries(&hists->entries_collapsed);
+}
+
+static void hists_evsel__exit(struct perf_evsel *evsel)
+{
+       struct hists *hists = evsel__hists(evsel);
+
+       hists__delete_all_entries(hists);
+}
+
+static int hists_evsel__init(struct perf_evsel *evsel)
+{
+       struct hists *hists = evsel__hists(evsel);
+
+       __hists__init(hists);
+       return 0;
+}
+
 /*
  * XXX We probably need a hists_evsel__exit() to free the hist_entries
  * stored in the rbtree...
@@ -1581,7 +1640,8 @@ static int hists_evsel__init(struct perf_evsel *evsel)
 int hists__init(void)
 {
        int err = perf_evsel__object_config(sizeof(struct hists_evsel),
-                                           hists_evsel__init, NULL);
+                                           hists_evsel__init,
+                                           hists_evsel__exit);
        if (err)
                fputs("FATAL ERROR: Couldn't setup hists class\n", stderr);
 
index a48a2078d288f01b9edf10814571509803b674d1..d4ec4822a1038611a7269aa0df2eb37171a647a6 100644 (file)
@@ -52,6 +52,7 @@ enum hist_column {
        HISTC_MEM_IADDR_SYMBOL,
        HISTC_TRANSACTION,
        HISTC_CYCLES,
+       HISTC_TRACE,
        HISTC_NR_COLS, /* Last entry */
 };
 
@@ -114,8 +115,8 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
                                      struct addr_location *al,
                                      struct symbol *parent,
                                      struct branch_info *bi,
-                                     struct mem_info *mi, u64 period,
-                                     u64 weight, u64 transaction,
+                                     struct mem_info *mi,
+                                     struct perf_sample *sample,
                                      bool sample_self);
 int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
                         int max_stack_depth, void *arg);
@@ -184,6 +185,11 @@ static inline struct hists *evsel__hists(struct perf_evsel *evsel)
 }
 
 int hists__init(void);
+int __hists__init(struct hists *hists);
+
+struct rb_root *hists__get_rotate_entries_in(struct hists *hists);
+bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
+                                 struct rb_root *root, struct hist_entry *he);
 
 struct perf_hpp {
        char *buf;
@@ -261,10 +267,20 @@ void perf_hpp__append_sort_keys(void);
 
 bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format);
 bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b);
+bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *format);
+bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists);
 
-static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format)
+static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format,
+                                        struct hists *hists)
 {
-       return format->elide;
+       if (format->elide)
+               return true;
+
+       if (perf_hpp__is_dynamic_entry(format) &&
+           !perf_hpp__defined_dynamic_entry(format, hists))
+               return true;
+
+       return false;
 }
 
 void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists);
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
deleted file mode 100644 (file)
index 40bd214..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef _PERF_BITOPS_H
-#define _PERF_BITOPS_H
-
-#include <string.h>
-#include <linux/bitops.h>
-
-#define DECLARE_BITMAP(name,bits) \
-       unsigned long name[BITS_TO_LONGS(bits)]
-
-int __bitmap_weight(const unsigned long *bitmap, int bits);
-void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
-                const unsigned long *bitmap2, int bits);
-
-#define BITMAP_LAST_WORD_MASK(nbits)                                   \
-(                                                                      \
-       ((nbits) % BITS_PER_LONG) ?                                     \
-               (1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL               \
-)
-
-#define small_const_nbits(nbits) \
-       (__builtin_constant_p(nbits) && (nbits) <= BITS_PER_LONG)
-
-static inline void bitmap_zero(unsigned long *dst, int nbits)
-{
-       if (small_const_nbits(nbits))
-               *dst = 0UL;
-       else {
-               int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
-               memset(dst, 0, len);
-       }
-}
-
-static inline int bitmap_weight(const unsigned long *src, int nbits)
-{
-       if (small_const_nbits(nbits))
-               return hweight_long(*src & BITMAP_LAST_WORD_MASK(nbits));
-       return __bitmap_weight(src, nbits);
-}
-
-static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
-                            const unsigned long *src2, int nbits)
-{
-       if (small_const_nbits(nbits))
-               *dst = *src1 | *src2;
-       else
-               __bitmap_or(dst, src1, src2, nbits);
-}
-
-/**
- * test_and_set_bit - Set a bit and return its old value
- * @nr: Bit to set
- * @addr: Address to count from
- */
-static inline int test_and_set_bit(int nr, unsigned long *addr)
-{
-       unsigned long mask = BIT_MASK(nr);
-       unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
-       unsigned long old;
-
-       old = *p;
-       *p = old | mask;
-
-       return (old & mask) != 0;
-}
-
-#endif /* _PERF_BITOPS_H */
diff --git a/tools/perf/util/include/linux/string.h b/tools/perf/util/include/linux/string.h
deleted file mode 100644 (file)
index 6f19c54..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#include <string.h>
-
-void *memdup(const void *src, size_t len);
index 97f963a3dcb95157f8dcaf3e568d3ac487989608..81a2eb77ba7ff56f7558328437fa32e8345051cd 100644 (file)
@@ -1744,7 +1744,7 @@ static void intel_pt_free(struct perf_session *session)
        auxtrace_heap__free(&pt->heap);
        intel_pt_free_events(session);
        session->auxtrace = NULL;
-       thread__delete(pt->unknown_thread);
+       thread__put(pt->unknown_thread);
        free(pt);
 }
 
@@ -2153,7 +2153,7 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
        return 0;
 
 err_delete_thread:
-       thread__delete(pt->unknown_thread);
+       thread__zput(pt->unknown_thread);
 err_free_queues:
        intel_pt_log_disable();
        auxtrace_queues__free(&pt->queues);
index 8b303ff20289a8ffb4baff9e29292dd47e9068eb..ad79297c76c87533fb961ac5f8e3daee58f2fda6 100644 (file)
@@ -25,6 +25,7 @@ static void dsos__init(struct dsos *dsos)
 
 int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 {
+       memset(machine, 0, sizeof(*machine));
        map_groups__init(&machine->kmaps, machine);
        RB_CLEAR_NODE(&machine->rb_node);
        dsos__init(&machine->dsos);
@@ -44,6 +45,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
        machine->comm_exec = false;
        machine->kernel_start = 0;
 
+       memset(machine->vmlinux_maps, 0, sizeof(machine->vmlinux_maps));
+
        machine->root_dir = strdup(root_dir);
        if (machine->root_dir == NULL)
                return -ENOMEM;
@@ -122,6 +125,7 @@ void machine__delete_threads(struct machine *machine)
 
 void machine__exit(struct machine *machine)
 {
+       machine__destroy_kernel_maps(machine);
        map_groups__exit(&machine->kmaps);
        dsos__exit(&machine->dsos);
        machine__exit_vdso(machine);
@@ -348,13 +352,18 @@ static void machine__update_thread_pid(struct machine *machine,
        }
 
        th->mg = map_groups__get(leader->mg);
-
+out_put:
+       thread__put(leader);
        return;
-
 out_err:
        pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid);
+       goto out_put;
 }
 
+/*
+ * Caller must eventually drop thread->refcnt returned with a successfull
+ * lookup/new thread inserted.
+ */
 static struct thread *____machine__findnew_thread(struct machine *machine,
                                                  pid_t pid, pid_t tid,
                                                  bool create)
@@ -372,7 +381,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
        if (th != NULL) {
                if (th->tid == tid) {
                        machine__update_thread_pid(machine, th, pid);
-                       return th;
+                       return thread__get(th);
                }
 
                machine->last_match = NULL;
@@ -385,7 +394,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
                if (th->tid == tid) {
                        machine->last_match = th;
                        machine__update_thread_pid(machine, th, pid);
-                       return th;
+                       return thread__get(th);
                }
 
                if (tid < th->tid)
@@ -413,7 +422,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
                if (thread__init_map_groups(th, machine)) {
                        rb_erase_init(&th->rb_node, &machine->threads);
                        RB_CLEAR_NODE(&th->rb_node);
-                       thread__delete(th);
+                       thread__put(th);
                        return NULL;
                }
                /*
@@ -437,7 +446,7 @@ struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
        struct thread *th;
 
        pthread_rwlock_wrlock(&machine->threads_lock);
-       th = thread__get(__machine__findnew_thread(machine, pid, tid));
+       th = __machine__findnew_thread(machine, pid, tid);
        pthread_rwlock_unlock(&machine->threads_lock);
        return th;
 }
@@ -447,7 +456,7 @@ struct thread *machine__find_thread(struct machine *machine, pid_t pid,
 {
        struct thread *th;
        pthread_rwlock_rdlock(&machine->threads_lock);
-       th =  thread__get(____machine__findnew_thread(machine, pid, tid, false));
+       th =  ____machine__findnew_thread(machine, pid, tid, false);
        pthread_rwlock_unlock(&machine->threads_lock);
        return th;
 }
@@ -560,11 +569,29 @@ int machine__process_switch_event(struct machine *machine __maybe_unused,
        return 0;
 }
 
+static void dso__adjust_kmod_long_name(struct dso *dso, const char *filename)
+{
+       const char *dup_filename;
+
+       if (!filename || !dso || !dso->long_name)
+               return;
+       if (dso->long_name[0] != '[')
+               return;
+       if (!strchr(filename, '/'))
+               return;
+
+       dup_filename = strdup(filename);
+       if (!dup_filename)
+               return;
+
+       dso__set_long_name(dso, dup_filename, true);
+}
+
 struct map *machine__findnew_module_map(struct machine *machine, u64 start,
                                        const char *filename)
 {
        struct map *map = NULL;
-       struct dso *dso;
+       struct dso *dso = NULL;
        struct kmod_path m;
 
        if (kmod_path__parse_name(&m, filename))
@@ -572,8 +599,15 @@ struct map *machine__findnew_module_map(struct machine *machine, u64 start,
 
        map = map_groups__find_by_name(&machine->kmaps, MAP__FUNCTION,
                                       m.name);
-       if (map)
+       if (map) {
+               /*
+                * If the map's dso is an offline module, give dso__load()
+                * a chance to find the file path of that module by fixing
+                * long_name.
+                */
+               dso__adjust_kmod_long_name(map->dso, filename);
                goto out;
+       }
 
        dso = machine__findnew_module_dso(machine, &m, filename);
        if (dso == NULL)
@@ -585,7 +619,11 @@ struct map *machine__findnew_module_map(struct machine *machine, u64 start,
 
        map_groups__insert(&machine->kmaps, map);
 
+       /* Put the map here because map_groups__insert alread got it */
+       map__put(map);
 out:
+       /* put the dso here, corresponding to  machine__findnew_module_dso */
+       dso__put(dso);
        free(m.name);
        return map;
 }
@@ -740,6 +778,9 @@ int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
        enum map_type type;
        u64 start = machine__get_running_kernel_start(machine, NULL);
 
+       /* In case of renewal the kernel map, destroy previous one */
+       machine__destroy_kernel_maps(machine);
+
        for (type = 0; type < MAP__NR_TYPES; ++type) {
                struct kmap *kmap;
                struct map *map;
@@ -788,6 +829,7 @@ void machine__destroy_kernel_maps(struct machine *machine)
                                kmap->ref_reloc_sym = NULL;
                }
 
+               map__put(machine->vmlinux_maps[type]);
                machine->vmlinux_maps[type] = NULL;
        }
 }
@@ -1084,11 +1126,14 @@ int machine__create_kernel_maps(struct machine *machine)
        struct dso *kernel = machine__get_kernel(machine);
        const char *name;
        u64 addr = machine__get_running_kernel_start(machine, &name);
-       if (!addr)
+       int ret;
+
+       if (!addr || kernel == NULL)
                return -1;
 
-       if (kernel == NULL ||
-           __machine__create_kernel_maps(machine, kernel) < 0)
+       ret = __machine__create_kernel_maps(machine, kernel);
+       dso__put(kernel);
+       if (ret < 0)
                return -1;
 
        if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
@@ -1609,6 +1654,8 @@ static int add_callchain_ip(struct thread *thread,
                }
        }
 
+       if (symbol_conf.hide_unresolved && al.sym == NULL)
+               return 0;
        return callchain_cursor_append(&callchain_cursor, al.addr, al.map, al.sym);
 }
 
@@ -1863,6 +1910,9 @@ check_calls:
 static int unwind_entry(struct unwind_entry *entry, void *arg)
 {
        struct callchain_cursor *cursor = arg;
+
+       if (symbol_conf.hide_unresolved && entry->sym == NULL)
+               return 0;
        return callchain_cursor_append(cursor, entry->ip,
                                       entry->map, entry->sym);
 }
index afc6b56cf749b687c297018dcae986fef977859c..171b6d10a04b6d9fe4626b6af8725beee924adf0 100644 (file)
@@ -26,8 +26,8 @@ const char *map_type__name[MAP__NR_TYPES] = {
 static inline int is_anon_memory(const char *filename)
 {
        return !strcmp(filename, "//anon") ||
-              !strcmp(filename, "/dev/zero (deleted)") ||
-              !strcmp(filename, "/anon_hugepage (deleted)");
+              !strncmp(filename, "/dev/zero", sizeof("/dev/zero") - 1) ||
+              !strncmp(filename, "/anon_hugepage", sizeof("/anon_hugepage") - 1);
 }
 
 static inline int is_no_dso_memory(const char *filename)
@@ -691,6 +691,7 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp
                        __map_groups__insert(pos->groups, before);
                        if (verbose >= 2)
                                map__fprintf(before, fp);
+                       map__put(before);
                }
 
                if (map->end < pos->end) {
@@ -705,6 +706,7 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp
                        __map_groups__insert(pos->groups, after);
                        if (verbose >= 2)
                                map__fprintf(after, fp);
+                       map__put(after);
                }
 put_map:
                map__put(pos);
@@ -742,6 +744,7 @@ int map_groups__clone(struct map_groups *mg,
                if (new == NULL)
                        goto out_unlock;
                map_groups__insert(mg, new);
+               map__put(new);
        }
 
        err = 0;
diff --git a/tools/perf/util/pager.c b/tools/perf/util/pager.c
deleted file mode 100644 (file)
index 53ef006..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-#include "cache.h"
-#include "run-command.h"
-#include "sigchain.h"
-
-/*
- * This is split up from the rest of git so that we can do
- * something different on Windows.
- */
-
-static int spawned_pager;
-
-static void pager_preexec(void)
-{
-       /*
-        * Work around bug in "less" by not starting it until we
-        * have real input
-        */
-       fd_set in;
-
-       FD_ZERO(&in);
-       FD_SET(0, &in);
-       select(1, &in, NULL, &in, NULL);
-
-       setenv("LESS", "FRSX", 0);
-}
-
-static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
-static struct child_process pager_process;
-
-static void wait_for_pager(void)
-{
-       fflush(stdout);
-       fflush(stderr);
-       /* signal EOF to pager */
-       close(1);
-       close(2);
-       finish_command(&pager_process);
-}
-
-static void wait_for_pager_signal(int signo)
-{
-       wait_for_pager();
-       sigchain_pop(signo);
-       raise(signo);
-}
-
-void setup_pager(void)
-{
-       const char *pager = getenv("PERF_PAGER");
-
-       if (!isatty(1))
-               return;
-       if (!pager)
-               pager = getenv("PAGER");
-       if (!(pager || access("/usr/bin/pager", X_OK)))
-               pager = "/usr/bin/pager";
-       if (!(pager || access("/usr/bin/less", X_OK)))
-               pager = "/usr/bin/less";
-       if (!pager)
-               pager = "cat";
-       if (!*pager || !strcmp(pager, "cat"))
-               return;
-
-       spawned_pager = 1; /* means we are emitting to terminal */
-
-       /* spawn the pager */
-       pager_argv[2] = pager;
-       pager_process.argv = pager_argv;
-       pager_process.in = -1;
-       pager_process.preexec_cb = pager_preexec;
-
-       if (start_command(&pager_process))
-               return;
-
-       /* original process continues, but writes to the pipe */
-       dup2(pager_process.in, 1);
-       if (isatty(2))
-               dup2(pager_process.in, 2);
-       close(pager_process.in);
-
-       /* this makes sure that the parent terminates after the pager */
-       sigchain_push_common(wait_for_pager_signal);
-       atexit(wait_for_pager);
-}
-
-int pager_in_use(void)
-{
-       const char *env;
-
-       if (spawned_pager)
-               return 1;
-
-       env = getenv("PERF_PAGER_IN_USE");
-       return env ? perf_config_bool("PERF_PAGER_IN_USE", env) : 0;
-}
index 355eecf6bf598ba051dde4df6368747e55fb141a..afc088dd7d20948929aa087661f13f913b850b97 100644 (file)
@@ -1,7 +1,7 @@
 #include "perf.h"
 #include "util/util.h"
 #include "util/debug.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/parse-branch-options.h"
 
 #define BRANCH_OPT(n, m) \
index e48d9da757078f0c35afae590ce87ac7892dafab..4f7b0efdde2fa0c0c9f7cab32c6a20809ea47a4f 100644 (file)
@@ -4,9 +4,9 @@
 #include "../perf.h"
 #include "evlist.h"
 #include "evsel.h"
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
 #include "parse-events.h"
-#include "exec_cmd.h"
+#include <subcmd/exec-cmd.h>
 #include "string.h"
 #include "symbol.h"
 #include "cache.h"
@@ -124,6 +124,10 @@ struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = {
                .symbol = "dummy",
                .alias  = "",
        },
+       [PERF_COUNT_SW_BPF_OUTPUT] = {
+               .symbol = "bpf-output",
+               .alias  = "",
+       },
 };
 
 #define __PERF_EVENT_FIELD(config, name) \
@@ -1879,7 +1883,7 @@ restart:
 
        for (i = 0; i < max; i++, syms++) {
 
-               if (event_glob != NULL &&
+               if (event_glob != NULL && syms->symbol != NULL &&
                    !(strglobmatch(syms->symbol, event_glob) ||
                      (syms->alias && strglobmatch(syms->alias, event_glob))))
                        continue;
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
deleted file mode 100644 (file)
index 9fca092..0000000
+++ /dev/null
@@ -1,867 +0,0 @@
-#include "util.h"
-#include "parse-options.h"
-#include "cache.h"
-#include "header.h"
-#include <linux/string.h>
-
-#define OPT_SHORT 1
-#define OPT_UNSET 2
-
-static struct strbuf error_buf = STRBUF_INIT;
-
-static int opterror(const struct option *opt, const char *reason, int flags)
-{
-       if (flags & OPT_SHORT)
-               return error("switch `%c' %s", opt->short_name, reason);
-       if (flags & OPT_UNSET)
-               return error("option `no-%s' %s", opt->long_name, reason);
-       return error("option `%s' %s", opt->long_name, reason);
-}
-
-static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
-                  int flags, const char **arg)
-{
-       if (p->opt) {
-               *arg = p->opt;
-               p->opt = NULL;
-       } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
-                   **(p->argv + 1) == '-')) {
-               *arg = (const char *)opt->defval;
-       } else if (p->argc > 1) {
-               p->argc--;
-               *arg = *++p->argv;
-       } else
-               return opterror(opt, "requires a value", flags);
-       return 0;
-}
-
-static int get_value(struct parse_opt_ctx_t *p,
-                    const struct option *opt, int flags)
-{
-       const char *s, *arg = NULL;
-       const int unset = flags & OPT_UNSET;
-       int err;
-
-       if (unset && p->opt)
-               return opterror(opt, "takes no value", flags);
-       if (unset && (opt->flags & PARSE_OPT_NONEG))
-               return opterror(opt, "isn't available", flags);
-       if (opt->flags & PARSE_OPT_DISABLED)
-               return opterror(opt, "is not usable", flags);
-
-       if (opt->flags & PARSE_OPT_EXCLUSIVE) {
-               if (p->excl_opt && p->excl_opt != opt) {
-                       char msg[128];
-
-                       if (((flags & OPT_SHORT) && p->excl_opt->short_name) ||
-                           p->excl_opt->long_name == NULL) {
-                               scnprintf(msg, sizeof(msg), "cannot be used with switch `%c'",
-                                         p->excl_opt->short_name);
-                       } else {
-                               scnprintf(msg, sizeof(msg), "cannot be used with %s",
-                                         p->excl_opt->long_name);
-                       }
-                       opterror(opt, msg, flags);
-                       return -3;
-               }
-               p->excl_opt = opt;
-       }
-       if (!(flags & OPT_SHORT) && p->opt) {
-               switch (opt->type) {
-               case OPTION_CALLBACK:
-                       if (!(opt->flags & PARSE_OPT_NOARG))
-                               break;
-                       /* FALLTHROUGH */
-               case OPTION_BOOLEAN:
-               case OPTION_INCR:
-               case OPTION_BIT:
-               case OPTION_SET_UINT:
-               case OPTION_SET_PTR:
-                       return opterror(opt, "takes no value", flags);
-               case OPTION_END:
-               case OPTION_ARGUMENT:
-               case OPTION_GROUP:
-               case OPTION_STRING:
-               case OPTION_INTEGER:
-               case OPTION_UINTEGER:
-               case OPTION_LONG:
-               case OPTION_U64:
-               default:
-                       break;
-               }
-       }
-
-       switch (opt->type) {
-       case OPTION_BIT:
-               if (unset)
-                       *(int *)opt->value &= ~opt->defval;
-               else
-                       *(int *)opt->value |= opt->defval;
-               return 0;
-
-       case OPTION_BOOLEAN:
-               *(bool *)opt->value = unset ? false : true;
-               if (opt->set)
-                       *(bool *)opt->set = true;
-               return 0;
-
-       case OPTION_INCR:
-               *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
-               return 0;
-
-       case OPTION_SET_UINT:
-               *(unsigned int *)opt->value = unset ? 0 : opt->defval;
-               return 0;
-
-       case OPTION_SET_PTR:
-               *(void **)opt->value = unset ? NULL : (void *)opt->defval;
-               return 0;
-
-       case OPTION_STRING:
-               err = 0;
-               if (unset)
-                       *(const char **)opt->value = NULL;
-               else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
-                       *(const char **)opt->value = (const char *)opt->defval;
-               else
-                       err = get_arg(p, opt, flags, (const char **)opt->value);
-
-               /* PARSE_OPT_NOEMPTY: Allow NULL but disallow empty string. */
-               if (opt->flags & PARSE_OPT_NOEMPTY) {
-                       const char *val = *(const char **)opt->value;
-
-                       if (!val)
-                               return err;
-
-                       /* Similar to unset if we are given an empty string. */
-                       if (val[0] == '\0') {
-                               *(const char **)opt->value = NULL;
-                               return 0;
-                       }
-               }
-
-               return err;
-
-       case OPTION_CALLBACK:
-               if (unset)
-                       return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
-               if (opt->flags & PARSE_OPT_NOARG)
-                       return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
-               if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
-                       return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
-               if (get_arg(p, opt, flags, &arg))
-                       return -1;
-               return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
-
-       case OPTION_INTEGER:
-               if (unset) {
-                       *(int *)opt->value = 0;
-                       return 0;
-               }
-               if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
-                       *(int *)opt->value = opt->defval;
-                       return 0;
-               }
-               if (get_arg(p, opt, flags, &arg))
-                       return -1;
-               *(int *)opt->value = strtol(arg, (char **)&s, 10);
-               if (*s)
-                       return opterror(opt, "expects a numerical value", flags);
-               return 0;
-
-       case OPTION_UINTEGER:
-               if (unset) {
-                       *(unsigned int *)opt->value = 0;
-                       return 0;
-               }
-               if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
-                       *(unsigned int *)opt->value = opt->defval;
-                       return 0;
-               }
-               if (get_arg(p, opt, flags, &arg))
-                       return -1;
-               *(unsigned int *)opt->value = strtol(arg, (char **)&s, 10);
-               if (*s)
-                       return opterror(opt, "expects a numerical value", flags);
-               return 0;
-
-       case OPTION_LONG:
-               if (unset) {
-                       *(long *)opt->value = 0;
-                       return 0;
-               }
-               if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
-                       *(long *)opt->value = opt->defval;
-                       return 0;
-               }
-               if (get_arg(p, opt, flags, &arg))
-                       return -1;
-               *(long *)opt->value = strtol(arg, (char **)&s, 10);
-               if (*s)
-                       return opterror(opt, "expects a numerical value", flags);
-               return 0;
-
-       case OPTION_U64:
-               if (unset) {
-                       *(u64 *)opt->value = 0;
-                       return 0;
-               }
-               if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
-                       *(u64 *)opt->value = opt->defval;
-                       return 0;
-               }
-               if (get_arg(p, opt, flags, &arg))
-                       return -1;
-               *(u64 *)opt->value = strtoull(arg, (char **)&s, 10);
-               if (*s)
-                       return opterror(opt, "expects a numerical value", flags);
-               return 0;
-
-       case OPTION_END:
-       case OPTION_ARGUMENT:
-       case OPTION_GROUP:
-       default:
-               die("should not happen, someone must be hit on the forehead");
-       }
-}
-
-static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
-{
-       for (; options->type != OPTION_END; options++) {
-               if (options->short_name == *p->opt) {
-                       p->opt = p->opt[1] ? p->opt + 1 : NULL;
-                       return get_value(p, options, OPT_SHORT);
-               }
-       }
-       return -2;
-}
-
-static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
-                          const struct option *options)
-{
-       const char *arg_end = strchr(arg, '=');
-       const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
-       int abbrev_flags = 0, ambiguous_flags = 0;
-
-       if (!arg_end)
-               arg_end = arg + strlen(arg);
-
-       for (; options->type != OPTION_END; options++) {
-               const char *rest;
-               int flags = 0;
-
-               if (!options->long_name)
-                       continue;
-
-               rest = skip_prefix(arg, options->long_name);
-               if (options->type == OPTION_ARGUMENT) {
-                       if (!rest)
-                               continue;
-                       if (*rest == '=')
-                               return opterror(options, "takes no value", flags);
-                       if (*rest)
-                               continue;
-                       p->out[p->cpidx++] = arg - 2;
-                       return 0;
-               }
-               if (!rest) {
-                       if (!prefixcmp(options->long_name, "no-")) {
-                               /*
-                                * The long name itself starts with "no-", so
-                                * accept the option without "no-" so that users
-                                * do not have to enter "no-no-" to get the
-                                * negation.
-                                */
-                               rest = skip_prefix(arg, options->long_name + 3);
-                               if (rest) {
-                                       flags |= OPT_UNSET;
-                                       goto match;
-                               }
-                               /* Abbreviated case */
-                               if (!prefixcmp(options->long_name + 3, arg)) {
-                                       flags |= OPT_UNSET;
-                                       goto is_abbreviated;
-                               }
-                       }
-                       /* abbreviated? */
-                       if (!strncmp(options->long_name, arg, arg_end - arg)) {
-is_abbreviated:
-                               if (abbrev_option) {
-                                       /*
-                                        * If this is abbreviated, it is
-                                        * ambiguous. So when there is no
-                                        * exact match later, we need to
-                                        * error out.
-                                        */
-                                       ambiguous_option = abbrev_option;
-                                       ambiguous_flags = abbrev_flags;
-                               }
-                               if (!(flags & OPT_UNSET) && *arg_end)
-                                       p->opt = arg_end + 1;
-                               abbrev_option = options;
-                               abbrev_flags = flags;
-                               continue;
-                       }
-                       /* negated and abbreviated very much? */
-                       if (!prefixcmp("no-", arg)) {
-                               flags |= OPT_UNSET;
-                               goto is_abbreviated;
-                       }
-                       /* negated? */
-                       if (strncmp(arg, "no-", 3))
-                               continue;
-                       flags |= OPT_UNSET;
-                       rest = skip_prefix(arg + 3, options->long_name);
-                       /* abbreviated and negated? */
-                       if (!rest && !prefixcmp(options->long_name, arg + 3))
-                               goto is_abbreviated;
-                       if (!rest)
-                               continue;
-               }
-match:
-               if (*rest) {
-                       if (*rest != '=')
-                               continue;
-                       p->opt = rest + 1;
-               }
-               return get_value(p, options, flags);
-       }
-
-       if (ambiguous_option)
-               return error("Ambiguous option: %s "
-                       "(could be --%s%s or --%s%s)",
-                       arg,
-                       (ambiguous_flags & OPT_UNSET) ?  "no-" : "",
-                       ambiguous_option->long_name,
-                       (abbrev_flags & OPT_UNSET) ?  "no-" : "",
-                       abbrev_option->long_name);
-       if (abbrev_option)
-               return get_value(p, abbrev_option, abbrev_flags);
-       return -2;
-}
-
-static void check_typos(const char *arg, const struct option *options)
-{
-       if (strlen(arg) < 3)
-               return;
-
-       if (!prefixcmp(arg, "no-")) {
-               error ("did you mean `--%s` (with two dashes ?)", arg);
-               exit(129);
-       }
-
-       for (; options->type != OPTION_END; options++) {
-               if (!options->long_name)
-                       continue;
-               if (!prefixcmp(options->long_name, arg)) {
-                       error ("did you mean `--%s` (with two dashes ?)", arg);
-                       exit(129);
-               }
-       }
-}
-
-void parse_options_start(struct parse_opt_ctx_t *ctx,
-                        int argc, const char **argv, int flags)
-{
-       memset(ctx, 0, sizeof(*ctx));
-       ctx->argc = argc - 1;
-       ctx->argv = argv + 1;
-       ctx->out  = argv;
-       ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
-       ctx->flags = flags;
-       if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
-           (flags & PARSE_OPT_STOP_AT_NON_OPTION))
-               die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
-}
-
-static int usage_with_options_internal(const char * const *,
-                                      const struct option *, int,
-                                      struct parse_opt_ctx_t *);
-
-int parse_options_step(struct parse_opt_ctx_t *ctx,
-                      const struct option *options,
-                      const char * const usagestr[])
-{
-       int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
-       int excl_short_opt = 1;
-       const char *arg;
-
-       /* we must reset ->opt, unknown short option leave it dangling */
-       ctx->opt = NULL;
-
-       for (; ctx->argc; ctx->argc--, ctx->argv++) {
-               arg = ctx->argv[0];
-               if (*arg != '-' || !arg[1]) {
-                       if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
-                               break;
-                       ctx->out[ctx->cpidx++] = ctx->argv[0];
-                       continue;
-               }
-
-               if (arg[1] != '-') {
-                       ctx->opt = ++arg;
-                       if (internal_help && *ctx->opt == 'h') {
-                               return usage_with_options_internal(usagestr, options, 0, ctx);
-                       }
-                       switch (parse_short_opt(ctx, options)) {
-                       case -1:
-                               return parse_options_usage(usagestr, options, arg, 1);
-                       case -2:
-                               goto unknown;
-                       case -3:
-                               goto exclusive;
-                       default:
-                               break;
-                       }
-                       if (ctx->opt)
-                               check_typos(arg, options);
-                       while (ctx->opt) {
-                               if (internal_help && *ctx->opt == 'h')
-                                       return usage_with_options_internal(usagestr, options, 0, ctx);
-                               arg = ctx->opt;
-                               switch (parse_short_opt(ctx, options)) {
-                               case -1:
-                                       return parse_options_usage(usagestr, options, arg, 1);
-                               case -2:
-                                       /* fake a short option thing to hide the fact that we may have
-                                        * started to parse aggregated stuff
-                                        *
-                                        * This is leaky, too bad.
-                                        */
-                                       ctx->argv[0] = strdup(ctx->opt - 1);
-                                       *(char *)ctx->argv[0] = '-';
-                                       goto unknown;
-                               case -3:
-                                       goto exclusive;
-                               default:
-                                       break;
-                               }
-                       }
-                       continue;
-               }
-
-               if (!arg[2]) { /* "--" */
-                       if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
-                               ctx->argc--;
-                               ctx->argv++;
-                       }
-                       break;
-               }
-
-               arg += 2;
-               if (internal_help && !strcmp(arg, "help-all"))
-                       return usage_with_options_internal(usagestr, options, 1, ctx);
-               if (internal_help && !strcmp(arg, "help"))
-                       return usage_with_options_internal(usagestr, options, 0, ctx);
-               if (!strcmp(arg, "list-opts"))
-                       return PARSE_OPT_LIST_OPTS;
-               if (!strcmp(arg, "list-cmds"))
-                       return PARSE_OPT_LIST_SUBCMDS;
-               switch (parse_long_opt(ctx, arg, options)) {
-               case -1:
-                       return parse_options_usage(usagestr, options, arg, 0);
-               case -2:
-                       goto unknown;
-               case -3:
-                       excl_short_opt = 0;
-                       goto exclusive;
-               default:
-                       break;
-               }
-               continue;
-unknown:
-               if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
-                       return PARSE_OPT_UNKNOWN;
-               ctx->out[ctx->cpidx++] = ctx->argv[0];
-               ctx->opt = NULL;
-       }
-       return PARSE_OPT_DONE;
-
-exclusive:
-       parse_options_usage(usagestr, options, arg, excl_short_opt);
-       if ((excl_short_opt && ctx->excl_opt->short_name) ||
-           ctx->excl_opt->long_name == NULL) {
-               char opt = ctx->excl_opt->short_name;
-               parse_options_usage(NULL, options, &opt, 1);
-       } else {
-               parse_options_usage(NULL, options, ctx->excl_opt->long_name, 0);
-       }
-       return PARSE_OPT_HELP;
-}
-
-int parse_options_end(struct parse_opt_ctx_t *ctx)
-{
-       memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
-       ctx->out[ctx->cpidx + ctx->argc] = NULL;
-       return ctx->cpidx + ctx->argc;
-}
-
-int parse_options_subcommand(int argc, const char **argv, const struct option *options,
-                       const char *const subcommands[], const char *usagestr[], int flags)
-{
-       struct parse_opt_ctx_t ctx;
-
-       perf_env__set_cmdline(&perf_env, argc, argv);
-
-       /* build usage string if it's not provided */
-       if (subcommands && !usagestr[0]) {
-               struct strbuf buf = STRBUF_INIT;
-
-               strbuf_addf(&buf, "perf %s [<options>] {", argv[0]);
-               for (int i = 0; subcommands[i]; i++) {
-                       if (i)
-                               strbuf_addstr(&buf, "|");
-                       strbuf_addstr(&buf, subcommands[i]);
-               }
-               strbuf_addstr(&buf, "}");
-
-               usagestr[0] = strdup(buf.buf);
-               strbuf_release(&buf);
-       }
-
-       parse_options_start(&ctx, argc, argv, flags);
-       switch (parse_options_step(&ctx, options, usagestr)) {
-       case PARSE_OPT_HELP:
-               exit(129);
-       case PARSE_OPT_DONE:
-               break;
-       case PARSE_OPT_LIST_OPTS:
-               while (options->type != OPTION_END) {
-                       if (options->long_name)
-                               printf("--%s ", options->long_name);
-                       options++;
-               }
-               putchar('\n');
-               exit(130);
-       case PARSE_OPT_LIST_SUBCMDS:
-               if (subcommands) {
-                       for (int i = 0; subcommands[i]; i++)
-                               printf("%s ", subcommands[i]);
-               }
-               putchar('\n');
-               exit(130);
-       default: /* PARSE_OPT_UNKNOWN */
-               if (ctx.argv[0][1] == '-') {
-                       strbuf_addf(&error_buf, "unknown option `%s'",
-                                   ctx.argv[0] + 2);
-               } else {
-                       strbuf_addf(&error_buf, "unknown switch `%c'",
-                                   *ctx.opt);
-               }
-               usage_with_options(usagestr, options);
-       }
-
-       return parse_options_end(&ctx);
-}
-
-int parse_options(int argc, const char **argv, const struct option *options,
-                 const char * const usagestr[], int flags)
-{
-       return parse_options_subcommand(argc, argv, options, NULL,
-                                       (const char **) usagestr, flags);
-}
-
-#define USAGE_OPTS_WIDTH 24
-#define USAGE_GAP         2
-
-static void print_option_help(const struct option *opts, int full)
-{
-       size_t pos;
-       int pad;
-
-       if (opts->type == OPTION_GROUP) {
-               fputc('\n', stderr);
-               if (*opts->help)
-                       fprintf(stderr, "%s\n", opts->help);
-               return;
-       }
-       if (!full && (opts->flags & PARSE_OPT_HIDDEN))
-               return;
-       if (opts->flags & PARSE_OPT_DISABLED)
-               return;
-
-       pos = fprintf(stderr, "    ");
-       if (opts->short_name)
-               pos += fprintf(stderr, "-%c", opts->short_name);
-       else
-               pos += fprintf(stderr, "    ");
-
-       if (opts->long_name && opts->short_name)
-               pos += fprintf(stderr, ", ");
-       if (opts->long_name)
-               pos += fprintf(stderr, "--%s", opts->long_name);
-
-       switch (opts->type) {
-       case OPTION_ARGUMENT:
-               break;
-       case OPTION_LONG:
-       case OPTION_U64:
-       case OPTION_INTEGER:
-       case OPTION_UINTEGER:
-               if (opts->flags & PARSE_OPT_OPTARG)
-                       if (opts->long_name)
-                               pos += fprintf(stderr, "[=<n>]");
-                       else
-                               pos += fprintf(stderr, "[<n>]");
-               else
-                       pos += fprintf(stderr, " <n>");
-               break;
-       case OPTION_CALLBACK:
-               if (opts->flags & PARSE_OPT_NOARG)
-                       break;
-               /* FALLTHROUGH */
-       case OPTION_STRING:
-               if (opts->argh) {
-                       if (opts->flags & PARSE_OPT_OPTARG)
-                               if (opts->long_name)
-                                       pos += fprintf(stderr, "[=<%s>]", opts->argh);
-                               else
-                                       pos += fprintf(stderr, "[<%s>]", opts->argh);
-                       else
-                               pos += fprintf(stderr, " <%s>", opts->argh);
-               } else {
-                       if (opts->flags & PARSE_OPT_OPTARG)
-                               if (opts->long_name)
-                                       pos += fprintf(stderr, "[=...]");
-                               else
-                                       pos += fprintf(stderr, "[...]");
-                       else
-                               pos += fprintf(stderr, " ...");
-               }
-               break;
-       default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
-       case OPTION_END:
-       case OPTION_GROUP:
-       case OPTION_BIT:
-       case OPTION_BOOLEAN:
-       case OPTION_INCR:
-       case OPTION_SET_UINT:
-       case OPTION_SET_PTR:
-               break;
-       }
-
-       if (pos <= USAGE_OPTS_WIDTH)
-               pad = USAGE_OPTS_WIDTH - pos;
-       else {
-               fputc('\n', stderr);
-               pad = USAGE_OPTS_WIDTH;
-       }
-       fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
-}
-
-static int option__cmp(const void *va, const void *vb)
-{
-       const struct option *a = va, *b = vb;
-       int sa = tolower(a->short_name), sb = tolower(b->short_name), ret;
-
-       if (sa == 0)
-               sa = 'z' + 1;
-       if (sb == 0)
-               sb = 'z' + 1;
-
-       ret = sa - sb;
-
-       if (ret == 0) {
-               const char *la = a->long_name ?: "",
-                          *lb = b->long_name ?: "";
-               ret = strcmp(la, lb);
-       }
-
-       return ret;
-}
-
-static struct option *options__order(const struct option *opts)
-{
-       int nr_opts = 0;
-       const struct option *o = opts;
-       struct option *ordered;
-
-       for (o = opts; o->type != OPTION_END; o++)
-               ++nr_opts;
-
-       ordered = memdup(opts, sizeof(*o) * (nr_opts + 1));
-       if (ordered == NULL)
-               goto out;
-
-       qsort(ordered, nr_opts, sizeof(*o), option__cmp);
-out:
-       return ordered;
-}
-
-static bool option__in_argv(const struct option *opt, const struct parse_opt_ctx_t *ctx)
-{
-       int i;
-
-       for (i = 1; i < ctx->argc; ++i) {
-               const char *arg = ctx->argv[i];
-
-               if (arg[0] != '-') {
-                       if (arg[1] == '\0') {
-                               if (arg[0] == opt->short_name)
-                                       return true;
-                               continue;
-                       }
-
-                       if (opt->long_name && strcmp(opt->long_name, arg) == 0)
-                               return true;
-
-                       if (opt->help && strcasestr(opt->help, arg) != NULL)
-                               return true;
-
-                       continue;
-               }
-
-               if (arg[1] == opt->short_name ||
-                   (arg[1] == '-' && opt->long_name && strcmp(opt->long_name, arg + 2) == 0))
-                       return true;
-       }
-
-       return false;
-}
-
-int usage_with_options_internal(const char * const *usagestr,
-                               const struct option *opts, int full,
-                               struct parse_opt_ctx_t *ctx)
-{
-       struct option *ordered;
-
-       if (!usagestr)
-               return PARSE_OPT_HELP;
-
-       setup_pager();
-
-       if (strbuf_avail(&error_buf)) {
-               fprintf(stderr, "  Error: %s\n", error_buf.buf);
-               strbuf_release(&error_buf);
-       }
-
-       fprintf(stderr, "\n Usage: %s\n", *usagestr++);
-       while (*usagestr && **usagestr)
-               fprintf(stderr, "    or: %s\n", *usagestr++);
-       while (*usagestr) {
-               fprintf(stderr, "%s%s\n",
-                               **usagestr ? "    " : "",
-                               *usagestr);
-               usagestr++;
-       }
-
-       if (opts->type != OPTION_GROUP)
-               fputc('\n', stderr);
-
-       ordered = options__order(opts);
-       if (ordered)
-               opts = ordered;
-
-       for (  ; opts->type != OPTION_END; opts++) {
-               if (ctx && ctx->argc > 1 && !option__in_argv(opts, ctx))
-                       continue;
-               print_option_help(opts, full);
-       }
-
-       fputc('\n', stderr);
-
-       free(ordered);
-
-       return PARSE_OPT_HELP;
-}
-
-void usage_with_options(const char * const *usagestr,
-                       const struct option *opts)
-{
-       exit_browser(false);
-       usage_with_options_internal(usagestr, opts, 0, NULL);
-       exit(129);
-}
-
-void usage_with_options_msg(const char * const *usagestr,
-                           const struct option *opts, const char *fmt, ...)
-{
-       va_list ap;
-
-       exit_browser(false);
-
-       va_start(ap, fmt);
-       strbuf_addv(&error_buf, fmt, ap);
-       va_end(ap);
-
-       usage_with_options_internal(usagestr, opts, 0, NULL);
-       exit(129);
-}
-
-int parse_options_usage(const char * const *usagestr,
-                       const struct option *opts,
-                       const char *optstr, bool short_opt)
-{
-       if (!usagestr)
-               goto opt;
-
-       fprintf(stderr, "\n Usage: %s\n", *usagestr++);
-       while (*usagestr && **usagestr)
-               fprintf(stderr, "    or: %s\n", *usagestr++);
-       while (*usagestr) {
-               fprintf(stderr, "%s%s\n",
-                               **usagestr ? "    " : "",
-                               *usagestr);
-               usagestr++;
-       }
-       fputc('\n', stderr);
-
-opt:
-       for (  ; opts->type != OPTION_END; opts++) {
-               if (short_opt) {
-                       if (opts->short_name == *optstr) {
-                               print_option_help(opts, 0);
-                               break;
-                       }
-                       continue;
-               }
-
-               if (opts->long_name == NULL)
-                       continue;
-
-               if (!prefixcmp(opts->long_name, optstr))
-                       print_option_help(opts, 0);
-               if (!prefixcmp("no-", optstr) &&
-                   !prefixcmp(opts->long_name, optstr + 3))
-                       print_option_help(opts, 0);
-       }
-
-       return PARSE_OPT_HELP;
-}
-
-
-int parse_opt_verbosity_cb(const struct option *opt,
-                          const char *arg __maybe_unused,
-                          int unset)
-{
-       int *target = opt->value;
-
-       if (unset)
-               /* --no-quiet, --no-verbose */
-               *target = 0;
-       else if (opt->short_name == 'v') {
-               if (*target >= 0)
-                       (*target)++;
-               else
-                       *target = 1;
-       } else {
-               if (*target <= 0)
-                       (*target)--;
-               else
-                       *target = -1;
-       }
-       return 0;
-}
-
-void set_option_flag(struct option *opts, int shortopt, const char *longopt,
-                    int flag)
-{
-       for (; opts->type != OPTION_END; opts++) {
-               if ((shortopt && opts->short_name == shortopt) ||
-                   (opts->long_name && longopt &&
-                    !strcmp(opts->long_name, longopt))) {
-                       opts->flags |= flag;
-                       break;
-               }
-       }
-}
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
deleted file mode 100644 (file)
index a8e407b..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-#ifndef __PERF_PARSE_OPTIONS_H
-#define __PERF_PARSE_OPTIONS_H
-
-#include <linux/kernel.h>
-#include <stdbool.h>
-
-enum parse_opt_type {
-       /* special types */
-       OPTION_END,
-       OPTION_ARGUMENT,
-       OPTION_GROUP,
-       /* options with no arguments */
-       OPTION_BIT,
-       OPTION_BOOLEAN,
-       OPTION_INCR,
-       OPTION_SET_UINT,
-       OPTION_SET_PTR,
-       /* options with arguments (usually) */
-       OPTION_STRING,
-       OPTION_INTEGER,
-       OPTION_LONG,
-       OPTION_CALLBACK,
-       OPTION_U64,
-       OPTION_UINTEGER,
-};
-
-enum parse_opt_flags {
-       PARSE_OPT_KEEP_DASHDASH = 1,
-       PARSE_OPT_STOP_AT_NON_OPTION = 2,
-       PARSE_OPT_KEEP_ARGV0 = 4,
-       PARSE_OPT_KEEP_UNKNOWN = 8,
-       PARSE_OPT_NO_INTERNAL_HELP = 16,
-};
-
-enum parse_opt_option_flags {
-       PARSE_OPT_OPTARG  = 1,
-       PARSE_OPT_NOARG   = 2,
-       PARSE_OPT_NONEG   = 4,
-       PARSE_OPT_HIDDEN  = 8,
-       PARSE_OPT_LASTARG_DEFAULT = 16,
-       PARSE_OPT_DISABLED = 32,
-       PARSE_OPT_EXCLUSIVE = 64,
-       PARSE_OPT_NOEMPTY  = 128,
-};
-
-struct option;
-typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
-
-/*
- * `type`::
- *   holds the type of the option, you must have an OPTION_END last in your
- *   array.
- *
- * `short_name`::
- *   the character to use as a short option name, '\0' if none.
- *
- * `long_name`::
- *   the long option name, without the leading dashes, NULL if none.
- *
- * `value`::
- *   stores pointers to the values to be filled.
- *
- * `argh`::
- *   token to explain the kind of argument this option wants. Keep it
- *   homogenous across the repository.
- *
- * `help`::
- *   the short help associated to what the option does.
- *   Must never be NULL (except for OPTION_END).
- *   OPTION_GROUP uses this pointer to store the group header.
- *
- * `flags`::
- *   mask of parse_opt_option_flags.
- *   PARSE_OPT_OPTARG: says that the argument is optionnal (not for BOOLEANs)
- *   PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs
- *   PARSE_OPT_NONEG: says that this option cannot be negated
- *   PARSE_OPT_HIDDEN this option is skipped in the default usage, showed in
- *                    the long one.
- *
- * `callback`::
- *   pointer to the callback to use for OPTION_CALLBACK.
- *
- * `defval`::
- *   default value to fill (*->value) with for PARSE_OPT_OPTARG.
- *   OPTION_{BIT,SET_UINT,SET_PTR} store the {mask,integer,pointer} to put in
- *   the value when met.
- *   CALLBACKS can use it like they want.
- *
- * `set`::
- *   whether an option was set by the user
- */
-struct option {
-       enum parse_opt_type type;
-       int short_name;
-       const char *long_name;
-       void *value;
-       const char *argh;
-       const char *help;
-
-       int flags;
-       parse_opt_cb *callback;
-       intptr_t defval;
-       bool *set;
-       void *data;
-};
-
-#define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v )
-
-#define OPT_END()                   { .type = OPTION_END }
-#define OPT_ARGUMENT(l, h)          { .type = OPTION_ARGUMENT, .long_name = (l), .help = (h) }
-#define OPT_GROUP(h)                { .type = OPTION_GROUP, .help = (h) }
-#define OPT_BIT(s, l, v, h, b)      { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h), .defval = (b) }
-#define OPT_BOOLEAN(s, l, v, h)     { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h) }
-#define OPT_BOOLEAN_FLAG(s, l, v, h, f)     { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h), .flags = (f) }
-#define OPT_BOOLEAN_SET(s, l, v, os, h) \
-       { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), \
-       .value = check_vtype(v, bool *), .help = (h), \
-       .set = check_vtype(os, bool *)}
-#define OPT_INCR(s, l, v, h)        { .type = OPTION_INCR, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) }
-#define OPT_SET_UINT(s, l, v, h, i)  { .type = OPTION_SET_UINT, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h), .defval = (i) }
-#define OPT_SET_PTR(s, l, v, h, p)  { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) }
-#define OPT_INTEGER(s, l, v, h)     { .type = OPTION_INTEGER, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) }
-#define OPT_UINTEGER(s, l, v, h)    { .type = OPTION_UINTEGER, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h) }
-#define OPT_LONG(s, l, v, h)        { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = check_vtype(v, long *), .help = (h) }
-#define OPT_U64(s, l, v, h)         { .type = OPTION_U64, .short_name = (s), .long_name = (l), .value = check_vtype(v, u64 *), .help = (h) }
-#define OPT_STRING(s, l, v, a, h)   { .type = OPTION_STRING,  .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h) }
-#define OPT_STRING_OPTARG(s, l, v, a, h, d) \
-       { .type = OPTION_STRING,  .short_name = (s), .long_name = (l), \
-         .value = check_vtype(v, const char **), (a), .help = (h), \
-         .flags = PARSE_OPT_OPTARG, .defval = (intptr_t)(d) }
-#define OPT_STRING_NOEMPTY(s, l, v, a, h)   { .type = OPTION_STRING,  .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h), .flags = PARSE_OPT_NOEMPTY}
-#define OPT_DATE(s, l, v, h) \
-       { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }
-#define OPT_CALLBACK(s, l, v, a, h, f) \
-       { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f) }
-#define OPT_CALLBACK_NOOPT(s, l, v, a, h, f) \
-       { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .flags = PARSE_OPT_NOARG }
-#define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \
-       { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT }
-#define OPT_CALLBACK_DEFAULT_NOOPT(s, l, v, a, h, f, d) \
-       { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\
-       .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\
-       .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG}
-#define OPT_CALLBACK_OPTARG(s, l, v, d, a, h, f) \
-       { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), \
-         .value = (v), (a), .help = (h), .callback = (f), \
-         .flags = PARSE_OPT_OPTARG, .data = (d) }
-
-/* parse_options() will filter out the processed options and leave the
- * non-option argments in argv[].
- * Returns the number of arguments left in argv[].
- */
-extern int parse_options(int argc, const char **argv,
-                         const struct option *options,
-                         const char * const usagestr[], int flags);
-
-extern int parse_options_subcommand(int argc, const char **argv,
-                               const struct option *options,
-                               const char *const subcommands[],
-                               const char *usagestr[], int flags);
-
-extern NORETURN void usage_with_options(const char * const *usagestr,
-                                        const struct option *options);
-extern NORETURN __attribute__((format(printf,3,4)))
-void usage_with_options_msg(const char * const *usagestr,
-                           const struct option *options,
-                           const char *fmt, ...);
-
-/*----- incremantal advanced APIs -----*/
-
-enum {
-       PARSE_OPT_HELP = -1,
-       PARSE_OPT_DONE,
-       PARSE_OPT_LIST_OPTS,
-       PARSE_OPT_LIST_SUBCMDS,
-       PARSE_OPT_UNKNOWN,
-};
-
-/*
- * It's okay for the caller to consume argv/argc in the usual way.
- * Other fields of that structure are private to parse-options and should not
- * be modified in any way.
- */
-struct parse_opt_ctx_t {
-       const char **argv;
-       const char **out;
-       int argc, cpidx;
-       const char *opt;
-       const struct option *excl_opt;
-       int flags;
-};
-
-extern int parse_options_usage(const char * const *usagestr,
-                              const struct option *opts,
-                              const char *optstr,
-                              bool short_opt);
-
-extern void parse_options_start(struct parse_opt_ctx_t *ctx,
-                               int argc, const char **argv, int flags);
-
-extern int parse_options_step(struct parse_opt_ctx_t *ctx,
-                             const struct option *options,
-                             const char * const usagestr[]);
-
-extern int parse_options_end(struct parse_opt_ctx_t *ctx);
-
-
-/*----- some often used options -----*/
-extern int parse_opt_abbrev_cb(const struct option *, const char *, int);
-extern int parse_opt_approxidate_cb(const struct option *, const char *, int);
-extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
-
-#define OPT__VERBOSE(var)  OPT_BOOLEAN('v', "verbose", (var), "be verbose")
-#define OPT__QUIET(var)    OPT_BOOLEAN('q', "quiet",   (var), "be quiet")
-#define OPT__VERBOSITY(var) \
-       { OPTION_CALLBACK, 'v', "verbose", (var), NULL, "be more verbose", \
-         PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }, \
-       { OPTION_CALLBACK, 'q', "quiet", (var), NULL, "be more quiet", \
-         PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }
-#define OPT__DRY_RUN(var)  OPT_BOOLEAN('n', "dry-run", (var), "dry run")
-#define OPT__ABBREV(var)  \
-       { OPTION_CALLBACK, 0, "abbrev", (var), "n", \
-         "use <n> digits to display SHA-1s", \
-         PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
-
-extern const char *parse_options_fix_filename(const char *prefix, const char *file);
-
-void set_option_flag(struct option *opts, int sopt, const char *lopt, int flag);
-#endif /* __PERF_PARSE_OPTIONS_H */
index 4f2c1c255d818bcf0b13a05d806ddb04fcbd2ff5..646ecf736aadb78b8b747065a867a24f90e740b8 100644 (file)
@@ -1,7 +1,7 @@
 #include "perf.h"
 #include "util/util.h"
 #include "util/debug.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/parse-regs-options.h"
 
 int
index 5d13cb45b3171a98a171b0f7228d1fff470bf8c0..3654d964e49de2af41a30ca915a349563aba4fd1 100644 (file)
@@ -22,24 +22,6 @@ static const char *get_perf_dir(void)
        return ".";
 }
 
-/*
- * If libc has strlcpy() then that version will override this
- * implementation:
- */
-size_t __weak strlcpy(char *dest, const char *src, size_t size)
-{
-       size_t ret = strlen(src);
-
-       if (size) {
-               size_t len = (ret >= size) ? size - 1 : ret;
-
-               memcpy(dest, src, len);
-               dest[len] = '\0';
-       }
-
-       return ret;
-}
-
 static char *get_pathname(void)
 {
        static char pathname_array[4][PATH_MAX];
index e4b173dec4b9978cb3d1eb53c3569277c5110714..b597bcc8fc781f4fa2c631044bddaab447b756e9 100644 (file)
@@ -220,6 +220,7 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
        alias->scale = 1.0;
        alias->unit[0] = '\0';
        alias->per_pkg = false;
+       alias->snapshot = false;
 
        ret = parse_events_terms(&alias->terms, val);
        if (ret) {
index 03875f9154e7562c060e5935d30bc65d6ba0973b..93996ec4bbe34f9d380e93a2cb2e8f27c05dede6 100644 (file)
@@ -2326,8 +2326,11 @@ static int get_new_event_name(char *buf, size_t len, const char *base,
                goto out;
 
        if (!allow_suffix) {
-               pr_warning("Error: event \"%s\" already exists. "
-                          "(Use -f to force duplicates.)\n", buf);
+               pr_warning("Error: event \"%s\" already exists.\n"
+                          " Hint: Remove existing event by 'perf probe -d'\n"
+                          "       or force duplicates by 'perf probe -f'\n"
+                          "       or set 'force=yes' in BPF source.\n",
+                          buf);
                ret = -EEXIST;
                goto out;
        }
index 05012bb178d7a8d75ebf4879438fbc0d6f774926..2be10fb27172727fe15d5f3822ff194a5ad96d95 100644 (file)
@@ -654,6 +654,7 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod,
 static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
 {
        Dwarf_Attribute fb_attr;
+       Dwarf_Frame *frame = NULL;
        size_t nops;
        int ret;
 
@@ -686,11 +687,11 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
 #if _ELFUTILS_PREREQ(0, 142)
        } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
                   pf->cfi != NULL) {
-               Dwarf_Frame *frame;
                if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 ||
                    dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) {
                        pr_warning("Failed to get call frame on 0x%jx\n",
                                   (uintmax_t)pf->addr);
+                       free(frame);
                        return -ENOENT;
                }
 #endif
@@ -699,7 +700,8 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
        /* Call finder's callback handler */
        ret = pf->callback(sc_die, pf);
 
-       /* *pf->fb_ops will be cached in libdw. Don't free it. */
+       /* Since *pf->fb_ops can be a part of frame. we should free it here. */
+       free(frame);
        pf->fb_ops = NULL;
 
        return ret;
index 51be28b1bca26430de01a86649b976e382bb1198..8162ba0e2e57e7d265c283d474f8265430171713 100644 (file)
@@ -10,6 +10,8 @@ util/ctype.c
 util/evlist.c
 util/evsel.c
 util/cpumap.c
+../lib/bitmap.c
+../lib/find_bit.c
 ../lib/hweight.c
 util/thread_map.c
 util/util.c
diff --git a/tools/perf/util/run-command.c b/tools/perf/util/run-command.c
deleted file mode 100644 (file)
index 34622b5..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-#include "cache.h"
-#include "run-command.h"
-#include "exec_cmd.h"
-#include "debug.h"
-
-static inline void close_pair(int fd[2])
-{
-       close(fd[0]);
-       close(fd[1]);
-}
-
-static inline void dup_devnull(int to)
-{
-       int fd = open("/dev/null", O_RDWR);
-       dup2(fd, to);
-       close(fd);
-}
-
-int start_command(struct child_process *cmd)
-{
-       int need_in, need_out, need_err;
-       int fdin[2], fdout[2], fderr[2];
-       char sbuf[STRERR_BUFSIZE];
-
-       /*
-        * In case of errors we must keep the promise to close FDs
-        * that have been passed in via ->in and ->out.
-        */
-
-       need_in = !cmd->no_stdin && cmd->in < 0;
-       if (need_in) {
-               if (pipe(fdin) < 0) {
-                       if (cmd->out > 0)
-                               close(cmd->out);
-                       return -ERR_RUN_COMMAND_PIPE;
-               }
-               cmd->in = fdin[1];
-       }
-
-       need_out = !cmd->no_stdout
-               && !cmd->stdout_to_stderr
-               && cmd->out < 0;
-       if (need_out) {
-               if (pipe(fdout) < 0) {
-                       if (need_in)
-                               close_pair(fdin);
-                       else if (cmd->in)
-                               close(cmd->in);
-                       return -ERR_RUN_COMMAND_PIPE;
-               }
-               cmd->out = fdout[0];
-       }
-
-       need_err = !cmd->no_stderr && cmd->err < 0;
-       if (need_err) {
-               if (pipe(fderr) < 0) {
-                       if (need_in)
-                               close_pair(fdin);
-                       else if (cmd->in)
-                               close(cmd->in);
-                       if (need_out)
-                               close_pair(fdout);
-                       else if (cmd->out)
-                               close(cmd->out);
-                       return -ERR_RUN_COMMAND_PIPE;
-               }
-               cmd->err = fderr[0];
-       }
-
-       fflush(NULL);
-       cmd->pid = fork();
-       if (!cmd->pid) {
-               if (cmd->no_stdin)
-                       dup_devnull(0);
-               else if (need_in) {
-                       dup2(fdin[0], 0);
-                       close_pair(fdin);
-               } else if (cmd->in) {
-                       dup2(cmd->in, 0);
-                       close(cmd->in);
-               }
-
-               if (cmd->no_stderr)
-                       dup_devnull(2);
-               else if (need_err) {
-                       dup2(fderr[1], 2);
-                       close_pair(fderr);
-               }
-
-               if (cmd->no_stdout)
-                       dup_devnull(1);
-               else if (cmd->stdout_to_stderr)
-                       dup2(2, 1);
-               else if (need_out) {
-                       dup2(fdout[1], 1);
-                       close_pair(fdout);
-               } else if (cmd->out > 1) {
-                       dup2(cmd->out, 1);
-                       close(cmd->out);
-               }
-
-               if (cmd->dir && chdir(cmd->dir))
-                       die("exec %s: cd to %s failed (%s)", cmd->argv[0],
-                           cmd->dir, strerror_r(errno, sbuf, sizeof(sbuf)));
-               if (cmd->env) {
-                       for (; *cmd->env; cmd->env++) {
-                               if (strchr(*cmd->env, '='))
-                                       putenv((char*)*cmd->env);
-                               else
-                                       unsetenv(*cmd->env);
-                       }
-               }
-               if (cmd->preexec_cb)
-                       cmd->preexec_cb();
-               if (cmd->perf_cmd) {
-                       execv_perf_cmd(cmd->argv);
-               } else {
-                       execvp(cmd->argv[0], (char *const*) cmd->argv);
-               }
-               exit(127);
-       }
-
-       if (cmd->pid < 0) {
-               int err = errno;
-               if (need_in)
-                       close_pair(fdin);
-               else if (cmd->in)
-                       close(cmd->in);
-               if (need_out)
-                       close_pair(fdout);
-               else if (cmd->out)
-                       close(cmd->out);
-               if (need_err)
-                       close_pair(fderr);
-               return err == ENOENT ?
-                       -ERR_RUN_COMMAND_EXEC :
-                       -ERR_RUN_COMMAND_FORK;
-       }
-
-       if (need_in)
-               close(fdin[0]);
-       else if (cmd->in)
-               close(cmd->in);
-
-       if (need_out)
-               close(fdout[1]);
-       else if (cmd->out)
-               close(cmd->out);
-
-       if (need_err)
-               close(fderr[1]);
-
-       return 0;
-}
-
-static int wait_or_whine(pid_t pid)
-{
-       char sbuf[STRERR_BUFSIZE];
-
-       for (;;) {
-               int status, code;
-               pid_t waiting = waitpid(pid, &status, 0);
-
-               if (waiting < 0) {
-                       if (errno == EINTR)
-                               continue;
-                       error("waitpid failed (%s)",
-                             strerror_r(errno, sbuf, sizeof(sbuf)));
-                       return -ERR_RUN_COMMAND_WAITPID;
-               }
-               if (waiting != pid)
-                       return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
-               if (WIFSIGNALED(status))
-                       return -ERR_RUN_COMMAND_WAITPID_SIGNAL;
-
-               if (!WIFEXITED(status))
-                       return -ERR_RUN_COMMAND_WAITPID_NOEXIT;
-               code = WEXITSTATUS(status);
-               switch (code) {
-               case 127:
-                       return -ERR_RUN_COMMAND_EXEC;
-               case 0:
-                       return 0;
-               default:
-                       return -code;
-               }
-       }
-}
-
-int finish_command(struct child_process *cmd)
-{
-       return wait_or_whine(cmd->pid);
-}
-
-int run_command(struct child_process *cmd)
-{
-       int code = start_command(cmd);
-       if (code)
-               return code;
-       return finish_command(cmd);
-}
-
-static void prepare_run_command_v_opt(struct child_process *cmd,
-                                     const char **argv,
-                                     int opt)
-{
-       memset(cmd, 0, sizeof(*cmd));
-       cmd->argv = argv;
-       cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
-       cmd->perf_cmd = opt & RUN_PERF_CMD ? 1 : 0;
-       cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
-}
-
-int run_command_v_opt(const char **argv, int opt)
-{
-       struct child_process cmd;
-       prepare_run_command_v_opt(&cmd, argv, opt);
-       return run_command(&cmd);
-}
diff --git a/tools/perf/util/run-command.h b/tools/perf/util/run-command.h
deleted file mode 100644 (file)
index 1ef264d..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef __PERF_RUN_COMMAND_H
-#define __PERF_RUN_COMMAND_H
-
-enum {
-       ERR_RUN_COMMAND_FORK = 10000,
-       ERR_RUN_COMMAND_EXEC,
-       ERR_RUN_COMMAND_PIPE,
-       ERR_RUN_COMMAND_WAITPID,
-       ERR_RUN_COMMAND_WAITPID_WRONG_PID,
-       ERR_RUN_COMMAND_WAITPID_SIGNAL,
-       ERR_RUN_COMMAND_WAITPID_NOEXIT,
-};
-#define IS_RUN_COMMAND_ERR(x) (-(x) >= ERR_RUN_COMMAND_FORK)
-
-struct child_process {
-       const char **argv;
-       pid_t pid;
-       /*
-        * Using .in, .out, .err:
-        * - Specify 0 for no redirections (child inherits stdin, stdout,
-        *   stderr from parent).
-        * - Specify -1 to have a pipe allocated as follows:
-        *     .in: returns the writable pipe end; parent writes to it,
-        *          the readable pipe end becomes child's stdin
-        *     .out, .err: returns the readable pipe end; parent reads from
-        *          it, the writable pipe end becomes child's stdout/stderr
-        *   The caller of start_command() must close the returned FDs
-        *   after it has completed reading from/writing to it!
-        * - Specify > 0 to set a channel to a particular FD as follows:
-        *     .in: a readable FD, becomes child's stdin
-        *     .out: a writable FD, becomes child's stdout/stderr
-        *     .err > 0 not supported
-        *   The specified FD is closed by start_command(), even in case
-        *   of errors!
-        */
-       int in;
-       int out;
-       int err;
-       const char *dir;
-       const char *const *env;
-       unsigned no_stdin:1;
-       unsigned no_stdout:1;
-       unsigned no_stderr:1;
-       unsigned perf_cmd:1; /* if this is to be perf sub-command */
-       unsigned stdout_to_stderr:1;
-       void (*preexec_cb)(void);
-};
-
-int start_command(struct child_process *);
-int finish_command(struct child_process *);
-int run_command(struct child_process *);
-
-#define RUN_COMMAND_NO_STDIN 1
-#define RUN_PERF_CMD        2  /*If this is to be perf sub-command */
-#define RUN_COMMAND_STDOUT_TO_STDERR 4
-int run_command_v_opt(const char **argv, int opt);
-
-#endif /* __PERF_RUN_COMMAND_H */
index a8e825fca42af9aeab46de300855e5e22ea8ffc0..d72fafc1c800db1a699ac37e4ecb4acd0f1e3326 100644 (file)
@@ -41,6 +41,9 @@
 #include "../thread-stack.h"
 #include "../trace-event.h"
 #include "../machine.h"
+#include "thread_map.h"
+#include "cpumap.h"
+#include "stat.h"
 
 PyMODINIT_FUNC initperf_trace_context(void);
 
@@ -859,6 +862,104 @@ static void python_process_event(union perf_event *event,
        }
 }
 
+static void get_handler_name(char *str, size_t size,
+                            struct perf_evsel *evsel)
+{
+       char *p = str;
+
+       scnprintf(str, size, "stat__%s", perf_evsel__name(evsel));
+
+       while ((p = strchr(p, ':'))) {
+               *p = '_';
+               p++;
+       }
+}
+
+static void
+process_stat(struct perf_evsel *counter, int cpu, int thread, u64 tstamp,
+            struct perf_counts_values *count)
+{
+       PyObject *handler, *t;
+       static char handler_name[256];
+       int n = 0;
+
+       t = PyTuple_New(MAX_FIELDS);
+       if (!t)
+               Py_FatalError("couldn't create Python tuple");
+
+       get_handler_name(handler_name, sizeof(handler_name),
+                        counter);
+
+       handler = get_handler(handler_name);
+       if (!handler) {
+               pr_debug("can't find python handler %s\n", handler_name);
+               return;
+       }
+
+       PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
+       PyTuple_SetItem(t, n++, PyInt_FromLong(thread));
+
+       tuple_set_u64(t, n++, tstamp);
+       tuple_set_u64(t, n++, count->val);
+       tuple_set_u64(t, n++, count->ena);
+       tuple_set_u64(t, n++, count->run);
+
+       if (_PyTuple_Resize(&t, n) == -1)
+               Py_FatalError("error resizing Python tuple");
+
+       call_object(handler, t, handler_name);
+
+       Py_DECREF(t);
+}
+
+static void python_process_stat(struct perf_stat_config *config,
+                               struct perf_evsel *counter, u64 tstamp)
+{
+       struct thread_map *threads = counter->threads;
+       struct cpu_map *cpus = counter->cpus;
+       int cpu, thread;
+
+       if (config->aggr_mode == AGGR_GLOBAL) {
+               process_stat(counter, -1, -1, tstamp,
+                            &counter->counts->aggr);
+               return;
+       }
+
+       for (thread = 0; thread < threads->nr; thread++) {
+               for (cpu = 0; cpu < cpus->nr; cpu++) {
+                       process_stat(counter, cpus->map[cpu],
+                                    thread_map__pid(threads, thread), tstamp,
+                                    perf_counts(counter->counts, cpu, thread));
+               }
+       }
+}
+
+static void python_process_stat_interval(u64 tstamp)
+{
+       PyObject *handler, *t;
+       static const char handler_name[] = "stat__interval";
+       int n = 0;
+
+       t = PyTuple_New(MAX_FIELDS);
+       if (!t)
+               Py_FatalError("couldn't create Python tuple");
+
+       handler = get_handler(handler_name);
+       if (!handler) {
+               pr_debug("can't find python handler %s\n", handler_name);
+               return;
+       }
+
+       tuple_set_u64(t, n++, tstamp);
+
+       if (_PyTuple_Resize(&t, n) == -1)
+               Py_FatalError("error resizing Python tuple");
+
+       call_object(handler, t, handler_name);
+
+       Py_DECREF(t);
+}
+
 static int run_start_sub(void)
 {
        main_module = PyImport_AddModule("__main__");
@@ -1201,10 +1302,12 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
 }
 
 struct scripting_ops python_scripting_ops = {
-       .name = "Python",
-       .start_script = python_start_script,
-       .flush_script = python_flush_script,
-       .stop_script = python_stop_script,
-       .process_event = python_process_event,
-       .generate_script = python_generate_script,
+       .name                   = "Python",
+       .start_script           = python_start_script,
+       .flush_script           = python_flush_script,
+       .stop_script            = python_stop_script,
+       .process_event          = python_process_event,
+       .process_stat           = python_process_stat,
+       .process_stat_interval  = python_process_stat_interval,
+       .generate_script        = python_generate_script,
 };
index c35ffdd360fe13e1590559217365e0f78414e91c..d5636ba94b20f722d3f521614e8fae08b620fad4 100644 (file)
@@ -17,6 +17,7 @@
 #include "asm/bug.h"
 #include "auxtrace.h"
 #include "thread-stack.h"
+#include "stat.h"
 
 static int perf_session__deliver_event(struct perf_session *session,
                                       union perf_event *event,
@@ -36,6 +37,9 @@ static int perf_session__open(struct perf_session *session)
        if (perf_data_file__is_pipe(file))
                return 0;
 
+       if (perf_header__has_feat(&session->header, HEADER_STAT))
+               return 0;
+
        if (!perf_evlist__valid_sample_type(session->evlist)) {
                pr_err("non matching sample_type\n");
                return -1;
@@ -205,6 +209,18 @@ static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused,
        return 0;
 }
 
+static int process_event_synth_event_update_stub(struct perf_tool *tool __maybe_unused,
+                                                union perf_event *event __maybe_unused,
+                                                struct perf_evlist **pevlist
+                                                __maybe_unused)
+{
+       if (dump_trace)
+               perf_event__fprintf_event_update(event, stdout);
+
+       dump_printf(": unhandled!\n");
+       return 0;
+}
+
 static int process_event_sample_stub(struct perf_tool *tool __maybe_unused,
                                     union perf_event *event __maybe_unused,
                                     struct perf_sample *sample __maybe_unused,
@@ -296,6 +312,67 @@ int process_event_auxtrace_error_stub(struct perf_tool *tool __maybe_unused,
        return 0;
 }
 
+
+static
+int process_event_thread_map_stub(struct perf_tool *tool __maybe_unused,
+                                 union perf_event *event __maybe_unused,
+                                 struct perf_session *session __maybe_unused)
+{
+       if (dump_trace)
+               perf_event__fprintf_thread_map(event, stdout);
+
+       dump_printf(": unhandled!\n");
+       return 0;
+}
+
+static
+int process_event_cpu_map_stub(struct perf_tool *tool __maybe_unused,
+                              union perf_event *event __maybe_unused,
+                              struct perf_session *session __maybe_unused)
+{
+       if (dump_trace)
+               perf_event__fprintf_cpu_map(event, stdout);
+
+       dump_printf(": unhandled!\n");
+       return 0;
+}
+
+static
+int process_event_stat_config_stub(struct perf_tool *tool __maybe_unused,
+                                  union perf_event *event __maybe_unused,
+                                  struct perf_session *session __maybe_unused)
+{
+       if (dump_trace)
+               perf_event__fprintf_stat_config(event, stdout);
+
+       dump_printf(": unhandled!\n");
+       return 0;
+}
+
+static int process_stat_stub(struct perf_tool *tool __maybe_unused,
+                            union perf_event *event __maybe_unused,
+                            struct perf_session *perf_session
+                            __maybe_unused)
+{
+       if (dump_trace)
+               perf_event__fprintf_stat(event, stdout);
+
+       dump_printf(": unhandled!\n");
+       return 0;
+}
+
+static int process_stat_round_stub(struct perf_tool *tool __maybe_unused,
+                                  union perf_event *event __maybe_unused,
+                                  struct perf_session *perf_session
+                                  __maybe_unused)
+{
+       if (dump_trace)
+               perf_event__fprintf_stat_round(event, stdout);
+
+       dump_printf(": unhandled!\n");
+       return 0;
+}
+
 void perf_tool__fill_defaults(struct perf_tool *tool)
 {
        if (tool->sample == NULL)
@@ -328,6 +405,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
                tool->unthrottle = process_event_stub;
        if (tool->attr == NULL)
                tool->attr = process_event_synth_attr_stub;
+       if (tool->event_update == NULL)
+               tool->event_update = process_event_synth_event_update_stub;
        if (tool->tracing_data == NULL)
                tool->tracing_data = process_event_synth_tracing_data_stub;
        if (tool->build_id == NULL)
@@ -346,6 +425,16 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
                tool->auxtrace = process_event_auxtrace_stub;
        if (tool->auxtrace_error == NULL)
                tool->auxtrace_error = process_event_auxtrace_error_stub;
+       if (tool->thread_map == NULL)
+               tool->thread_map = process_event_thread_map_stub;
+       if (tool->cpu_map == NULL)
+               tool->cpu_map = process_event_cpu_map_stub;
+       if (tool->stat_config == NULL)
+               tool->stat_config = process_event_stat_config_stub;
+       if (tool->stat == NULL)
+               tool->stat = process_stat_stub;
+       if (tool->stat_round == NULL)
+               tool->stat_round = process_stat_round_stub;
 }
 
 static void swap_sample_id_all(union perf_event *event, void *data)
@@ -569,6 +658,13 @@ static void perf_event__hdr_attr_swap(union perf_event *event,
        mem_bswap_64(event->attr.id, size);
 }
 
+static void perf_event__event_update_swap(union perf_event *event,
+                                         bool sample_id_all __maybe_unused)
+{
+       event->event_update.type = bswap_64(event->event_update.type);
+       event->event_update.id   = bswap_64(event->event_update.id);
+}
+
 static void perf_event__event_type_swap(union perf_event *event,
                                        bool sample_id_all __maybe_unused)
 {
@@ -616,6 +712,81 @@ static void perf_event__auxtrace_error_swap(union perf_event *event,
        event->auxtrace_error.ip   = bswap_64(event->auxtrace_error.ip);
 }
 
+static void perf_event__thread_map_swap(union perf_event *event,
+                                       bool sample_id_all __maybe_unused)
+{
+       unsigned i;
+
+       event->thread_map.nr = bswap_64(event->thread_map.nr);
+
+       for (i = 0; i < event->thread_map.nr; i++)
+               event->thread_map.entries[i].pid = bswap_64(event->thread_map.entries[i].pid);
+}
+
+static void perf_event__cpu_map_swap(union perf_event *event,
+                                    bool sample_id_all __maybe_unused)
+{
+       struct cpu_map_data *data = &event->cpu_map.data;
+       struct cpu_map_entries *cpus;
+       struct cpu_map_mask *mask;
+       unsigned i;
+
+       data->type = bswap_64(data->type);
+
+       switch (data->type) {
+       case PERF_CPU_MAP__CPUS:
+               cpus = (struct cpu_map_entries *)data->data;
+
+               cpus->nr = bswap_16(cpus->nr);
+
+               for (i = 0; i < cpus->nr; i++)
+                       cpus->cpu[i] = bswap_16(cpus->cpu[i]);
+               break;
+       case PERF_CPU_MAP__MASK:
+               mask = (struct cpu_map_mask *) data->data;
+
+               mask->nr = bswap_16(mask->nr);
+               mask->long_size = bswap_16(mask->long_size);
+
+               switch (mask->long_size) {
+               case 4: mem_bswap_32(&mask->mask, mask->nr); break;
+               case 8: mem_bswap_64(&mask->mask, mask->nr); break;
+               default:
+                       pr_err("cpu_map swap: unsupported long size\n");
+               }
+       default:
+               break;
+       }
+}
+
+static void perf_event__stat_config_swap(union perf_event *event,
+                                        bool sample_id_all __maybe_unused)
+{
+       u64 size;
+
+       size  = event->stat_config.nr * sizeof(event->stat_config.data[0]);
+       size += 1; /* nr item itself */
+       mem_bswap_64(&event->stat_config.nr, size);
+}
+
+static void perf_event__stat_swap(union perf_event *event,
+                                 bool sample_id_all __maybe_unused)
+{
+       event->stat.id     = bswap_64(event->stat.id);
+       event->stat.thread = bswap_32(event->stat.thread);
+       event->stat.cpu    = bswap_32(event->stat.cpu);
+       event->stat.val    = bswap_64(event->stat.val);
+       event->stat.ena    = bswap_64(event->stat.ena);
+       event->stat.run    = bswap_64(event->stat.run);
+}
+
+static void perf_event__stat_round_swap(union perf_event *event,
+                                       bool sample_id_all __maybe_unused)
+{
+       event->stat_round.type = bswap_64(event->stat_round.type);
+       event->stat_round.time = bswap_64(event->stat_round.time);
+}
+
 typedef void (*perf_event__swap_op)(union perf_event *event,
                                    bool sample_id_all);
 
@@ -643,6 +814,12 @@ static perf_event__swap_op perf_event__swap_ops[] = {
        [PERF_RECORD_AUXTRACE_INFO]       = perf_event__auxtrace_info_swap,
        [PERF_RECORD_AUXTRACE]            = perf_event__auxtrace_swap,
        [PERF_RECORD_AUXTRACE_ERROR]      = perf_event__auxtrace_error_swap,
+       [PERF_RECORD_THREAD_MAP]          = perf_event__thread_map_swap,
+       [PERF_RECORD_CPU_MAP]             = perf_event__cpu_map_swap,
+       [PERF_RECORD_STAT_CONFIG]         = perf_event__stat_config_swap,
+       [PERF_RECORD_STAT]                = perf_event__stat_swap,
+       [PERF_RECORD_STAT_ROUND]          = perf_event__stat_round_swap,
+       [PERF_RECORD_EVENT_UPDATE]        = perf_event__event_update_swap,
        [PERF_RECORD_HEADER_MAX]          = NULL,
 };
 
@@ -1154,6 +1331,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
                        perf_session__set_comm_exec(session);
                }
                return err;
+       case PERF_RECORD_EVENT_UPDATE:
+               return tool->event_update(tool, event, &session->evlist);
        case PERF_RECORD_HEADER_EVENT_TYPE:
                /*
                 * Depreceated, but we need to handle it for sake
@@ -1179,6 +1358,16 @@ static s64 perf_session__process_user_event(struct perf_session *session,
        case PERF_RECORD_AUXTRACE_ERROR:
                perf_session__auxtrace_error_inc(session, event);
                return tool->auxtrace_error(tool, event, session);
+       case PERF_RECORD_THREAD_MAP:
+               return tool->thread_map(tool, event, session);
+       case PERF_RECORD_CPU_MAP:
+               return tool->cpu_map(tool, event, session);
+       case PERF_RECORD_STAT_CONFIG:
+               return tool->stat_config(tool, event, session);
+       case PERF_RECORD_STAT:
+               return tool->stat(tool, event, session);
+       case PERF_RECORD_STAT_ROUND:
+               return tool->stat_round(tool, event, session);
        default:
                return -EINVAL;
        }
@@ -1311,17 +1500,20 @@ struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
        return machine__findnew_thread(&session->machines.host, -1, pid);
 }
 
-struct thread *perf_session__register_idle_thread(struct perf_session *session)
+int perf_session__register_idle_thread(struct perf_session *session)
 {
        struct thread *thread;
+       int err = 0;
 
        thread = machine__findnew_thread(&session->machines.host, 0, 0);
        if (thread == NULL || thread__set_comm(thread, "swapper", 0)) {
                pr_err("problem inserting idle task.\n");
-               thread = NULL;
+               err = -1;
        }
 
-       return thread;
+       /* machine__findnew_thread() got the thread, so put it */
+       thread__put(thread);
+       return err;
 }
 
 static void perf_session__warn_about_errors(const struct perf_session *session)
@@ -1676,7 +1868,7 @@ int perf_session__process_events(struct perf_session *session)
        u64 size = perf_data_file__size(session->file);
        int err;
 
-       if (perf_session__register_idle_thread(session) == NULL)
+       if (perf_session__register_idle_thread(session) < 0)
                return -ENOMEM;
 
        if (!perf_data_file__is_pipe(session->file))
index 3e900c0efc734a19188ff2e6658e0321f9b6b843..5f792e35d4c1e2f72201aceb650798ee3f6a9f26 100644 (file)
@@ -89,7 +89,7 @@ struct machine *perf_session__findnew_machine(struct perf_session *session, pid_
 }
 
 struct thread *perf_session__findnew(struct perf_session *session, pid_t pid);
-struct thread *perf_session__register_idle_thread(struct perf_session *session);
+int perf_session__register_idle_thread(struct perf_session *session);
 
 size_t perf_session__fprintf(struct perf_session *session, FILE *fp);
 
diff --git a/tools/perf/util/sigchain.c b/tools/perf/util/sigchain.c
deleted file mode 100644 (file)
index ba785e9..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#include "sigchain.h"
-#include "cache.h"
-
-#define SIGCHAIN_MAX_SIGNALS 32
-
-struct sigchain_signal {
-       sigchain_fun *old;
-       int n;
-       int alloc;
-};
-static struct sigchain_signal signals[SIGCHAIN_MAX_SIGNALS];
-
-static void check_signum(int sig)
-{
-       if (sig < 1 || sig >= SIGCHAIN_MAX_SIGNALS)
-               die("BUG: signal out of range: %d", sig);
-}
-
-static int sigchain_push(int sig, sigchain_fun f)
-{
-       struct sigchain_signal *s = signals + sig;
-       check_signum(sig);
-
-       ALLOC_GROW(s->old, s->n + 1, s->alloc);
-       s->old[s->n] = signal(sig, f);
-       if (s->old[s->n] == SIG_ERR)
-               return -1;
-       s->n++;
-       return 0;
-}
-
-int sigchain_pop(int sig)
-{
-       struct sigchain_signal *s = signals + sig;
-       check_signum(sig);
-       if (s->n < 1)
-               return 0;
-
-       if (signal(sig, s->old[s->n - 1]) == SIG_ERR)
-               return -1;
-       s->n--;
-       return 0;
-}
-
-void sigchain_push_common(sigchain_fun f)
-{
-       sigchain_push(SIGINT, f);
-       sigchain_push(SIGHUP, f);
-       sigchain_push(SIGTERM, f);
-       sigchain_push(SIGQUIT, f);
-       sigchain_push(SIGPIPE, f);
-}
diff --git a/tools/perf/util/sigchain.h b/tools/perf/util/sigchain.h
deleted file mode 100644 (file)
index 959d64e..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef __PERF_SIGCHAIN_H
-#define __PERF_SIGCHAIN_H
-
-typedef void (*sigchain_fun)(int);
-
-int sigchain_pop(int sig);
-
-void sigchain_push_common(sigchain_fun f);
-
-#endif /* __PERF_SIGCHAIN_H */
index 2d8ccd4d9e1b7bd5231d35c2afaaec9078c86573..ec722346e6ffb8dd6531e94576bb15b548a1487b 100644 (file)
@@ -4,6 +4,8 @@
 #include "comm.h"
 #include "symbol.h"
 #include "evsel.h"
+#include "evlist.h"
+#include <traceevent/event-parse.h>
 
 regex_t                parent_regex;
 const char     default_parent_pattern[] = "^sys_|^do_page_fault";
@@ -13,6 +15,7 @@ const char    default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cy
 const char     default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
 const char     default_top_sort_order[] = "dso,symbol";
 const char     default_diff_sort_order[] = "dso,symbol";
+const char     default_tracepoint_sort_order[] = "trace";
 const char     *sort_order;
 const char     *field_order;
 regex_t                ignore_callees_regex;
@@ -443,6 +446,70 @@ struct sort_entry sort_socket = {
        .se_width_idx   = HISTC_SOCKET,
 };
 
+/* --sort trace */
+
+static char *get_trace_output(struct hist_entry *he)
+{
+       struct trace_seq seq;
+       struct perf_evsel *evsel;
+       struct pevent_record rec = {
+               .data = he->raw_data,
+               .size = he->raw_size,
+       };
+
+       evsel = hists_to_evsel(he->hists);
+
+       trace_seq_init(&seq);
+       if (symbol_conf.raw_trace) {
+               pevent_print_fields(&seq, he->raw_data, he->raw_size,
+                                   evsel->tp_format);
+       } else {
+               pevent_event_info(&seq, evsel->tp_format, &rec);
+       }
+       return seq.buffer;
+}
+
+static int64_t
+sort__trace_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       struct perf_evsel *evsel;
+
+       evsel = hists_to_evsel(left->hists);
+       if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
+               return 0;
+
+       if (left->trace_output == NULL)
+               left->trace_output = get_trace_output(left);
+       if (right->trace_output == NULL)
+               right->trace_output = get_trace_output(right);
+
+       hists__new_col_len(left->hists, HISTC_TRACE, strlen(left->trace_output));
+       hists__new_col_len(right->hists, HISTC_TRACE, strlen(right->trace_output));
+
+       return strcmp(right->trace_output, left->trace_output);
+}
+
+static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf,
+                                   size_t size, unsigned int width)
+{
+       struct perf_evsel *evsel;
+
+       evsel = hists_to_evsel(he->hists);
+       if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
+               return scnprintf(bf, size, "%-*.*s", width, width, "N/A");
+
+       if (he->trace_output == NULL)
+               he->trace_output = get_trace_output(he);
+       return repsep_snprintf(bf, size, "%-*.*s", width, width, he->trace_output);
+}
+
+struct sort_entry sort_trace = {
+       .se_header      = "Trace output",
+       .se_cmp         = sort__trace_cmp,
+       .se_snprintf    = hist_entry__trace_snprintf,
+       .se_width_idx   = HISTC_TRACE,
+};
+
 /* sort keys for branch stacks */
 
 static int64_t
@@ -1312,6 +1379,7 @@ static struct sort_dimension common_sort_dimensions[] = {
        DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
        DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
        DIM(SORT_TRANSACTION, "transaction", sort_transaction),
+       DIM(SORT_TRACE, "trace", sort_trace),
 };
 
 #undef DIM
@@ -1529,6 +1597,455 @@ static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
        return 0;
 }
 
+struct hpp_dynamic_entry {
+       struct perf_hpp_fmt hpp;
+       struct perf_evsel *evsel;
+       struct format_field *field;
+       unsigned dynamic_len;
+       bool raw_trace;
+};
+
+static int hde_width(struct hpp_dynamic_entry *hde)
+{
+       if (!hde->hpp.len) {
+               int len = hde->dynamic_len;
+               int namelen = strlen(hde->field->name);
+               int fieldlen = hde->field->size;
+
+               if (namelen > len)
+                       len = namelen;
+
+               if (!(hde->field->flags & FIELD_IS_STRING)) {
+                       /* length for print hex numbers */
+                       fieldlen = hde->field->size * 2 + 2;
+               }
+               if (fieldlen > len)
+                       len = fieldlen;
+
+               hde->hpp.len = len;
+       }
+       return hde->hpp.len;
+}
+
+static void update_dynamic_len(struct hpp_dynamic_entry *hde,
+                              struct hist_entry *he)
+{
+       char *str, *pos;
+       struct format_field *field = hde->field;
+       size_t namelen;
+       bool last = false;
+
+       if (hde->raw_trace)
+               return;
+
+       /* parse pretty print result and update max length */
+       if (!he->trace_output)
+               he->trace_output = get_trace_output(he);
+
+       namelen = strlen(field->name);
+       str = he->trace_output;
+
+       while (str) {
+               pos = strchr(str, ' ');
+               if (pos == NULL) {
+                       last = true;
+                       pos = str + strlen(str);
+               }
+
+               if (!strncmp(str, field->name, namelen)) {
+                       size_t len;
+
+                       str += namelen + 1;
+                       len = pos - str;
+
+                       if (len > hde->dynamic_len)
+                               hde->dynamic_len = len;
+                       break;
+               }
+
+               if (last)
+                       str = NULL;
+               else
+                       str = pos + 1;
+       }
+}
+
+static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+                             struct perf_evsel *evsel __maybe_unused)
+{
+       struct hpp_dynamic_entry *hde;
+       size_t len = fmt->user_len;
+
+       hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
+
+       if (!len)
+               len = hde_width(hde);
+
+       return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, hde->field->name);
+}
+
+static int __sort__hde_width(struct perf_hpp_fmt *fmt,
+                            struct perf_hpp *hpp __maybe_unused,
+                            struct perf_evsel *evsel __maybe_unused)
+{
+       struct hpp_dynamic_entry *hde;
+       size_t len = fmt->user_len;
+
+       hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
+
+       if (!len)
+               len = hde_width(hde);
+
+       return len;
+}
+
+bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists)
+{
+       struct hpp_dynamic_entry *hde;
+
+       hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
+
+       return hists_to_evsel(hists) == hde->evsel;
+}
+
+static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+                            struct hist_entry *he)
+{
+       struct hpp_dynamic_entry *hde;
+       size_t len = fmt->user_len;
+       char *str, *pos;
+       struct format_field *field;
+       size_t namelen;
+       bool last = false;
+       int ret;
+
+       hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
+
+       if (!len)
+               len = hde_width(hde);
+
+       if (hde->raw_trace)
+               goto raw_field;
+
+       field = hde->field;
+       namelen = strlen(field->name);
+       str = he->trace_output;
+
+       while (str) {
+               pos = strchr(str, ' ');
+               if (pos == NULL) {
+                       last = true;
+                       pos = str + strlen(str);
+               }
+
+               if (!strncmp(str, field->name, namelen)) {
+                       str += namelen + 1;
+                       str = strndup(str, pos - str);
+
+                       if (str == NULL)
+                               return scnprintf(hpp->buf, hpp->size,
+                                                "%*.*s", len, len, "ERROR");
+                       break;
+               }
+
+               if (last)
+                       str = NULL;
+               else
+                       str = pos + 1;
+       }
+
+       if (str == NULL) {
+               struct trace_seq seq;
+raw_field:
+               trace_seq_init(&seq);
+               pevent_print_field(&seq, he->raw_data, hde->field);
+               str = seq.buffer;
+       }
+
+       ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, str);
+       free(str);
+       return ret;
+}
+
+static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
+                              struct hist_entry *a, struct hist_entry *b)
+{
+       struct hpp_dynamic_entry *hde;
+       struct format_field *field;
+       unsigned offset, size;
+
+       hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
+
+       field = hde->field;
+       if (field->flags & FIELD_IS_DYNAMIC) {
+               unsigned long long dyn;
+
+               pevent_read_number_field(field, a->raw_data, &dyn);
+               offset = dyn & 0xffff;
+               size = (dyn >> 16) & 0xffff;
+
+               /* record max width for output */
+               if (size > hde->dynamic_len)
+                       hde->dynamic_len = size;
+       } else {
+               offset = field->offset;
+               size = field->size;
+
+               update_dynamic_len(hde, a);
+               update_dynamic_len(hde, b);
+       }
+
+       return memcmp(a->raw_data + offset, b->raw_data + offset, size);
+}
+
+bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt)
+{
+       return fmt->cmp == __sort__hde_cmp;
+}
+
+static struct hpp_dynamic_entry *
+__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field)
+{
+       struct hpp_dynamic_entry *hde;
+
+       hde = malloc(sizeof(*hde));
+       if (hde == NULL) {
+               pr_debug("Memory allocation failed\n");
+               return NULL;
+       }
+
+       hde->evsel = evsel;
+       hde->field = field;
+       hde->dynamic_len = 0;
+
+       hde->hpp.name = field->name;
+       hde->hpp.header = __sort__hde_header;
+       hde->hpp.width  = __sort__hde_width;
+       hde->hpp.entry  = __sort__hde_entry;
+       hde->hpp.color  = NULL;
+
+       hde->hpp.cmp = __sort__hde_cmp;
+       hde->hpp.collapse = __sort__hde_cmp;
+       hde->hpp.sort = __sort__hde_cmp;
+
+       INIT_LIST_HEAD(&hde->hpp.list);
+       INIT_LIST_HEAD(&hde->hpp.sort_list);
+       hde->hpp.elide = false;
+       hde->hpp.len = 0;
+       hde->hpp.user_len = 0;
+
+       return hde;
+}
+
+static int parse_field_name(char *str, char **event, char **field, char **opt)
+{
+       char *event_name, *field_name, *opt_name;
+
+       event_name = str;
+       field_name = strchr(str, '.');
+
+       if (field_name) {
+               *field_name++ = '\0';
+       } else {
+               event_name = NULL;
+               field_name = str;
+       }
+
+       opt_name = strchr(field_name, '/');
+       if (opt_name)
+               *opt_name++ = '\0';
+
+       *event = event_name;
+       *field = field_name;
+       *opt   = opt_name;
+
+       return 0;
+}
+
+/* find match evsel using a given event name.  The event name can be:
+ *   1. '%' + event index (e.g. '%1' for first event)
+ *   2. full event name (e.g. sched:sched_switch)
+ *   3. partial event name (should not contain ':')
+ */
+static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_name)
+{
+       struct perf_evsel *evsel = NULL;
+       struct perf_evsel *pos;
+       bool full_name;
+
+       /* case 1 */
+       if (event_name[0] == '%') {
+               int nr = strtol(event_name+1, NULL, 0);
+
+               if (nr > evlist->nr_entries)
+                       return NULL;
+
+               evsel = perf_evlist__first(evlist);
+               while (--nr > 0)
+                       evsel = perf_evsel__next(evsel);
+
+               return evsel;
+       }
+
+       full_name = !!strchr(event_name, ':');
+       evlist__for_each(evlist, pos) {
+               /* case 2 */
+               if (full_name && !strcmp(pos->name, event_name))
+                       return pos;
+               /* case 3 */
+               if (!full_name && strstr(pos->name, event_name)) {
+                       if (evsel) {
+                               pr_debug("'%s' event is ambiguous: it can be %s or %s\n",
+                                        event_name, evsel->name, pos->name);
+                               return NULL;
+                       }
+                       evsel = pos;
+               }
+       }
+
+       return evsel;
+}
+
+static int __dynamic_dimension__add(struct perf_evsel *evsel,
+                                   struct format_field *field,
+                                   bool raw_trace)
+{
+       struct hpp_dynamic_entry *hde;
+
+       hde = __alloc_dynamic_entry(evsel, field);
+       if (hde == NULL)
+               return -ENOMEM;
+
+       hde->raw_trace = raw_trace;
+
+       perf_hpp__register_sort_field(&hde->hpp);
+       return 0;
+}
+
+static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace)
+{
+       int ret;
+       struct format_field *field;
+
+       field = evsel->tp_format->format.fields;
+       while (field) {
+               ret = __dynamic_dimension__add(evsel, field, raw_trace);
+               if (ret < 0)
+                       return ret;
+
+               field = field->next;
+       }
+       return 0;
+}
+
+static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace)
+{
+       int ret;
+       struct perf_evsel *evsel;
+
+       evlist__for_each(evlist, evsel) {
+               if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
+                       continue;
+
+               ret = add_evsel_fields(evsel, raw_trace);
+               if (ret < 0)
+                       return ret;
+       }
+       return 0;
+}
+
+static int add_all_matching_fields(struct perf_evlist *evlist,
+                                  char *field_name, bool raw_trace)
+{
+       int ret = -ESRCH;
+       struct perf_evsel *evsel;
+       struct format_field *field;
+
+       evlist__for_each(evlist, evsel) {
+               if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
+                       continue;
+
+               field = pevent_find_any_field(evsel->tp_format, field_name);
+               if (field == NULL)
+                       continue;
+
+               ret = __dynamic_dimension__add(evsel, field, raw_trace);
+               if (ret < 0)
+                       break;
+       }
+       return ret;
+}
+
+static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
+{
+       char *str, *event_name, *field_name, *opt_name;
+       struct perf_evsel *evsel;
+       struct format_field *field;
+       bool raw_trace = symbol_conf.raw_trace;
+       int ret = 0;
+
+       if (evlist == NULL)
+               return -ENOENT;
+
+       str = strdup(tok);
+       if (str == NULL)
+               return -ENOMEM;
+
+       if (parse_field_name(str, &event_name, &field_name, &opt_name) < 0) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (opt_name) {
+               if (strcmp(opt_name, "raw")) {
+                       pr_debug("unsupported field option %s\n", opt_name);
+                       ret = -EINVAL;
+                       goto out;
+               }
+               raw_trace = true;
+       }
+
+       if (!strcmp(field_name, "trace_fields")) {
+               ret = add_all_dynamic_fields(evlist, raw_trace);
+               goto out;
+       }
+
+       if (event_name == NULL) {
+               ret = add_all_matching_fields(evlist, field_name, raw_trace);
+               goto out;
+       }
+
+       evsel = find_evsel(evlist, event_name);
+       if (evsel == NULL) {
+               pr_debug("Cannot find event: %s\n", event_name);
+               ret = -ENOENT;
+               goto out;
+       }
+
+       if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
+               pr_debug("%s is not a tracepoint event\n", event_name);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (!strcmp(field_name, "*")) {
+               ret = add_evsel_fields(evsel, raw_trace);
+       } else {
+               field = pevent_find_any_field(evsel->tp_format, field_name);
+               if (field == NULL) {
+                       pr_debug("Cannot find event field for %s.%s\n",
+                                event_name, field_name);
+                       return -ENOENT;
+               }
+
+               ret = __dynamic_dimension__add(evsel, field, raw_trace);
+       }
+
+out:
+       free(str);
+       return ret;
+}
+
 static int __sort_dimension__add(struct sort_dimension *sd)
 {
        if (sd->taken)
@@ -1583,7 +2100,8 @@ int hpp_dimension__add_output(unsigned col)
        return __hpp_dimension__add_output(&hpp_sort_dimensions[col]);
 }
 
-int sort_dimension__add(const char *tok)
+static int sort_dimension__add(const char *tok,
+                              struct perf_evlist *evlist __maybe_unused)
 {
        unsigned int i;
 
@@ -1664,10 +2182,13 @@ int sort_dimension__add(const char *tok)
                return 0;
        }
 
+       if (!add_dynamic_entry(evlist, tok))
+               return 0;
+
        return -ESRCH;
 }
 
-static const char *get_default_sort_order(void)
+static const char *get_default_sort_order(struct perf_evlist *evlist)
 {
        const char *default_sort_orders[] = {
                default_sort_order,
@@ -1675,14 +2196,33 @@ static const char *get_default_sort_order(void)
                default_mem_sort_order,
                default_top_sort_order,
                default_diff_sort_order,
+               default_tracepoint_sort_order,
        };
+       bool use_trace = true;
+       struct perf_evsel *evsel;
 
        BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
 
+       if (evlist == NULL)
+               goto out_no_evlist;
+
+       evlist__for_each(evlist, evsel) {
+               if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
+                       use_trace = false;
+                       break;
+               }
+       }
+
+       if (use_trace) {
+               sort__mode = SORT_MODE__TRACEPOINT;
+               if (symbol_conf.raw_trace)
+                       return "trace_fields";
+       }
+out_no_evlist:
        return default_sort_orders[sort__mode];
 }
 
-static int setup_sort_order(void)
+static int setup_sort_order(struct perf_evlist *evlist)
 {
        char *new_sort_order;
 
@@ -1703,7 +2243,7 @@ static int setup_sort_order(void)
         * because it's checked over the rest of the code.
         */
        if (asprintf(&new_sort_order, "%s,%s",
-                    get_default_sort_order(), sort_order + 1) < 0) {
+                    get_default_sort_order(evlist), sort_order + 1) < 0) {
                error("Not enough memory to set up --sort");
                return -ENOMEM;
        }
@@ -1712,13 +2252,41 @@ static int setup_sort_order(void)
        return 0;
 }
 
-static int __setup_sorting(void)
+/*
+ * Adds 'pre,' prefix into 'str' is 'pre' is
+ * not already part of 'str'.
+ */
+static char *prefix_if_not_in(const char *pre, char *str)
+{
+       char *n;
+
+       if (!str || strstr(str, pre))
+               return str;
+
+       if (asprintf(&n, "%s,%s", pre, str) < 0)
+               return NULL;
+
+       free(str);
+       return n;
+}
+
+static char *setup_overhead(char *keys)
+{
+       keys = prefix_if_not_in("overhead", keys);
+
+       if (symbol_conf.cumulate_callchain)
+               keys = prefix_if_not_in("overhead_children", keys);
+
+       return keys;
+}
+
+static int __setup_sorting(struct perf_evlist *evlist)
 {
        char *tmp, *tok, *str;
        const char *sort_keys;
        int ret = 0;
 
-       ret = setup_sort_order();
+       ret = setup_sort_order(evlist);
        if (ret)
                return ret;
 
@@ -1732,7 +2300,7 @@ static int __setup_sorting(void)
                        return 0;
                }
 
-               sort_keys = get_default_sort_order();
+               sort_keys = get_default_sort_order(evlist);
        }
 
        str = strdup(sort_keys);
@@ -1741,9 +2309,20 @@ static int __setup_sorting(void)
                return -ENOMEM;
        }
 
+       /*
+        * Prepend overhead fields for backward compatibility.
+        */
+       if (!is_strict_order(field_order)) {
+               str = setup_overhead(str);
+               if (str == NULL) {
+                       error("Not enough memory to setup overhead keys");
+                       return -ENOMEM;
+               }
+       }
+
        for (tok = strtok_r(str, ", ", &tmp);
                        tok; tok = strtok_r(NULL, ", ", &tmp)) {
-               ret = sort_dimension__add(tok);
+               ret = sort_dimension__add(tok, evlist);
                if (ret == -EINVAL) {
                        error("Invalid --sort key: `%s'", tok);
                        break;
@@ -1954,16 +2533,16 @@ out:
        return ret;
 }
 
-int setup_sorting(void)
+int setup_sorting(struct perf_evlist *evlist)
 {
        int err;
 
-       err = __setup_sorting();
+       err = __setup_sorting(evlist);
        if (err < 0)
                return err;
 
        if (parent_pattern != default_parent_pattern) {
-               err = sort_dimension__add("parent");
+               err = sort_dimension__add("parent", evlist);
                if (err < 0)
                        return err;
        }
index 31228851e397770d6b7567be00e7feb27435c8c0..687bbb1244281ba65a99c3cb78f5bcb8a1eaa41b 100644 (file)
@@ -18,7 +18,7 @@
 #include "debug.h"
 #include "header.h"
 
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
 #include "parse-events.h"
 #include "hist.h"
 #include "thread.h"
@@ -122,6 +122,9 @@ struct hist_entry {
        struct branch_info      *branch_info;
        struct hists            *hists;
        struct mem_info         *mem_info;
+       void                    *raw_data;
+       u32                     raw_size;
+       void                    *trace_output;
        struct callchain_root   callchain[0]; /* must be last member */
 };
 
@@ -164,6 +167,7 @@ enum sort_mode {
        SORT_MODE__MEMORY,
        SORT_MODE__TOP,
        SORT_MODE__DIFF,
+       SORT_MODE__TRACEPOINT,
 };
 
 enum sort_type {
@@ -180,6 +184,7 @@ enum sort_type {
        SORT_LOCAL_WEIGHT,
        SORT_GLOBAL_WEIGHT,
        SORT_TRANSACTION,
+       SORT_TRACE,
 
        /* branch stack specific sort keys */
        __SORT_BRANCH_STACK,
@@ -209,8 +214,6 @@ enum sort_type {
  */
 
 struct sort_entry {
-       struct list_head list;
-
        const char *se_header;
 
        int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *);
@@ -224,10 +227,11 @@ struct sort_entry {
 extern struct sort_entry sort_thread;
 extern struct list_head hist_entry__sort_list;
 
-int setup_sorting(void);
+struct perf_evlist;
+struct pevent;
+int setup_sorting(struct perf_evlist *evlist);
 int setup_output_field(void);
 void reset_output_field(void);
-extern int sort_dimension__add(const char *);
 void sort__setup_elide(FILE *fp);
 void perf_hpp__set_elide(int idx, bool elide);
 
index 2d9d8306dbd3f97f3d1f9734ace17b25d9ed583a..2f901d15e06370d26d579869d351811f4d31f940 100644 (file)
@@ -341,3 +341,65 @@ int perf_stat_process_counter(struct perf_stat_config *config,
 
        return 0;
 }
+
+int perf_event__process_stat_event(struct perf_tool *tool __maybe_unused,
+                                  union perf_event *event,
+                                  struct perf_session *session)
+{
+       struct perf_counts_values count;
+       struct stat_event *st = &event->stat;
+       struct perf_evsel *counter;
+
+       count.val = st->val;
+       count.ena = st->ena;
+       count.run = st->run;
+
+       counter = perf_evlist__id2evsel(session->evlist, st->id);
+       if (!counter) {
+               pr_err("Failed to resolve counter for stat event.\n");
+               return -EINVAL;
+       }
+
+       *perf_counts(counter->counts, st->cpu, st->thread) = count;
+       counter->supported = true;
+       return 0;
+}
+
+size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp)
+{
+       struct stat_event *st = (struct stat_event *) event;
+       size_t ret;
+
+       ret  = fprintf(fp, "\n... id %" PRIu64 ", cpu %d, thread %d\n",
+                      st->id, st->cpu, st->thread);
+       ret += fprintf(fp, "... value %" PRIu64 ", enabled %" PRIu64 ", running %" PRIu64 "\n",
+                      st->val, st->ena, st->run);
+
+       return ret;
+}
+
+size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp)
+{
+       struct stat_round_event *rd = (struct stat_round_event *)event;
+       size_t ret;
+
+       ret = fprintf(fp, "\n... time %" PRIu64 ", type %s\n", rd->time,
+                     rd->type == PERF_STAT_ROUND_TYPE__FINAL ? "FINAL" : "INTERVAL");
+
+       return ret;
+}
+
+size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp)
+{
+       struct perf_stat_config sc;
+       size_t ret;
+
+       perf_event__read_stat_config(&sc, &event->stat_config);
+
+       ret  = fprintf(fp, "\n");
+       ret += fprintf(fp, "... aggr_mode %d\n", sc.aggr_mode);
+       ret += fprintf(fp, "... scale     %d\n", sc.scale);
+       ret += fprintf(fp, "... interval  %u\n", sc.interval);
+
+       return ret;
+}
index da1d11c4f8c193cff476fec76868277b12f7c623..086f4e128d6351f0e0de862c2ebcc44801cbc2f8 100644 (file)
@@ -90,4 +90,14 @@ void perf_evlist__reset_stats(struct perf_evlist *evlist);
 
 int perf_stat_process_counter(struct perf_stat_config *config,
                              struct perf_evsel *counter);
+struct perf_tool;
+union perf_event;
+struct perf_session;
+int perf_event__process_stat_event(struct perf_tool *tool,
+                                  union perf_event *event,
+                                  struct perf_session *session);
+
+size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp);
+size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp);
+size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp);
 #endif
index fc8781de62dbbed618e1f220225dfaeb195ef7f0..7f7e072be746f5985eb3c9ae5e84ad3ce9115b61 100644 (file)
@@ -342,22 +342,6 @@ char *rtrim(char *s)
        return s;
 }
 
-/**
- * memdup - duplicate region of memory
- * @src: memory region to duplicate
- * @len: memory region length
- */
-void *memdup(const void *src, size_t len)
-{
-       void *p;
-
-       p = malloc(len);
-       if (p)
-               memcpy(p, src, len);
-
-       return p;
-}
-
 char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints)
 {
        /*
index 475d88d0a1c9a772323b3218cfcf5f5900c0e809..562b8ebeae5b2414b6bac867c928cb22ee9a5f13 100644 (file)
@@ -1026,8 +1026,8 @@ int dso__load_sym(struct dso *dso, struct map *map,
                                curr_dso->long_name_len = dso->long_name_len;
                                curr_map = map__new2(start, curr_dso,
                                                     map->type);
+                               dso__put(curr_dso);
                                if (curr_map == NULL) {
-                                       dso__put(curr_dso);
                                        goto out_elf_end;
                                }
                                if (adjust_kernel_syms) {
@@ -1042,7 +1042,14 @@ int dso__load_sym(struct dso *dso, struct map *map,
                                }
                                curr_dso->symtab_type = dso->symtab_type;
                                map_groups__insert(kmaps, curr_map);
+                               /*
+                                * Add it before we drop the referece to curr_map,
+                                * i.e. while we still are sure to have a reference
+                                * to this DSO via curr_map->dso.
+                                */
                                dsos__add(&map->groups->machine->dsos, curr_dso);
+                               /* kmaps already got it */
+                               map__put(curr_map);
                                dso__set_loaded(curr_dso, map->type);
                        } else
                                curr_dso = curr_map->dso;
index cd08027a6d2cdb9640734a5ba8eb20ade14f57f2..3b2de6eb33763b0ab1a23195529fda8d6367eb1d 100644 (file)
@@ -39,6 +39,7 @@ struct symbol_conf symbol_conf = {
        .cumulate_callchain     = true,
        .show_hist_headers      = true,
        .symfs                  = "",
+       .event_group            = true,
 };
 
 static enum dso_binary_type binary_type_symtab[] = {
@@ -1860,24 +1861,44 @@ static void vmlinux_path__exit(void)
        zfree(&vmlinux_path);
 }
 
+static const char * const vmlinux_paths[] = {
+       "vmlinux",
+       "/boot/vmlinux"
+};
+
+static const char * const vmlinux_paths_upd[] = {
+       "/boot/vmlinux-%s",
+       "/usr/lib/debug/boot/vmlinux-%s",
+       "/lib/modules/%s/build/vmlinux",
+       "/usr/lib/debug/lib/modules/%s/vmlinux",
+       "/usr/lib/debug/boot/vmlinux-%s.debug"
+};
+
+static int vmlinux_path__add(const char *new_entry)
+{
+       vmlinux_path[vmlinux_path__nr_entries] = strdup(new_entry);
+       if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
+               return -1;
+       ++vmlinux_path__nr_entries;
+
+       return 0;
+}
+
 static int vmlinux_path__init(struct perf_env *env)
 {
        struct utsname uts;
        char bf[PATH_MAX];
        char *kernel_version;
+       unsigned int i;
 
-       vmlinux_path = malloc(sizeof(char *) * 6);
+       vmlinux_path = malloc(sizeof(char *) * (ARRAY_SIZE(vmlinux_paths) +
+                             ARRAY_SIZE(vmlinux_paths_upd)));
        if (vmlinux_path == NULL)
                return -1;
 
-       vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
-       if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
-               goto out_fail;
-       ++vmlinux_path__nr_entries;
-       vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
-       if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
-               goto out_fail;
-       ++vmlinux_path__nr_entries;
+       for (i = 0; i < ARRAY_SIZE(vmlinux_paths); i++)
+               if (vmlinux_path__add(vmlinux_paths[i]) < 0)
+                       goto out_fail;
 
        /* only try kernel version if no symfs was given */
        if (symbol_conf.symfs[0] != 0)
@@ -1892,28 +1913,11 @@ static int vmlinux_path__init(struct perf_env *env)
                kernel_version = uts.release;
        }
 
-       snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", kernel_version);
-       vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
-       if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
-               goto out_fail;
-       ++vmlinux_path__nr_entries;
-       snprintf(bf, sizeof(bf), "/usr/lib/debug/boot/vmlinux-%s",
-                kernel_version);
-       vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
-       if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
-               goto out_fail;
-        ++vmlinux_path__nr_entries;
-       snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", kernel_version);
-       vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
-       if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
-               goto out_fail;
-       ++vmlinux_path__nr_entries;
-       snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
-                kernel_version);
-       vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
-       if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
-               goto out_fail;
-       ++vmlinux_path__nr_entries;
+       for (i = 0; i < ARRAY_SIZE(vmlinux_paths_upd); i++) {
+               snprintf(bf, sizeof(bf), vmlinux_paths_upd[i], kernel_version);
+               if (vmlinux_path__add(bf) < 0)
+                       goto out_fail;
+       }
 
        return 0;
 
index dcd786e364f2da1385c2f78803fe1770071ce609..ccd1caa40e116645be37025665388886d7c97546 100644 (file)
@@ -108,7 +108,9 @@ struct symbol_conf {
                        show_hist_headers,
                        branch_callstack,
                        has_filter,
-                       show_ref_callgraph;
+                       show_ref_callgraph,
+                       hide_unresolved,
+                       raw_trace;
        const char      *vmlinux_name,
                        *kallsyms_name,
                        *source_prefix,
diff --git a/tools/perf/util/term.c b/tools/perf/util/term.c
new file mode 100644 (file)
index 0000000..90b47d8
--- /dev/null
@@ -0,0 +1,35 @@
+#include "util.h"
+
+void get_term_dimensions(struct winsize *ws)
+{
+       char *s = getenv("LINES");
+
+       if (s != NULL) {
+               ws->ws_row = atoi(s);
+               s = getenv("COLUMNS");
+               if (s != NULL) {
+                       ws->ws_col = atoi(s);
+                       if (ws->ws_row && ws->ws_col)
+                               return;
+               }
+       }
+#ifdef TIOCGWINSZ
+       if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
+           ws->ws_row && ws->ws_col)
+               return;
+#endif
+       ws->ws_row = 25;
+       ws->ws_col = 80;
+}
+
+void set_term_quiet_input(struct termios *old)
+{
+       struct termios tc;
+
+       tcgetattr(0, old);
+       tc = *old;
+       tc.c_lflag &= ~(ICANON | ECHO);
+       tc.c_cc[VMIN] = 0;
+       tc.c_cc[VTIME] = 0;
+       tcsetattr(0, TCSANOW, &tc);
+}
diff --git a/tools/perf/util/term.h b/tools/perf/util/term.h
new file mode 100644 (file)
index 0000000..2c06a61
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __PERF_TERM_H
+#define __PERF_TERM_H
+
+struct termios;
+struct winsize;
+
+void get_term_dimensions(struct winsize *ws);
+void set_term_quiet_input(struct termios *old);
+
+#endif /* __PERF_TERM_H */
index 0a9ae8014729c085ffd2872e2bc13871f79c9908..dfd00c6dad6e68ad3dfde68cbb9e0b16a95f1fee 100644 (file)
@@ -19,8 +19,10 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)
                thread->mg = map_groups__new(machine);
        } else {
                leader = __machine__findnew_thread(machine, pid, pid);
-               if (leader)
+               if (leader) {
                        thread->mg = map_groups__get(leader->mg);
+                       thread__put(leader);
+               }
        }
 
        return thread->mg ? 0 : -1;
@@ -53,7 +55,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
                        goto err_thread;
 
                list_add(&comm->list, &thread->comm_list);
-               atomic_set(&thread->refcnt, 0);
+               atomic_set(&thread->refcnt, 1);
                RB_CLEAR_NODE(&thread->rb_node);
        }
 
@@ -95,6 +97,10 @@ struct thread *thread__get(struct thread *thread)
 void thread__put(struct thread *thread)
 {
        if (thread && atomic_dec_and_test(&thread->refcnt)) {
+               /*
+                * Remove it from the dead_threads list, as last reference
+                * is gone.
+                */
                list_del_init(&thread->node);
                thread__delete(thread);
        }
index 6ec3c5ca438f25c827dcfc1b7bde3491f8a5fe8c..08afc69099538f66172968dc3827fd9b7b40d5c2 100644 (file)
@@ -13,6 +13,7 @@
 #include "thread_map.h"
 #include "util.h"
 #include "debug.h"
+#include "event.h"
 
 /* Skip "." and ".." directories */
 static int filter(const struct dirent *dir)
@@ -304,6 +305,7 @@ out:
 
 out_free_threads:
        zfree(&threads);
+       strlist__delete(slist);
        goto out;
 }
 
@@ -408,3 +410,29 @@ void thread_map__read_comms(struct thread_map *threads)
        for (i = 0; i < threads->nr; ++i)
                comm_init(threads, i);
 }
+
+static void thread_map__copy_event(struct thread_map *threads,
+                                  struct thread_map_event *event)
+{
+       unsigned i;
+
+       threads->nr = (int) event->nr;
+
+       for (i = 0; i < event->nr; i++) {
+               thread_map__set_pid(threads, i, (pid_t) event->entries[i].pid);
+               threads->map[i].comm = strndup(event->entries[i].comm, 16);
+       }
+
+       atomic_set(&threads->refcnt, 1);
+}
+
+struct thread_map *thread_map__new_event(struct thread_map_event *event)
+{
+       struct thread_map *threads;
+
+       threads = thread_map__alloc(event->nr);
+       if (threads)
+               thread_map__copy_event(threads, event);
+
+       return threads;
+}
index af679d8a50f852ebb3457491f5dc4b96f6520743..85e4c7c4fbde1fd5455ed0fa58375aac3934b445 100644 (file)
@@ -16,11 +16,14 @@ struct thread_map {
        struct thread_map_data map[];
 };
 
+struct thread_map_event;
+
 struct thread_map *thread_map__new_dummy(void);
 struct thread_map *thread_map__new_by_pid(pid_t pid);
 struct thread_map *thread_map__new_by_tid(pid_t tid);
 struct thread_map *thread_map__new_by_uid(uid_t uid);
 struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid);
+struct thread_map *thread_map__new_event(struct thread_map_event *event);
 
 struct thread_map *thread_map__get(struct thread_map *map);
 void thread_map__put(struct thread_map *map);
index cab8cc24831bf479d3776f818c07996dad7ac57c..55de4cffcd4e9ae2ee2063dc5efc05d0d72fc7db 100644 (file)
@@ -50,12 +50,18 @@ struct perf_tool {
                        throttle,
                        unthrottle;
        event_attr_op   attr;
+       event_attr_op   event_update;
        event_op2       tracing_data;
        event_oe        finished_round;
        event_op2       build_id,
                        id_index,
                        auxtrace_info,
-                       auxtrace_error;
+                       auxtrace_error,
+                       thread_map,
+                       cpu_map,
+                       stat_config,
+                       stat,
+                       stat_round;
        event_op3       auxtrace;
        bool            ordered_events;
        bool            ordering_requires_timestamps;
index b85ee55cca0cc943c75e2ea348b932236ff0618f..bce5b1dac26827735e538d737e9417555f3c3e2b 100644 (file)
@@ -65,6 +65,7 @@ int tracing_data_put(struct tracing_data *tdata);
 struct addr_location;
 
 struct perf_session;
+struct perf_stat_config;
 
 struct scripting_ops {
        const char *name;
@@ -75,6 +76,9 @@ struct scripting_ops {
                               struct perf_sample *sample,
                               struct perf_evsel *evsel,
                               struct addr_location *al);
+       void (*process_stat)(struct perf_stat_config *config,
+                            struct perf_evsel *evsel, u64 tstamp);
+       void (*process_stat_interval)(u64 tstamp);
        int (*generate_script) (struct pevent *pevent, const char *outfile);
 };
 
index 2dcfe9a7c8d085b62d66acd574930ea2e5f327a7..cf5e250bc78e1a4c82a08fc2ea50d5876bec1c69 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/types.h>
 #include "event.h"
 #include "perf_regs.h"
+#include "callchain.h"
 
 static char *debuginfo_path;
 
@@ -52,25 +53,28 @@ static int report_module(u64 ip, struct unwind_info *ui)
        return __report_module(&al, ip, ui);
 }
 
+/*
+ * Store all entries within entries array,
+ * we will process it after we finish unwind.
+ */
 static int entry(u64 ip, struct unwind_info *ui)
 
 {
-       struct unwind_entry e;
+       struct unwind_entry *e = &ui->entries[ui->idx++];
        struct addr_location al;
 
        if (__report_module(&al, ip, ui))
                return -1;
 
-       e.ip  = ip;
-       e.map = al.map;
-       e.sym = al.sym;
+       e->ip  = ip;
+       e->map = al.map;
+       e->sym = al.sym;
 
        pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
                 al.sym ? al.sym->name : "''",
                 ip,
                 al.map ? al.map->map_ip(al.map, ip) : (u64) 0);
-
-       return ui->cb(&e, ui->arg);
+       return 0;
 }
 
 static pid_t next_thread(Dwfl *dwfl, void *arg, void **thread_argp)
@@ -91,6 +95,16 @@ static int access_dso_mem(struct unwind_info *ui, Dwarf_Addr addr,
 
        thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
                              MAP__FUNCTION, addr, &al);
+       if (!al.map) {
+               /*
+                * We've seen cases (softice) where DWARF unwinder went
+                * through non executable mmaps, which we need to lookup
+                * in MAP__VARIABLE tree.
+                */
+               thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
+                                     MAP__VARIABLE, addr, &al);
+       }
+
        if (!al.map) {
                pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
                return -1;
@@ -168,7 +182,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
                        struct perf_sample *data,
                        int max_stack)
 {
-       struct unwind_info ui = {
+       struct unwind_info *ui, ui_buf = {
                .sample         = data,
                .thread         = thread,
                .machine        = thread->mg->machine,
@@ -177,35 +191,54 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
                .max_stack      = max_stack,
        };
        Dwarf_Word ip;
-       int err = -EINVAL;
+       int err = -EINVAL, i;
 
        if (!data->user_regs.regs)
                return -EINVAL;
 
-       ui.dwfl = dwfl_begin(&offline_callbacks);
-       if (!ui.dwfl)
+       ui = zalloc(sizeof(ui_buf) + sizeof(ui_buf.entries[0]) * max_stack);
+       if (!ui)
+               return -ENOMEM;
+
+       *ui = ui_buf;
+
+       ui->dwfl = dwfl_begin(&offline_callbacks);
+       if (!ui->dwfl)
                goto out;
 
        err = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP);
        if (err)
                goto out;
 
-       err = report_module(ip, &ui);
+       err = report_module(ip, ui);
        if (err)
                goto out;
 
-       if (!dwfl_attach_state(ui.dwfl, EM_NONE, thread->tid, &callbacks, &ui))
+       if (!dwfl_attach_state(ui->dwfl, EM_NONE, thread->tid, &callbacks, ui))
                goto out;
 
-       err = dwfl_getthread_frames(ui.dwfl, thread->tid, frame_callback, &ui);
+       err = dwfl_getthread_frames(ui->dwfl, thread->tid, frame_callback, ui);
 
-       if (err && !ui.max_stack)
+       if (err && !ui->max_stack)
                err = 0;
 
+       /*
+        * Display what we got based on the order setup.
+        */
+       for (i = 0; i < ui->idx && !err; i++) {
+               int j = i;
+
+               if (callchain_param.order == ORDER_CALLER)
+                       j = ui->idx - i - 1;
+
+               err = ui->entries[j].ip ? ui->cb(&ui->entries[j], ui->arg) : 0;
+       }
+
  out:
        if (err)
                pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1));
 
-       dwfl_end(ui.dwfl);
+       dwfl_end(ui->dwfl);
+       free(ui);
        return 0;
 }
index 417a1426f3adb36072226eb7ea9d157b7a19ae37..58328669ed16a7af3b475bb569b73310a48678df 100644 (file)
@@ -16,6 +16,8 @@ struct unwind_info {
        unwind_entry_cb_t       cb;
        void                    *arg;
        int                     max_stack;
+       int                     idx;
+       struct unwind_entry     entries[];
 };
 
 #endif /* __PERF_UNWIND_LIBDW_H */
index c83832b555e580a771c1a831e1d18b3b5df135ac..ee7e372297e59adb7eb3c7a1ffec8acb6186f704 100644 (file)
@@ -319,6 +319,15 @@ static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
 
        thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
                              MAP__FUNCTION, ip, &al);
+       if (!al.map) {
+               /*
+                * We've seen cases (softice) where DWARF unwinder went
+                * through non executable mmaps, which we need to lookup
+                * in MAP__VARIABLE tree.
+                */
+               thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
+                                     MAP__VARIABLE, ip, &al);
+       }
        return al.map;
 }
 
@@ -416,20 +425,19 @@ get_proc_name(unw_addr_space_t __maybe_unused as,
 static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
                          unw_word_t *data)
 {
-       struct addr_location al;
+       struct map *map;
        ssize_t size;
 
-       thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
-                             MAP__FUNCTION, addr, &al);
-       if (!al.map) {
+       map = find_map(addr, ui);
+       if (!map) {
                pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
                return -1;
        }
 
-       if (!al.map->dso)
+       if (!map->dso)
                return -1;
 
-       size = dso__data_read_addr(al.map->dso, al.map, ui->machine,
+       size = dso__data_read_addr(map->dso, map, ui->machine,
                                   addr, (u8 *) data, sizeof(*data));
 
        return !(size == sizeof(*data));
@@ -614,23 +622,48 @@ void unwind__finish_access(struct thread *thread)
 static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
                       void *arg, int max_stack)
 {
+       u64 val;
+       unw_word_t ips[max_stack];
        unw_addr_space_t addr_space;
        unw_cursor_t c;
-       int ret;
-
-       addr_space = thread__priv(ui->thread);
-       if (addr_space == NULL)
-               return -1;
+       int ret, i = 0;
 
-       ret = unw_init_remote(&c, addr_space, ui);
+       ret = perf_reg_value(&val, &ui->sample->user_regs, PERF_REG_IP);
        if (ret)
-               display_error(ret);
+               return ret;
 
-       while (!ret && (unw_step(&c) > 0) && max_stack--) {
-               unw_word_t ip;
+       ips[i++] = (unw_word_t) val;
 
-               unw_get_reg(&c, UNW_REG_IP, &ip);
-               ret = ip ? entry(ip, ui->thread, cb, arg) : 0;
+       /*
+        * If we need more than one entry, do the DWARF
+        * unwind itself.
+        */
+       if (max_stack - 1 > 0) {
+               addr_space = thread__priv(ui->thread);
+               if (addr_space == NULL)
+                       return -1;
+
+               ret = unw_init_remote(&c, addr_space, ui);
+               if (ret)
+                       display_error(ret);
+
+               while (!ret && (unw_step(&c) > 0) && i < max_stack) {
+                       unw_get_reg(&c, UNW_REG_IP, &ips[i]);
+                       ++i;
+               }
+
+               max_stack = i;
+       }
+
+       /*
+        * Display what we got based on the order setup.
+        */
+       for (i = 0; i < max_stack && !ret; i++) {
+               int j = i;
+
+               if (callchain_param.order == ORDER_CALLER)
+                       j = max_stack - i - 1;
+               ret = ips[j] ? entry(ips[j], ui->thread, cb, arg) : 0;
        }
 
        return ret;
@@ -640,24 +673,17 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
                        struct thread *thread,
                        struct perf_sample *data, int max_stack)
 {
-       u64 ip;
        struct unwind_info ui = {
                .sample       = data,
                .thread       = thread,
                .machine      = thread->mg->machine,
        };
-       int ret;
 
        if (!data->user_regs.regs)
                return -EINVAL;
 
-       ret = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP);
-       if (ret)
-               return ret;
-
-       ret = entry(ip, thread, cb, arg);
-       if (ret)
-               return -ENOMEM;
+       if (max_stack <= 0)
+               return -EINVAL;
 
-       return --max_stack > 0 ? get_entries(&ui, cb, arg, max_stack) : 0;
+       return get_entries(&ui, cb, arg, max_stack);
 }
index 47b1e36c7ea0c948b0fc9cd247c4a29cf61464a8..88b8f8d21f58e6fb7c2143788528ff764b06f012 100644 (file)
 #include <linux/kernel.h>
 #include <unistd.h>
 #include "callchain.h"
+#include "strlist.h"
+#include <subcmd/exec-cmd.h>
 
 struct callchain_param callchain_param = {
        .mode   = CHAIN_GRAPH_ABS,
        .min_percent = 0.5,
        .order  = ORDER_CALLEE,
-       .key    = CCKEY_FUNCTION
+       .key    = CCKEY_FUNCTION,
+       .value  = CCVAL_PERCENT,
 };
 
 /*
@@ -351,41 +354,8 @@ void sighandler_dump_stack(int sig)
 {
        psignal(sig, "perf");
        dump_stack();
-       exit(sig);
-}
-
-void get_term_dimensions(struct winsize *ws)
-{
-       char *s = getenv("LINES");
-
-       if (s != NULL) {
-               ws->ws_row = atoi(s);
-               s = getenv("COLUMNS");
-               if (s != NULL) {
-                       ws->ws_col = atoi(s);
-                       if (ws->ws_row && ws->ws_col)
-                               return;
-               }
-       }
-#ifdef TIOCGWINSZ
-       if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
-           ws->ws_row && ws->ws_col)
-               return;
-#endif
-       ws->ws_row = 25;
-       ws->ws_col = 80;
-}
-
-void set_term_quiet_input(struct termios *old)
-{
-       struct termios tc;
-
-       tcgetattr(0, old);
-       tc = *old;
-       tc.c_lflag &= ~(ICANON | ECHO);
-       tc.c_cc[VMIN] = 0;
-       tc.c_cc[VTIME] = 0;
-       tcsetattr(0, TCSANOW, &tc);
+       signal(sig, SIG_DFL);
+       raise(sig);
 }
 
 int parse_nsec_time(const char *str, u64 *ptime)
@@ -695,3 +665,28 @@ fetch_kernel_version(unsigned int *puint, char *str,
                *puint = (version << 16) + (patchlevel << 8) + sublevel;
        return 0;
 }
+
+const char *perf_tip(const char *dirpath)
+{
+       struct strlist *tips;
+       struct str_node *node;
+       char *tip = NULL;
+       struct strlist_config conf = {
+               .dirname = system_path(dirpath) ,
+       };
+
+       tips = strlist__new("tips.txt", &conf);
+       if (tips == NULL || strlist__nr_entries(tips) == 1) {
+               tip = (char *)"Cannot find tips.txt file";
+               goto out;
+       }
+
+       node = strlist__entry(tips, random() % strlist__nr_entries(tips));
+       if (asprintf(&tip, "Tip: %s", node->s) < 0)
+               tip = (char *)"Tip: get more memory! ;-)";
+
+out:
+       strlist__delete(tips);
+
+       return tip;
+}
index dcc659017976da2a90ae67e51b922bcb7bb99a51..fe915e616f9b65388e15be963d0ef5cf58c325fd 100644 (file)
@@ -53,6 +53,7 @@
 #include <stdlib.h>
 #include <stdarg.h>
 #include <string.h>
+#include <term.h>
 #include <errno.h>
 #include <limits.h>
 #include <sys/param.h>
@@ -150,12 +151,6 @@ extern void set_warning_routine(void (*routine)(const char *err, va_list params)
 extern int prefixcmp(const char *str, const char *prefix);
 extern void set_buildid_dir(const char *dir);
 
-static inline const char *skip_prefix(const char *str, const char *prefix)
-{
-       size_t len = strlen(prefix);
-       return strncmp(str, prefix, len) ? NULL : str + len;
-}
-
 #ifdef __GLIBC_PREREQ
 #if __GLIBC_PREREQ(2, 1)
 #define HAVE_STRCHRNUL
@@ -186,14 +181,6 @@ static inline void *zalloc(size_t size)
 
 #define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
 
-static inline int has_extension(const char *filename, const char *ext)
-{
-       size_t len = strlen(filename);
-       size_t extlen = strlen(ext);
-
-       return len > extlen && !memcmp(filename + len - extlen, ext, extlen);
-}
-
 /* Sane ctype - no locale, and works with signed chars */
 #undef isascii
 #undef isspace
@@ -282,9 +269,6 @@ void sighandler_dump_stack(int sig);
 extern unsigned int page_size;
 extern int cacheline_size;
 
-void get_term_dimensions(struct winsize *ws);
-void set_term_quiet_input(struct termios *old);
-
 struct parse_tag {
        char tag;
        int mult;
@@ -358,4 +342,6 @@ int fetch_kernel_version(unsigned int *puint,
 #define KVER_FMT       "%d.%d.%d"
 #define KVER_PARAM(x)  KVER_VERSION(x), KVER_PATCHLEVEL(x), KVER_SUBLEVEL(x)
 
+const char *perf_tip(const char *dirpath);
+
 #endif /* GIT_COMPAT_UTIL_H */
index 5236e073919d2e508e6073d201fa157670a8688e..0f80eefb0bfd5a0cef6796f9f7f0fce60b3797c3 100755 (executable)
@@ -38,8 +38,6 @@
 #
 # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
 
-grace=120
-
 T=/tmp/kvm-test-1-run.sh.$$
 trap 'rm -rf $T' 0
 touch $T
@@ -152,7 +150,7 @@ fi
 qemu_args="`specify_qemu_cpus "$QEMU" "$qemu_args" "$cpu_count"`"
 
 # Generate architecture-specific and interaction-specific qemu arguments
-qemu_args="$qemu_args `identify_qemu_args "$QEMU" "$builddir/console.log"`"
+qemu_args="$qemu_args `identify_qemu_args "$QEMU" "$resdir/console.log"`"
 
 # Generate qemu -append arguments
 qemu_append="`identify_qemu_append "$QEMU"`"
@@ -168,7 +166,7 @@ then
        touch $resdir/buildonly
        exit 0
 fi
-echo "NOTE: $QEMU either did not run or was interactive" > $builddir/console.log
+echo "NOTE: $QEMU either did not run or was interactive" > $resdir/console.log
 echo $QEMU $qemu_args -m 512 -kernel $resdir/bzImage -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd
 ( $QEMU $qemu_args -m 512 -kernel $resdir/bzImage -append "$qemu_append $boot_args"; echo $? > $resdir/qemu-retval ) &
 qemu_pid=$!
@@ -214,7 +212,7 @@ then
                else
                        break
                fi
-               if test $kruntime -ge $((seconds + grace))
+               if test $kruntime -ge $((seconds + $TORTURE_SHUTDOWN_GRACE))
                then
                        echo "!!! PID $qemu_pid hung at $kruntime vs. $seconds seconds" >> $resdir/Warnings 2>&1
                        kill -KILL $qemu_pid
@@ -224,6 +222,5 @@ then
        done
 fi
 
-cp $builddir/console.log $resdir
 parse-torture.sh $resdir/console.log $title
 parse-console.sh $resdir/console.log $title
index f6483609ebc246f38d268dc97a9ddfa4072cbf7b..4a431767f77a0215096d3cc5421439a857175783 100755 (executable)
@@ -42,6 +42,7 @@ TORTURE_DEFCONFIG=defconfig
 TORTURE_BOOT_IMAGE=""
 TORTURE_INITRD="$KVM/initrd"; export TORTURE_INITRD
 TORTURE_KMAKE_ARG=""
+TORTURE_SHUTDOWN_GRACE=180
 TORTURE_SUITE=rcu
 resdir=""
 configs=""
@@ -149,6 +150,11 @@ do
                resdir=$2
                shift
                ;;
+       --shutdown-grace)
+               checkarg --shutdown-grace "(seconds)" "$#" "$2" '^[0-9]*$' '^error'
+               TORTURE_SHUTDOWN_GRACE=$2
+               shift
+               ;;
        --torture)
                checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\)$' '^--'
                TORTURE_SUITE=$2
@@ -266,6 +272,7 @@ TORTURE_KMAKE_ARG="$TORTURE_KMAKE_ARG"; export TORTURE_KMAKE_ARG
 TORTURE_QEMU_CMD="$TORTURE_QEMU_CMD"; export TORTURE_QEMU_CMD
 TORTURE_QEMU_INTERACTIVE="$TORTURE_QEMU_INTERACTIVE"; export TORTURE_QEMU_INTERACTIVE
 TORTURE_QEMU_MAC="$TORTURE_QEMU_MAC"; export TORTURE_QEMU_MAC
+TORTURE_SHUTDOWN_GRACE="$TORTURE_SHUTDOWN_GRACE"; export TORTURE_SHUTDOWN_GRACE
 TORTURE_SUITE="$TORTURE_SUITE"; export TORTURE_SUITE
 if ! test -e $resdir
 then
@@ -307,10 +314,10 @@ awk < $T/cfgcpu.pack \
 }
 
 # Dump out the scripting required to run one test batch.
-function dump(first, pastlast)
+function dump(first, pastlast, batchnum)
 {
-       print "echo ----Start batch: `date`";
-       print "echo ----Start batch: `date` >> " rd "/log";
+       print "echo ----Start batch " batchnum ": `date`";
+       print "echo ----Start batch " batchnum ": `date` >> " rd "/log";
        jn=1
        for (j = first; j < pastlast; j++) {
                builddir=KVM "/b" jn
@@ -371,25 +378,28 @@ END {
        njobs = i;
        nc = ncpus;
        first = 0;
+       batchnum = 1;
 
        # Each pass through the following loop considers one test.
        for (i = 0; i < njobs; i++) {
                if (ncpus == 0) {
                        # Sequential test specified, each test its own batch.
-                       dump(i, i + 1);
+                       dump(i, i + 1, batchnum);
                        first = i;
+                       batchnum++;
                } else if (nc < cpus[i] && i != 0) {
                        # Out of CPUs, dump out a batch.
-                       dump(first, i);
+                       dump(first, i, batchnum);
                        first = i;
                        nc = ncpus;
+                       batchnum++;
                }
                # Account for the CPUs needed by the current test.
                nc -= cpus[i];
        }
        # Dump the last batch.
        if (ncpus != 0)
-               dump(first, i);
+               dump(first, i, batchnum);
 }' >> $T/script
 
 cat << ___EOF___ >> $T/script
index d8f35cf116be2ca6fb5095caec9ef25daa90e2ac..844787a0d7bed618511a022f09700f8738018c11 100755 (executable)
@@ -24,9 +24,6 @@
 #
 # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
 
-T=/tmp/abat-chk-badness.sh.$$
-trap 'rm -f $T' 0
-
 file="$1"
 title="$2"
 
@@ -36,9 +33,41 @@ if grep -Pq '\x00' < $file
 then
        print_warning Console output contains nul bytes, old qemu still running?
 fi
-egrep 'Badness|WARNING:|Warn|BUG|===========|Call Trace:|Oops:|Stall ended before state dump start' < $file | grep -v 'ODEBUG: ' | grep -v 'Warning: unable to open an initial console' > $T
-if test -s $T
+egrep 'Badness|WARNING:|Warn|BUG|===========|Call Trace:|Oops:|detected stalls on CPUs/tasks:|Stall ended before state dump start' < $file | grep -v 'ODEBUG: ' | grep -v 'Warning: unable to open an initial console' > $1.diags
+if test -s $1.diags
 then
        print_warning Assertion failure in $file $title
-       cat $T
+       # cat $1.diags
+       summary=""
+       n_badness=`grep -c Badness $1`
+       if test "$n_badness" -ne 0
+       then
+               summary="$summary  Badness: $n_badness"
+       fi
+       n_warn=`grep -v 'Warning: unable to open an initial console' $1 | egrep -c 'WARNING:|Warn'`
+       if test "$n_warn" -ne 0
+       then
+               summary="$summary  Warnings: $n_warn"
+       fi
+       n_bugs=`egrep -c 'BUG|Oops:' $1`
+       if test "$n_bugs" -ne 0
+       then
+               summary="$summary  Bugs: $n_bugs"
+       fi
+       n_calltrace=`grep -c 'Call Trace:' $1`
+       if test "$n_calltrace" -ne 0
+       then
+               summary="$summary  Call Traces: $n_calltrace"
+       fi
+       n_lockdep=`grep -c =========== $1`
+       if test "$n_badness" -ne 0
+       then
+               summary="$summary  lockdep: $n_badness"
+       fi
+       n_stalls=`egrep -c 'detected stalls on CPUs/tasks:|Stall ended before state dump start' $1`
+       if test "$n_stalls" -ne 0
+       then
+               summary="$summary  Stalls: $n_stalls"
+       fi
+       print_warning Summary: $summary
 fi
index 9ef33a743b733339ec104c10f0caadfb47035794..24396ae8355b46bdab31edecdc55819c089ddafc 100644 (file)
@@ -20,7 +20,6 @@ CONFIG_PROVE_RCU
 
 CONFIG_NO_HZ_FULL_SYSIDLE
 CONFIG_RCU_NOCB_CPU
-CONFIG_RCU_USER_QS
 
        Meaningless for TINY_RCU.
 
index 657f3a0354883aff2f00908f2760b035f572371a..4e2b1893d40d0d8e11c47ac6400fdc8a9c707962 100644 (file)
@@ -72,10 +72,6 @@ CONFIG_RCU_TORTURE_TEST_RUNNABLE
 
        Always used in KVM testing.
 
-CONFIG_RCU_USER_QS
-
-       Redundant with CONFIG_NO_HZ_FULL.
-
 CONFIG_PREEMPT_RCU
 CONFIG_TREE_RCU
 
index 627ec7425f78e1d235bd4561121ffe46bd12c362..fd88e3025bedc17d44c1537b8279aa6068d3ff47 100644 (file)
@@ -97,7 +97,7 @@ int get_cur_clocksource(char *buf, size_t size)
 int change_clocksource(char *clocksource)
 {
        int fd;
-       size_t size;
+       ssize_t size;
 
        fd = open("/sys/devices/system/clocksource/clocksource0/current_clocksource", O_WRONLY);
 
index 487d6357b7e75039ff914077eb11d890f938e51d..453eafd4dd6e5fa3f48b458e2fd62df0792c3554 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_arm.h>
+#include <asm/kvm_asm.h>
 #include <asm/kvm_mmu.h>
 
 /* These are for GICv2 emulation only */
 #define GICH_LR_PHYSID_CPUID           (7UL << GICH_LR_PHYSID_CPUID_SHIFT)
 #define ICH_LR_VIRTUALID_MASK          (BIT_ULL(32) - 1)
 
-/*
- * LRs are stored in reverse order in memory. make sure we index them
- * correctly.
- */
-#define LR_INDEX(lr)                   (VGIC_V3_MAX_LRS - 1 - lr)
-
 static u32 ich_vtr_el2;
 
 static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr)
 {
        struct vgic_lr lr_desc;
-       u64 val = vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)];
+       u64 val = vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[VGIC_V3_LR_INDEX(lr)];
 
        if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
                lr_desc.irq = val & ICH_LR_VIRTUALID_MASK;
@@ -111,7 +106,7 @@ static void vgic_v3_set_lr(struct kvm_vcpu *vcpu, int lr,
                lr_val |= ((u64)lr_desc.hwirq) << ICH_LR_PHYS_ID_SHIFT;
        }
 
-       vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)] = lr_val;
+       vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[VGIC_V3_LR_INDEX(lr)] = lr_val;
 
        if (!(lr_desc.state & LR_STATE_MASK))
                vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr |= (1U << lr);
index 7a2f449bd85d02d7f6571fa4f5b3091df81a04d9..043032c6a5a4dc6944c5b2bc6277ad6398decd23 100644 (file)
@@ -878,7 +878,7 @@ static int vgic_handle_mmio_write(struct kvm_vcpu *vcpu,
                                       true);
 }
 
-struct kvm_io_device_ops vgic_io_ops = {
+static struct kvm_io_device_ops vgic_io_ops = {
        .read   = vgic_handle_mmio_read,
        .write  = vgic_handle_mmio_write,
 };
index 77d42be6970ed88cd5812ecea855db267a333468..35315992245600a418874fd371e641ef336a0a22 100644 (file)
@@ -57,8 +57,7 @@ int kvm_async_pf_init(void)
 
 void kvm_async_pf_deinit(void)
 {
-       if (async_pf_cache)
-               kmem_cache_destroy(async_pf_cache);
+       kmem_cache_destroy(async_pf_cache);
        async_pf_cache = NULL;
 }
 
index f0b08a2a48ba3ff2486dc84180c709d0deacfe55..fe84e1a95dd55ed1ba346d19666c3fcf26261cc5 100644 (file)
@@ -166,6 +166,10 @@ out:
        return r;
 }
 
+void __attribute__((weak)) kvm_arch_irq_routing_update(struct kvm *kvm)
+{
+}
+
 int kvm_set_irq_routing(struct kvm *kvm,
                        const struct kvm_irq_routing_entry *ue,
                        unsigned nr,
@@ -219,9 +223,10 @@ int kvm_set_irq_routing(struct kvm *kvm,
        old = kvm->irq_routing;
        rcu_assign_pointer(kvm->irq_routing, new);
        kvm_irq_routing_update(kvm);
+       kvm_arch_irq_routing_update(kvm);
        mutex_unlock(&kvm->irq_lock);
 
-       kvm_arch_irq_routing_update(kvm);
+       kvm_arch_post_irq_routing_update(kvm);
 
        synchronize_srcu_expedited(&kvm->irq_srcu);
 
index 484079efea5b89d7d8533804255a0ababe6ad0af..314c7774652e761bd299716fab1e1cffe9da8050 100644 (file)
@@ -206,16 +206,6 @@ void kvm_reload_remote_mmus(struct kvm *kvm)
        kvm_make_all_cpus_request(kvm, KVM_REQ_MMU_RELOAD);
 }
 
-void kvm_make_mclock_inprogress_request(struct kvm *kvm)
-{
-       kvm_make_all_cpus_request(kvm, KVM_REQ_MCLOCK_INPROGRESS);
-}
-
-void kvm_make_scan_ioapic_request(struct kvm *kvm)
-{
-       kvm_make_all_cpus_request(kvm, KVM_REQ_SCAN_IOAPIC);
-}
-
 int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
 {
        struct page *page;
@@ -1164,15 +1154,15 @@ struct kvm_memory_slot *kvm_vcpu_gfn_to_memslot(struct kvm_vcpu *vcpu, gfn_t gfn
        return __gfn_to_memslot(kvm_vcpu_memslots(vcpu), gfn);
 }
 
-int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn)
+bool kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn)
 {
        struct kvm_memory_slot *memslot = gfn_to_memslot(kvm, gfn);
 
        if (!memslot || memslot->id >= KVM_USER_MEM_SLOTS ||
              memslot->flags & KVM_MEMSLOT_INVALID)
-               return 0;
+               return false;
 
-       return 1;
+       return true;
 }
 EXPORT_SYMBOL_GPL(kvm_is_visible_gfn);
 
@@ -2257,7 +2247,7 @@ static int create_vcpu_fd(struct kvm_vcpu *vcpu)
 static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
 {
        int r;
-       struct kvm_vcpu *vcpu, *v;
+       struct kvm_vcpu *vcpu;
 
        if (id >= KVM_MAX_VCPUS)
                return -EINVAL;
@@ -2281,12 +2271,10 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
                r = -EINVAL;
                goto unlock_vcpu_destroy;
        }
-
-       kvm_for_each_vcpu(r, v, kvm)
-               if (v->vcpu_id == id) {
-                       r = -EEXIST;
-                       goto unlock_vcpu_destroy;
-               }
+       if (kvm_get_vcpu_by_id(kvm, id)) {
+               r = -EEXIST;
+               goto unlock_vcpu_destroy;
+       }
 
        BUG_ON(kvm->vcpus[atomic_read(&kvm->online_vcpus)]);
 
@@ -3449,10 +3437,9 @@ static int kvm_init_debug(void)
                goto out;
 
        for (p = debugfs_entries; p->name; ++p) {
-               p->dentry = debugfs_create_file(p->name, 0444, kvm_debugfs_dir,
-                                               (void *)(long)p->offset,
-                                               stat_fops[p->kind]);
-               if (p->dentry == NULL)
+               if (!debugfs_create_file(p->name, 0444, kvm_debugfs_dir,
+                                        (void *)(long)p->offset,
+                                        stat_fops[p->kind]))
                        goto out_dir;
        }
 
@@ -3464,15 +3451,6 @@ out:
        return r;
 }
 
-static void kvm_exit_debug(void)
-{
-       struct kvm_stats_debugfs_item *p;
-
-       for (p = debugfs_entries; p->name; ++p)
-               debugfs_remove(p->dentry);
-       debugfs_remove(kvm_debugfs_dir);
-}
-
 static int kvm_suspend(void)
 {
        if (kvm_usage_count)
@@ -3630,7 +3608,7 @@ EXPORT_SYMBOL_GPL(kvm_init);
 
 void kvm_exit(void)
 {
-       kvm_exit_debug();
+       debugfs_remove_recursive(kvm_debugfs_dir);
        misc_deregister(&kvm_dev);
        kmem_cache_destroy(kvm_vcpu_cache);
        kvm_async_pf_deinit();